Check-in [9f0c27f8d1]

Login

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

Overview
Comment:Converted TIPs to Markdown
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 9f0c27f8d14faef5e50a194ccd93f0f562007dd158ef901bad2deb0f1fd63be0
User & Date: mjanssen 2017-09-06 14:15:49
Context
2017-09-06
14:15
Added script to generate index check-in: e62d322a99 user: mjanssen tags: trunk
14:15
Converted TIPs to Markdown check-in: 9f0c27f8d1 user: mjanssen tags: trunk
14:15
Clean-up CVS import check-in: dce4aef4b9 user: mjanssen tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Name change from tip/0.tip to tip/0.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288

TIP:            0
Title:          Tcl Core Team Basic Rules
Version:        $Revision: 2.6 $
Author:         John Ousterhout <[email protected]>
State:          Final
Type:           Process
Vote:           Done
Created:        11-Dec-2000
Post-History:


~ Abstract

This TIP describes the mission, structure, and operating procedures
of the Tcl Core Team (TCT).  When in doubt about how the TCT works,
consult this document as the final authority.

~ Introduction

The Tcl Core Team is a self-organizing group of Tcl experts who are
responsible for the evolution and management of the Tcl core.  The
Tcl Core Team decides what goes into releases; it implements, tests,
and documents new features and bug fixes; it manages the release
process; and it also manages the Tcl Developer Exchange Web site.

~ Scope: the Tcl core

The phrase "Tcl core" refers to the Tcl interpreter and the Tk
toolkit (the packages previously released by Sun, Scriptics, and
Ajuba).  We also include the Tcl Developer Exchange Web site and
the Tcl bug database in the Tcl core.  The Tcl Core Team may also
choose to take on additional responsibilities such as the creation
of more comprehensive "batteries included" releases.  We expect
other Tcl development teams to form independently from the Tcl
Core Team to manage additional projects, such as popular extensions.
The Tcl Core Team may eventually spin off some of its activities
into separate teams.

~ Team membership

The Tcl Core Team is a small group of people who are making major
contributions to the development of the Tcl core and who are highly
respected and trusted by the Tcl community.  Team members are expected
to invest significant amounts of their time to improve the Tcl core.

The original group of Team members was elected by the Tcl community,
but the TCT now handles its own membership according to rules described
here.  To become a member of the Team you must be nominated by an
existing member and voted on by the existing Team; you must receive
2/3 of the votes cast.  If you would like to join the Tcl Core Team,
you should first demonstrate your development skills and leadership by
participating in development projects under the auspices of an
existing team member.

Inactive or disruptive members of the team can be removed by a vote
of other Team members: a 2/3 majority of those voting is required to
remove a Team member.

~ Communication

The primary mechanism for communicating with the Tcl Core Team is the
mail alias [email protected].  This is a public mailing
list;  anyone interested in following the discussions of the TCT is
welcome to join the mailing list.  Email sent to this alias is
archived, so you can review previous discussions at SourceForge.

~ Basic organizational structure

The team structure is simple and flat.  All members have equal
standing: there is no Chairman.  The Tcl Core Team makes its own
rules and chooses its own members as described in this document.
Anyone on the Tcl Core Team can propose a change in the rules;
after discussion, the change is voted on by the Team and must
receive 2/3 of the votes cast.  The person proposing a rules change
is responsible for making sure that the change is properly
implemented after it has been approved (e.g. by modifying this
TIP, creating additional tools, etc.).

~ 2/3 vote

Wherever a 2/3 vote is called for in this document, it means that a
proposal must receive ''at least two-thirds of the votes cast'', not
votes from at least two-thirds of all TCT members.

~ Projects and maintainers

Tcl improvements are organized around two key ideas: ''projects''
and ''maintainers''.  Most of the activities of the Tcl Core
Team consist of projects.  A project can consist of a bug
fix, a new feature in the Tcl core, a new facility in the Tcl
Developer Exchange, or anything else except a change to this
TIP.  We divide projects into two general categories: bug
fixes and feature changes.  In general, if a project requires
manual entries to be updated then it is a feature change;  when
in doubt, a project is a feature change .  Bug fixes use a
more streamlined process for implementation, whereas feature
changes require discussion and approval in advance.

A maintainer is someone who has taken primary responsibility for
a portion of the Tcl sources.  Many maintainers will be members of
the Tcl Core Team, but the Team may also select maintainers from
outside the Tcl Core Team.  We hope to find enough maintainers to
cover all of the Tcl sources, but we will appoint a ''default
maintainer'' to handle the parts of Tcl for which no other maintainer
has volunteered.  We'll also try to have backup maintainers who
can step in when the primary maintainers are on vacation or
otherwise unavailable.

A maintainer accepts several responsibilities, including the
following:

     * Monitoring the bug database for bugs in his/her area.

     * Arranging for bugs to be fixed, either by doing it
       himself/herself or finding someone else to do it.

     * Coordinating and reviewing all modifications to his/her area.

     * Providing assistance to other people working in his/her area.

~ Project life-cycle: approval, implementation, integration; TYANNOTT

The project for a feature change goes through three stages: approval,
implementation, and integration.

A project starts when a member of the Tcl Core Team proposes it to
the Team.  Proposals are submitted by emailing TIPs (Tcl Improvement
Proposals) to the Tcl Core Team.  The format of TIPs is described
in a separate TIP.  Whoever proposes a project is responsible for
making sure it is properly implemented.  A proposal without a
committed implementor cannot be approved.

Project approval is done through a process called ''TYANNOTT'':
Two Yesses And No No's Or Two Thirds.  In order for a project to be
approved it must have support from at least one other member of the
Tcl Core Team besides the proposer.  Once a project has been proposed
and discussed, if there are no objections and there is a vote of
confidence from a second team member ("Two Yesses And No No's"),
then the project is approved.  If objections remain after the
discussion, then the proposer must summarize the objections and
call for a vote of the TCT; a 2/3 vote is required for approval.
The idea here is that most projects will be no-brainers and we want
a simple decision process that doesn't get in the way of progress.
On the other hand, the Tcl Core Team can only work effectively if
it is highly collegial; if the Team can't reach pretty clear
agreement on a project (i.e more than 1/3 of the TCT objects to it)
then the project needs to be rethought.

The second phase of a project is implementation.  The proposer is
responsible for the implementation, either doing it himself/herself
or arranging for someone else to do it.  The implementation is done
in a private work area and may not be integrated with the official
sources until the third phase, below.

The third phase of a project is integrating the results back into
the official Tcl repository.  This is where maintainers come in.
First, before any change can be applied to the official Tcl sources,
the implementor must post it as a patch to the SourceForge patch
manager.  This rule applies regardless of the type of change (anything
from a 1-line bug fix to a major new feature) and regardless of who
is proposing the change.  We use the SourceForge patch manager to
record all changes and also to facilitate discussion about the
changes before they are applied.

When a patch arrives in the SourceForge patch manager, the
appropriate maintainer reviews it and works with the proposer
to revise it as necessary.  Other people can also review the
patch, since it is public.  If changes are needed, a revised
patch is logged in the patch manager (the final version of
the patch must always appear in the SourceForge patch manager).
Once the maintainer is satisfied with the patch, it can be applied
to the Tcl sources.  If the patch implementor has write access
to the sources that he or she can apply the patch once the
maintainer has approved it.  If the patch implementor doesn't
have write access to the sources than the maintainer applies
the patch.

Maintainers are responsible for watching the SourceForge patch
manager to make sure that incoming patches in their area are dealt
with quickly.

If the implementor of a patch is the maintainer, then he/she can
apply the patch to the Tcl sources immediately after logging it in
the SourceForge patch manager, without waiting for additional
approval.  However, if someone objects to the patch then the
maintainer must be prepared to revise it after the fact.

~ Fast path for bug fixes

For a bug fix, no initial proposal or approval is required.  The
only approval needed is for the maintainer to review the patch
before it is applied to the sources.  For example, we invite everyone
in the Tcl community to fix bugs and submit patches to the SourceForge
patch manager.

~ Implementors outside the Tcl Core Team

We encourage people outside the Tcl Core Team to get involved with
Tcl development.  For example, anyone can submit patches for bug
fixes.  It's also fine for someone outside the Tcl core team to
propose a feature change and then implement it, but there must be
a sponsor on the Tcl Core Team who will take personal responsibility
for it.  Typically the sponsor will be the maintainer for the area
of the change.  It is the sponsor's responsibility to provide whatever
level of supervision is appropriate to ensure that the project is
executed well.  If the implementor for a project is not a TCT member
then they cannot vote for approval: TYANNOTT requires the sponsor
plus one other Team member.

~ Raising concerns

If you have concerns about a project, the best time to raise them is
during the initial discussion.  Once a project has been approved, the
best approach is to raise the issue directly with the implementor;
most issues should get resolved quickly this way.  If you can't find
the implementor or can't reach agreement, and if the implementor is
not a member of the Tcl Core Team, the next person to talk to is the
Tcl Core Team member in charge of the project.  If you still can't get
satisfaction, then raise the issue with the entire Tcl Core Team by
leading a discussion.  Once all the issues are out, you can either
withdraw your objection or summarize the issues (on both sides!) and
call for a vote.  If you aren't a member of the Tcl Core Team
you will need to convince a Team member to manage the discussion
and vote.

Even if a project has received initial approval, a Team member can
object to the project later (e.g. if they believe it hasn't been
implemented properly).  If the objection isn't resolved there will
be an additional vote of the Team, and the project cannot be applied
to the official sources unless it receives a 2/3 majority of
the votes cast.  At the same time, Team members are expected to
raise their objections as early as possible; it would be somewhat
anti-social to raise a basic design objection late in the
implementation of a project when it could have been raised during
the initial approval.

~ Disagreements over patches

Normally, patches are not reviewed by the entire TCT; once the
relevant maintainer has reviewed and approved them then they can
be integrated.  However, everyone is invited to review as many
patches as they wish.  If someone on the TCT objects to a patch
and can't resolve the objection with the implementor and/or
maintainer, then it gets discussed by the entire Tcl Core Team with
the usual rules: if anyone on the Tcl Core Team has an objection
that isn't resolved by the discussion, then a 2/3 vote is required
to retain the patch.  Thus if an implementor reaches a disagreement
with a maintainer he/she can appeal to the entire Tcl Core Team.
Or, if someone on the Tcl Core Team objects to a patch applied by
a maintainer, they too can start a discussion in the whole team.
The goal of the maintainer mechanism is to simplify and speed up
improvements in the common case where everyone is in agreement,
while still allowing the entire Tcl Core Team to offer input and
resolve disagreements.

~ Changes that span areas

If a change involves several different areas of the Tcl sources,
with different maintainers, then one of the maintainers acts as
coordinator (presumably the one whose area has the most changes).
It is their responsibility to consult with other maintainers whose
areas are affected, so that all relevant maintainers are happy
before the patch is applied to the sources.

~ Write access to the Tcl sources and the Web site

Everyone in the Tcl Core Team has write access to all the sources
and the Web site, but they may only make changes consistent with
approved projects.  The Tcl Core Team can also give access to other
people who are working on projects.  For example, as part of a project
proposal a Tcl Core Team member can propose that the work will be
done by someone outside the team, and that that person should have
write access for putting back changes.  Giving out write access is
part of a project decision, with the associated rules for approval.
However, if someone outside the Tcl Core Team has write access, it
must be under the auspices of a Tcl Core Team member; the Tcl
Core Team member is personally responsible for making sure the
project is completed satisfactorily and/or cleaning up any messes.

~ Deadlock resolution

If something should go wrong with the TCT organization and the
Tcl Core Team deadlocks to a point where it can't make meaningful
progress, then John Ousterhout will step in as benevolent dictator
and make enough unilateral decisions to break the deadlock.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
>

|


|


|







|


|
|








|



















|







|








|
|

|


|


|

|
|














|
|
















|





|
|




|




|







|












|
|








|
|

















|







|













|










|





|
|








|


















|



|




|














|






|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288

# TIP 0: Tcl Core Team Basic Rules

	Author:         John Ousterhout <[email protected]>
	State:          Final
	Type:           Process
	Vote:           Done
	Created:        11-Dec-2000
	Post-History:
-----

# Abstract

This TIP describes the mission, structure, and operating procedures
of the Tcl Core Team \(TCT\).  When in doubt about how the TCT works,
consult this document as the final authority.

# Introduction

The Tcl Core Team is a self-organizing group of Tcl experts who are
responsible for the evolution and management of the Tcl core.  The
Tcl Core Team decides what goes into releases; it implements, tests,
and documents new features and bug fixes; it manages the release
process; and it also manages the Tcl Developer Exchange Web site.

# Scope: the Tcl core

The phrase "Tcl core" refers to the Tcl interpreter and the Tk
toolkit \(the packages previously released by Sun, Scriptics, and
Ajuba\).  We also include the Tcl Developer Exchange Web site and
the Tcl bug database in the Tcl core.  The Tcl Core Team may also
choose to take on additional responsibilities such as the creation
of more comprehensive "batteries included" releases.  We expect
other Tcl development teams to form independently from the Tcl
Core Team to manage additional projects, such as popular extensions.
The Tcl Core Team may eventually spin off some of its activities
into separate teams.

# Team membership

The Tcl Core Team is a small group of people who are making major
contributions to the development of the Tcl core and who are highly
respected and trusted by the Tcl community.  Team members are expected
to invest significant amounts of their time to improve the Tcl core.

The original group of Team members was elected by the Tcl community,
but the TCT now handles its own membership according to rules described
here.  To become a member of the Team you must be nominated by an
existing member and voted on by the existing Team; you must receive
2/3 of the votes cast.  If you would like to join the Tcl Core Team,
you should first demonstrate your development skills and leadership by
participating in development projects under the auspices of an
existing team member.

Inactive or disruptive members of the team can be removed by a vote
of other Team members: a 2/3 majority of those voting is required to
remove a Team member.

# Communication

The primary mechanism for communicating with the Tcl Core Team is the
mail alias [email protected].  This is a public mailing
list;  anyone interested in following the discussions of the TCT is
welcome to join the mailing list.  Email sent to this alias is
archived, so you can review previous discussions at SourceForge.

# Basic organizational structure

The team structure is simple and flat.  All members have equal
standing: there is no Chairman.  The Tcl Core Team makes its own
rules and chooses its own members as described in this document.
Anyone on the Tcl Core Team can propose a change in the rules;
after discussion, the change is voted on by the Team and must
receive 2/3 of the votes cast.  The person proposing a rules change
is responsible for making sure that the change is properly
implemented after it has been approved \(e.g. by modifying this
TIP, creating additional tools, etc.\).

# 2/3 vote

Wherever a 2/3 vote is called for in this document, it means that a
proposal must receive _at least two-thirds of the votes cast_, not
votes from at least two-thirds of all TCT members.

# Projects and maintainers

Tcl improvements are organized around two key ideas: _projects_
and _maintainers_.  Most of the activities of the Tcl Core
Team consist of projects.  A project can consist of a bug
fix, a new feature in the Tcl core, a new facility in the Tcl
Developer Exchange, or anything else except a change to this
TIP.  We divide projects into two general categories: bug
fixes and feature changes.  In general, if a project requires
manual entries to be updated then it is a feature change;  when
in doubt, a project is a feature change .  Bug fixes use a
more streamlined process for implementation, whereas feature
changes require discussion and approval in advance.

A maintainer is someone who has taken primary responsibility for
a portion of the Tcl sources.  Many maintainers will be members of
the Tcl Core Team, but the Team may also select maintainers from
outside the Tcl Core Team.  We hope to find enough maintainers to
cover all of the Tcl sources, but we will appoint a _default
maintainer_ to handle the parts of Tcl for which no other maintainer
has volunteered.  We'll also try to have backup maintainers who
can step in when the primary maintainers are on vacation or
otherwise unavailable.

A maintainer accepts several responsibilities, including the
following:

     * Monitoring the bug database for bugs in his/her area.

     * Arranging for bugs to be fixed, either by doing it
       himself/herself or finding someone else to do it.

     * Coordinating and reviewing all modifications to his/her area.

     * Providing assistance to other people working in his/her area.

# Project life-cycle: approval, implementation, integration; TYANNOTT

The project for a feature change goes through three stages: approval,
implementation, and integration.

A project starts when a member of the Tcl Core Team proposes it to
the Team.  Proposals are submitted by emailing TIPs \(Tcl Improvement
Proposals\) to the Tcl Core Team.  The format of TIPs is described
in a separate TIP.  Whoever proposes a project is responsible for
making sure it is properly implemented.  A proposal without a
committed implementor cannot be approved.

Project approval is done through a process called _TYANNOTT_:
Two Yesses And No No's Or Two Thirds.  In order for a project to be
approved it must have support from at least one other member of the
Tcl Core Team besides the proposer.  Once a project has been proposed
and discussed, if there are no objections and there is a vote of
confidence from a second team member \("Two Yesses And No No's"\),
then the project is approved.  If objections remain after the
discussion, then the proposer must summarize the objections and
call for a vote of the TCT; a 2/3 vote is required for approval.
The idea here is that most projects will be no-brainers and we want
a simple decision process that doesn't get in the way of progress.
On the other hand, the Tcl Core Team can only work effectively if
it is highly collegial; if the Team can't reach pretty clear
agreement on a project \(i.e more than 1/3 of the TCT objects to it\)
then the project needs to be rethought.

The second phase of a project is implementation.  The proposer is
responsible for the implementation, either doing it himself/herself
or arranging for someone else to do it.  The implementation is done
in a private work area and may not be integrated with the official
sources until the third phase, below.

The third phase of a project is integrating the results back into
the official Tcl repository.  This is where maintainers come in.
First, before any change can be applied to the official Tcl sources,
the implementor must post it as a patch to the SourceForge patch
manager.  This rule applies regardless of the type of change \(anything
from a 1-line bug fix to a major new feature\) and regardless of who
is proposing the change.  We use the SourceForge patch manager to
record all changes and also to facilitate discussion about the
changes before they are applied.

When a patch arrives in the SourceForge patch manager, the
appropriate maintainer reviews it and works with the proposer
to revise it as necessary.  Other people can also review the
patch, since it is public.  If changes are needed, a revised
patch is logged in the patch manager \(the final version of
the patch must always appear in the SourceForge patch manager\).
Once the maintainer is satisfied with the patch, it can be applied
to the Tcl sources.  If the patch implementor has write access
to the sources that he or she can apply the patch once the
maintainer has approved it.  If the patch implementor doesn't
have write access to the sources than the maintainer applies
the patch.

Maintainers are responsible for watching the SourceForge patch
manager to make sure that incoming patches in their area are dealt
with quickly.

If the implementor of a patch is the maintainer, then he/she can
apply the patch to the Tcl sources immediately after logging it in
the SourceForge patch manager, without waiting for additional
approval.  However, if someone objects to the patch then the
maintainer must be prepared to revise it after the fact.

# Fast path for bug fixes

For a bug fix, no initial proposal or approval is required.  The
only approval needed is for the maintainer to review the patch
before it is applied to the sources.  For example, we invite everyone
in the Tcl community to fix bugs and submit patches to the SourceForge
patch manager.

# Implementors outside the Tcl Core Team

We encourage people outside the Tcl Core Team to get involved with
Tcl development.  For example, anyone can submit patches for bug
fixes.  It's also fine for someone outside the Tcl core team to
propose a feature change and then implement it, but there must be
a sponsor on the Tcl Core Team who will take personal responsibility
for it.  Typically the sponsor will be the maintainer for the area
of the change.  It is the sponsor's responsibility to provide whatever
level of supervision is appropriate to ensure that the project is
executed well.  If the implementor for a project is not a TCT member
then they cannot vote for approval: TYANNOTT requires the sponsor
plus one other Team member.

# Raising concerns

If you have concerns about a project, the best time to raise them is
during the initial discussion.  Once a project has been approved, the
best approach is to raise the issue directly with the implementor;
most issues should get resolved quickly this way.  If you can't find
the implementor or can't reach agreement, and if the implementor is
not a member of the Tcl Core Team, the next person to talk to is the
Tcl Core Team member in charge of the project.  If you still can't get
satisfaction, then raise the issue with the entire Tcl Core Team by
leading a discussion.  Once all the issues are out, you can either
withdraw your objection or summarize the issues \(on both sides!\) and
call for a vote.  If you aren't a member of the Tcl Core Team
you will need to convince a Team member to manage the discussion
and vote.

Even if a project has received initial approval, a Team member can
object to the project later \(e.g. if they believe it hasn't been
implemented properly\).  If the objection isn't resolved there will
be an additional vote of the Team, and the project cannot be applied
to the official sources unless it receives a 2/3 majority of
the votes cast.  At the same time, Team members are expected to
raise their objections as early as possible; it would be somewhat
anti-social to raise a basic design objection late in the
implementation of a project when it could have been raised during
the initial approval.

# Disagreements over patches

Normally, patches are not reviewed by the entire TCT; once the
relevant maintainer has reviewed and approved them then they can
be integrated.  However, everyone is invited to review as many
patches as they wish.  If someone on the TCT objects to a patch
and can't resolve the objection with the implementor and/or
maintainer, then it gets discussed by the entire Tcl Core Team with
the usual rules: if anyone on the Tcl Core Team has an objection
that isn't resolved by the discussion, then a 2/3 vote is required
to retain the patch.  Thus if an implementor reaches a disagreement
with a maintainer he/she can appeal to the entire Tcl Core Team.
Or, if someone on the Tcl Core Team objects to a patch applied by
a maintainer, they too can start a discussion in the whole team.
The goal of the maintainer mechanism is to simplify and speed up
improvements in the common case where everyone is in agreement,
while still allowing the entire Tcl Core Team to offer input and
resolve disagreements.

# Changes that span areas

If a change involves several different areas of the Tcl sources,
with different maintainers, then one of the maintainers acts as
coordinator \(presumably the one whose area has the most changes\).
It is their responsibility to consult with other maintainers whose
areas are affected, so that all relevant maintainers are happy
before the patch is applied to the sources.

# Write access to the Tcl sources and the Web site

Everyone in the Tcl Core Team has write access to all the sources
and the Web site, but they may only make changes consistent with
approved projects.  The Tcl Core Team can also give access to other
people who are working on projects.  For example, as part of a project
proposal a Tcl Core Team member can propose that the work will be
done by someone outside the team, and that that person should have
write access for putting back changes.  Giving out write access is
part of a project decision, with the associated rules for approval.
However, if someone outside the Tcl Core Team has write access, it
must be under the auspices of a Tcl Core Team member; the Tcl
Core Team member is personally responsible for making sure the
project is completed satisfactorily and/or cleaning up any messes.

# Deadlock resolution

If something should go wrong with the TCT organization and the
Tcl Core Team deadlocks to a point where it can't make meaningful
progress, then John Ousterhout will step in as benevolent dictator
and make enough unilateral decisions to break the deadlock.

# Copyright

This document has been placed in the public domain.

Name change from tip/1.tip to tip/1.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

TIP:            1
Title:          TIP Index
Version:        $Revision: 1.6 $
Author:         TIP Editor <[email protected]>
State:          Active
Type:           Informational
Vote:           No voting
Created:        14-Sep-2000
Post-History:


~ Abstract

This TIP contains the index of all TIPs published over the lifetime of
the TCT. It will be continually and automatically updated.

~ Index

#index:

White backgrounds indicate that the TIP is still a draft, yellow
backgrounds highlight TIPs being voted on, and where a TIP has been
rejected, withdrawn or obsoleted its index entry has a dark grey
background.  Blue backgrounds indicate a TIP has been accepted,
but still needs an implementation approved by maintainers.  Green
backgrounds indicate that the TIP is deferred, waiting for someone
to work on it.

~ Explanations and How To Submit New TIPs

See [2] for a description of the editorial process a TIP has to go
through and [3] for a description of their structure and the commands
used to write them. You submit a TIP to this archive by emailing it
(preferably in source form) to the TIP editor <[email protected]>
who will check it for following of the guidelines, style and general
relevance to Tcl/Tk before checking it into the CVS archive and notifying
the author, the rest of the Tcl Core Team, and the relevant newsgroups.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
>

|




|

|









|

|
|

|




|


>

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

# TIP 1: TIP Index

	Author:         TIP Editor <[email protected]>
	State:          Active
	Type:           Informational
	Vote:           No voting
	Created:        14-Sep-2000
	Post-History:
-----

# Abstract

This TIP contains the index of all TIPs published over the lifetime of
the TCT. It will be continually and automatically updated.

# Index

\#index:

White backgrounds indicate that the TIP is still a draft, yellow
backgrounds highlight TIPs being voted on, and where a TIP has been
rejected, withdrawn or obsoleted its index entry has a dark grey
background.  Blue backgrounds indicate a TIP has been accepted,
but still needs an implementation approved by maintainers.  Green
backgrounds indicate that the TIP is deferred, waiting for someone
to work on it.

# Explanations and How To Submit New TIPs

See [[2]](2.md) for a description of the editorial process a TIP has to go
through and [[3]](3.md) for a description of their structure and the commands
used to write them. You submit a TIP to this archive by emailing it
\(preferably in source form\) to the TIP editor <[email protected]>
who will check it for following of the guidelines, style and general
relevance to Tcl/Tk before checking it into the CVS archive and notifying
the author, the rest of the Tcl Core Team, and the relevant newsgroups.

# Copyright

This document has been placed in the public domain.

Name change from tip/10.tip to tip/10.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

TIP:            10
Title:          Tcl I/O Enhancement: Thread-Aware Channels
Version:        $Revision: 1.6 $
Author:         Andreas Kupries <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        08-Nov-2000
Post-History:   
Tcl-Version:    8.4


~ Abstract

This TIP describes how to change the generic I/O layer in the Tcl core
to make channels aware of the thread they are managed by.

~ Rationale

To explain the motives behind this TIP first a short look at the
history of channels and threading.

In ancient times the Tcl core was not thread safe and did not employ
threads.  All channels belonged to a single interpreter. Later on
interpreter hierarchies were introduced and the ability to move or
share a channel between the interpreters in a hierarchy. When the Tcl
core was made thread safe a short time after the ability to move
channels between threads was added (Helper APIs in the core, main
functionality in the Thread extension).  The goal behind these
modifications was to enable the creation of stream-like communication
paths between threads to complement the message based facilities
(thread send). The modifications were only a partial success because
an in-depth analysis of the relevant data structures showed that the
sharing of a channel between threads is not possible with the current
design, only moving. This was implemented to allow at least the
dispatcher- / worker-thread pattern for structuring a threaded
application.

In further pursuit of the original goal the currently chosen approach
is to define a channeltype where two channels are connected internally
through in-memory fifo buffers where access to these shared structures
is protected by mutexes.

During the implementation of fileevents for this channeltype it was
discovered that an efficient implementation of this part is ''not''
possible because of the inability to post file events to the
eventqueue of the thread the other channel of the pair resides in. An
API to post such events is available (''Tcl_ThreadQueueEvent''), but
not the information which thread actually manages the other
channel. Because of this the current implementation of the channeltype
uses polling based upon timer events posted by each side/thread to
itself to manage file events in a rather inefficient way.

~ Reference implementation

This TIP now proposes to change the internals of the generic I/O
layers in the core so that

   1. Channels know the thread they are managed by, and

   1. are able to deliver this information to an extension querying
      the core.

This then allows the two sides of the channeltype mentioned above to
post events to each other, facilitating an efficient implementation of
fileevents.

The changes necessary to accomplish this are:

   1. Extend the structure ''ChannelState'' in tclIO.h with a new
      field of type ''Tcl_ThreadId'' to hold the id of the thread
      currently managing all channels with this state. Note: This
      structure is shared by all channels in a stack of
      transformations.

   1. Modify the procedure ''Tcl_CreateChannel'' to store the Id of
      the current thread in the ''ChannelState'' of the new channel.
      This information can be obtained with ''Tcl_GetCurrentThread''.
      It is ''not'' necessary to modify ''Tcl_StackChannel'' as the
      thread information is already part of the state when it is
      called, and won't be changed by the call.

   1. If some sort of NIL/NULL value meaning "No thread" is available
      for ''Tcl_ThreadId'', then we should modify ''Tcl_CutChannel''
      to insert this value into the state of the channel it is called
      with, as this channel will not be managed by any thread
      afterward (the procedure removes the channel from the list of
      all channels managed by the current thread).

   1. Modify ''Tcl_SpliceChannel'' in the same manner as
      ''Tcl_CreateChannel'' as the channel will be managed by the
      current thread afterward (The procedure adds the channel to the
      list of all channels managed by the current thread).

   1. Declare a new API function to retrieve the Id of the managing
      thread from a channel. Add this declaration to generic/tcl.decls
      and implement the function in the file generic/tclIO.c.  I
      propose ''Tcl_GetChannelThread'' as the name of this new API
      function.

A patch implementing all of the changes described above and
additionally extending the documentation and the test-suite
is available here:
http://www.cs.man.ac.uk/fellowsd-bin/TIP/10.patch

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|




|









|
|


|












|


|





|















|
|




|
|
|
|




|


|
|

|
|
|
|




|





|

|


>

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

# TIP 10: Tcl I/O Enhancement: Thread-Aware Channels

	Author:         Andreas Kupries <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        08-Nov-2000
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

This TIP describes how to change the generic I/O layer in the Tcl core
to make channels aware of the thread they are managed by.

# Rationale

To explain the motives behind this TIP first a short look at the
history of channels and threading.

In ancient times the Tcl core was not thread safe and did not employ
threads.  All channels belonged to a single interpreter. Later on
interpreter hierarchies were introduced and the ability to move or
share a channel between the interpreters in a hierarchy. When the Tcl
core was made thread safe a short time after the ability to move
channels between threads was added \(Helper APIs in the core, main
functionality in the Thread extension\).  The goal behind these
modifications was to enable the creation of stream-like communication
paths between threads to complement the message based facilities
\(thread send\). The modifications were only a partial success because
an in-depth analysis of the relevant data structures showed that the
sharing of a channel between threads is not possible with the current
design, only moving. This was implemented to allow at least the
dispatcher- / worker-thread pattern for structuring a threaded
application.

In further pursuit of the original goal the currently chosen approach
is to define a channeltype where two channels are connected internally
through in-memory fifo buffers where access to these shared structures
is protected by mutexes.

During the implementation of fileevents for this channeltype it was
discovered that an efficient implementation of this part is _not_
possible because of the inability to post file events to the
eventqueue of the thread the other channel of the pair resides in. An
API to post such events is available \(_Tcl\_ThreadQueueEvent_\), but
not the information which thread actually manages the other
channel. Because of this the current implementation of the channeltype
uses polling based upon timer events posted by each side/thread to
itself to manage file events in a rather inefficient way.

# Reference implementation

This TIP now proposes to change the internals of the generic I/O
layers in the core so that

   1. Channels know the thread they are managed by, and

   1. are able to deliver this information to an extension querying
      the core.

This then allows the two sides of the channeltype mentioned above to
post events to each other, facilitating an efficient implementation of
fileevents.

The changes necessary to accomplish this are:

   1. Extend the structure _ChannelState_ in tclIO.h with a new
      field of type _Tcl\_ThreadId_ to hold the id of the thread
      currently managing all channels with this state. Note: This
      structure is shared by all channels in a stack of
      transformations.

   1. Modify the procedure _Tcl\_CreateChannel_ to store the Id of
      the current thread in the _ChannelState_ of the new channel.
      This information can be obtained with _Tcl\_GetCurrentThread_.
      It is _not_ necessary to modify _Tcl\_StackChannel_ as the
      thread information is already part of the state when it is
      called, and won't be changed by the call.

   1. If some sort of NIL/NULL value meaning "No thread" is available
      for _Tcl\_ThreadId_, then we should modify _Tcl\_CutChannel_
      to insert this value into the state of the channel it is called
      with, as this channel will not be managed by any thread
      afterward \(the procedure removes the channel from the list of
      all channels managed by the current thread\).

   1. Modify _Tcl\_SpliceChannel_ in the same manner as
      _Tcl\_CreateChannel_ as the channel will be managed by the
      current thread afterward \(The procedure adds the channel to the
      list of all channels managed by the current thread\).

   1. Declare a new API function to retrieve the Id of the managing
      thread from a channel. Add this declaration to generic/tcl.decls
      and implement the function in the file generic/tclIO.c.  I
      propose _Tcl\_GetChannelThread_ as the name of this new API
      function.

A patch implementing all of the changes described above and
additionally extending the documentation and the test-suite
is available here:
<http://www.cs.man.ac.uk/fellowsd-bin/TIP/10.patch>

# Copyright

This document has been placed in the public domain.

Name change from tip/100.tip to tip/100.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
TIP:            100
Title:          Add Support for Unloading Dynamic Libraries Loaded with [load]
Version:        $Revision: 1.10 $
Author:         George Petasis <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        11-Jun-2002
Post-History:   
Discussions-To: news:comp.lang.tcl
Keywords:       load,unload,dynamic library
Tcl-Version:    8.5


~ Abstract

Tcl already provides facilities for loading dynamic libraries, through
the ''load'' command.  However no facilities are currently offered in
order to ''unload'' dynamic libraries already loaded with the ''load''
command.  This TIP tries to add support for unloading libraries, by
introducing a new Tcl command (''unload'') and the guidelines that
dynamic libraries must follow, in order to be unloadable.  Note that
the ''unload'' command will operate only on libraries that are
designed to be unloadable by their developers.  This way backward
compatibility with older extensions is maintained, as unload will
never try to unload libraries unaware of this new functionality.

~ Rationale

Tcl is an ideal language for component-based applications.  Usually
these applications offer a framework in which components developed by
the users of the application can be embedded, in order to extend the
functionality of the framework.  Usually, these extensions are
implemented as C/C++ dynamic libraries that are loaded through the
''load'' Tcl command.

However the development of such components can be a time-consuming
process, as developers have to restart the framework application in
order to be able to reload the library into it and test its altered
functionality.  And this can be quite annoying (depending on the
application of course), as usually processing within the application
is required in order to bring it into a proper state before testing
the library.

The development cycle can be significantly shortened if Tcl provides a
mechanism for unloading a dynamic library.  A new version of the
library can be created, as its object file can now be written, and the
updated library can be re-loaded.

However, this is not the only application of unload.
Services running for long periods of time and want to unload
no longer needed functionality, replacing parts of an applications
(i.e. from an automatic update procedure) or functionality
temporarily needed (i.e. a web browser that loads a plugin
to display a file of a particular file type) are some
additional fields of application.

~ Introduction

Unload functionality has been left out of the Tcl core, mainly because
library unloading was poorly implemented in many operating systems.
But almost all operating systems have been improved in the meantime,
and as a result most modern operating systems now support library
unloading.

The main idea of this TIP is to enable dynamic library unloading at
the Tcl level, in the same sense ''load'' provides dynamic library
loading.  However, library unloading will be provided only when the
underlying operating system support this feature (as is also the case
for ''load'') and only when the library to be unloaded provides a set
of functions that can "undo" the changes the library has made to the
interpreter.  In all other cases, unloading a library will result in
an error.

This TIP proposes the insertion of a new Tcl command named ''unload''
and two functions ''pkg_Unload'' and ''pkg_SafeUnload'', modelled
after ''pkg_Init'' and ''pkg_SafeInit'', that libraries which can be
unloaded should implement.

~ Unloadable Libraries

A main concern is related to when a shared library can be "unloadable".
An unloadable library is a library characterised as such by its
developer. The developer of the library must export a function
from the library, similar to the library's initialisation
function. The unload command will never try to unload a library
that does not provide such a function. This makes old libraries
(before the introduction of the unload functionality) safe.

There is a category of libraries that
can never be unloaded (i.e. libraries that register new
tcl object types). However, the choice is upon the developer:
the developer knows if the library can be unloadable. The simpler
case, libraries that only register new commands are the most
probable libraries to be unloadable.
Libraries that export functions through a stub mechanism cannot be
unloaded, as the were meant for having dependencies with
other libraries that use the exported API. There is no way for
the provider library to know wether it is used or not.

~ Specification

Actually, all the facilities for unloading dynamic libraries already
exist in the Tcl core and simply they are not yet exposed at the Tcl
level.  As a result, the implementation of the unload command should
be fairly easy.

''load'' as it is currently implemented loads a dynamic library only
the first time this library is loaded.  It keeps an internal cache of
all loaded libraries and if an already loaded library is requested
again, only its initialisation function is called.  This cache should
be extended to keep some additional information:

   1.  Two reference counts, counting how many times a specific
       library has been loaded.  This reference count should be
       increased by each ''load'' and decreased for each ''unload''.
       When it reaches 0, the library can be unloaded.  Safe
       interpreters and normal interpreters should have different
       reference counts.  Both should be 0 in order for a library to
       be unloaded.

   2.  The addresses of the ''pkg_Unload'' and ''pkg_SafeUnload''
       functions, if these are implemented by the library.  If both of
       these functions are missing, the library will never be
       unloaded.  If only ''pkg_Unload'' is implemented, the library
       can be unloaded if it never has been loaded in a safe
       interpreter.  Finally, if ''pkg_SafeUnload'' is implemented,
       the library can be unloaded if it has never been loaded in a
       normal interpreter.

The ''unload'' command will always return an error, if the operating
system does not support library unloading.  In case the operating
system supports library unloading:

   1.  ''unload'' will examine the cache of ''load'' to locate the
       entry for the library to be unloaded.  It is an error to unload
       a library that has not been loaded with ''load''.

   2.  If the entry in the cache is found, ''unload'' checks whether
       the corresponding for the interpreter type unload function
       pointer is NULL or not.  If it is NULL, the library cannot be
       unloaded under this interpreter and again an error is returned.

   3.  If the unload function pointer is not NULL, it is executed.  If
       an error is returned by this function, ''unload'' also returns
       an error.

   4.  If the unload function finishes without errors, the reference
       count corresponding to the interpreter type is decreased.  If
       both reference counts reach 0, the library is unloaded.

~ Responsibilities of the Unload Functions

Its up to the developer of the library to decide if its library can be
unloaded or not.  A library can be unloaded if the function
''pkg_Unload'' is implemented and exported as a symbol from the
library, and the library will never be loaded in a safe interpreter.
A library that can be also loaded in safe interpreters is unloadable
if the function ''pkg_SafeUnload'' is also available.  These two
functions will accept two arguments, the interpreter under which the
library is unloaded and an integer, holding various flags.  The flags argument
can be either ''TCL_UNLOAD_DETACH_FROM_INTERPRETER'' or
''TCL_UNLOAD_DETACH_FROM_PROCESS''. In case the library will remain attached to
the process after the unload procedure returns (i.e. because the library is
used by other interpreters), TCL_UNLOAD_DETACH_FROM_INTERPRETER will be defined.
However, if the library is used only by the target interpreter and the library
will be detached from the application as soon as the unload procedure returns,
the flags argument will be set to TCL_UNLOAD_DETACH_FROM_PROCESS. 

The main responsibility of these functions is to remove from the
interpreter they are unloaded under any reference to a function
residing inside the library.  For example, such a function must:

   1.  Unregister any commands that have been registered by the
       ''Init()'' function to the ''interpreter'' given by the first
       argument.  In order to do this, the library should keep
       internally the tokens returned by each ''Tcl_Create*Command'',
       as command may have been renamed.

   2.  Unregister any other commands that may have been registered to
       the interpreter during the use of the library (usually used to
       represent special special data structures).

If the flag ''TCL_UNLOAD_DETACH_FROM_PROCESS'' is defined, the
developer must do additional task, that are not normally required when
the library gets unloaded from an interpreter:

   3.  Free any memory occupied by the internal structures of
       the library.

   4.  In general, try to remove any references Tcl may have
       to functions provided by the library.

If the developer cannot remove all reference to functions to the
library, its better to not provide at all these two functions, so as
unload to never attempt to unload the library.

~ Dependencies Among Libraries

It is possible that a library A has been loaded that exports some
symbols.  Then a library B is loaded, that has dependencies (i.e. uses
some exported symbols) on A.  What if A gets unloaded?

Actually, most modern operating systems seem to provide a solution to
this problem, as reference counts are hold internally by the operating
system for each library.  Newer Windows, Solaris and Linux seem to
provide similar solutions and in reality they don't unload the library
if such symbols remain, even if the unload system call has been made
for the library.  Both libraries A and B have to be unloaded in order
for A to be really removed from the address space.

~ Reference Implementation

A reference implementation can be found at:
http://sf.net/tracker/?func=detail&aid=823486&group_id=10894&atid=310894

~ Copyright

This document has been placed in the public domain.

~ Appendix: The unload man page.

     NAME
     unload - Unload machine code.
     SYNOPSIS
     unload ?switches? fileName
     unload ?switches? fileName packageName
     unload ?switches? fileName packageName interp
<
|
<
|
|
|
|
|
|
|
|
|
>

|


|
|

|

|




|





|
|




|
|











|
|
|


|








|

|
|




|
|
|


|







|


|
|








|






|







|





|


|

|



|



|

|

|





|






|



|


|


|
|
|
|


|






|

|



|
|

|













|


|
|









|


|

|



|








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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226

# TIP 100: Add Support for Unloading Dynamic Libraries Loaded with [load]

	Author:         George Petasis <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        11-Jun-2002
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Keywords:       load,unload,dynamic library
	Tcl-Version:    8.5
-----

# Abstract

Tcl already provides facilities for loading dynamic libraries, through
the _load_ command.  However no facilities are currently offered in
order to _unload_ dynamic libraries already loaded with the _load_
command.  This TIP tries to add support for unloading libraries, by
introducing a new Tcl command \(_unload_\) and the guidelines that
dynamic libraries must follow, in order to be unloadable.  Note that
the _unload_ command will operate only on libraries that are
designed to be unloadable by their developers.  This way backward
compatibility with older extensions is maintained, as unload will
never try to unload libraries unaware of this new functionality.

# Rationale

Tcl is an ideal language for component-based applications.  Usually
these applications offer a framework in which components developed by
the users of the application can be embedded, in order to extend the
functionality of the framework.  Usually, these extensions are
implemented as C/C\+\+ dynamic libraries that are loaded through the
_load_ Tcl command.

However the development of such components can be a time-consuming
process, as developers have to restart the framework application in
order to be able to reload the library into it and test its altered
functionality.  And this can be quite annoying \(depending on the
application of course\), as usually processing within the application
is required in order to bring it into a proper state before testing
the library.

The development cycle can be significantly shortened if Tcl provides a
mechanism for unloading a dynamic library.  A new version of the
library can be created, as its object file can now be written, and the
updated library can be re-loaded.

However, this is not the only application of unload.
Services running for long periods of time and want to unload
no longer needed functionality, replacing parts of an applications
\(i.e. from an automatic update procedure\) or functionality
temporarily needed \(i.e. a web browser that loads a plugin
to display a file of a particular file type\) are some
additional fields of application.

# Introduction

Unload functionality has been left out of the Tcl core, mainly because
library unloading was poorly implemented in many operating systems.
But almost all operating systems have been improved in the meantime,
and as a result most modern operating systems now support library
unloading.

The main idea of this TIP is to enable dynamic library unloading at
the Tcl level, in the same sense _load_ provides dynamic library
loading.  However, library unloading will be provided only when the
underlying operating system support this feature \(as is also the case
for _load_\) and only when the library to be unloaded provides a set
of functions that can "undo" the changes the library has made to the
interpreter.  In all other cases, unloading a library will result in
an error.

This TIP proposes the insertion of a new Tcl command named _unload_
and two functions _pkg\_Unload_ and _pkg\_SafeUnload_, modelled
after _pkg\_Init_ and _pkg\_SafeInit_, that libraries which can be
unloaded should implement.

# Unloadable Libraries

A main concern is related to when a shared library can be "unloadable".
An unloadable library is a library characterised as such by its
developer. The developer of the library must export a function
from the library, similar to the library's initialisation
function. The unload command will never try to unload a library
that does not provide such a function. This makes old libraries
\(before the introduction of the unload functionality\) safe.

There is a category of libraries that
can never be unloaded \(i.e. libraries that register new
tcl object types\). However, the choice is upon the developer:
the developer knows if the library can be unloadable. The simpler
case, libraries that only register new commands are the most
probable libraries to be unloadable.
Libraries that export functions through a stub mechanism cannot be
unloaded, as the were meant for having dependencies with
other libraries that use the exported API. There is no way for
the provider library to know wether it is used or not.

# Specification

Actually, all the facilities for unloading dynamic libraries already
exist in the Tcl core and simply they are not yet exposed at the Tcl
level.  As a result, the implementation of the unload command should
be fairly easy.

_load_ as it is currently implemented loads a dynamic library only
the first time this library is loaded.  It keeps an internal cache of
all loaded libraries and if an already loaded library is requested
again, only its initialisation function is called.  This cache should
be extended to keep some additional information:

   1.  Two reference counts, counting how many times a specific
       library has been loaded.  This reference count should be
       increased by each _load_ and decreased for each _unload_.
       When it reaches 0, the library can be unloaded.  Safe
       interpreters and normal interpreters should have different
       reference counts.  Both should be 0 in order for a library to
       be unloaded.

   2.  The addresses of the _pkg\_Unload_ and _pkg\_SafeUnload_
       functions, if these are implemented by the library.  If both of
       these functions are missing, the library will never be
       unloaded.  If only _pkg\_Unload_ is implemented, the library
       can be unloaded if it never has been loaded in a safe
       interpreter.  Finally, if _pkg\_SafeUnload_ is implemented,
       the library can be unloaded if it has never been loaded in a
       normal interpreter.

The _unload_ command will always return an error, if the operating
system does not support library unloading.  In case the operating
system supports library unloading:

   1.  _unload_ will examine the cache of _load_ to locate the
       entry for the library to be unloaded.  It is an error to unload
       a library that has not been loaded with _load_.

   2.  If the entry in the cache is found, _unload_ checks whether
       the corresponding for the interpreter type unload function
       pointer is NULL or not.  If it is NULL, the library cannot be
       unloaded under this interpreter and again an error is returned.

   3.  If the unload function pointer is not NULL, it is executed.  If
       an error is returned by this function, _unload_ also returns
       an error.

   4.  If the unload function finishes without errors, the reference
       count corresponding to the interpreter type is decreased.  If
       both reference counts reach 0, the library is unloaded.

# Responsibilities of the Unload Functions

Its up to the developer of the library to decide if its library can be
unloaded or not.  A library can be unloaded if the function
_pkg\_Unload_ is implemented and exported as a symbol from the
library, and the library will never be loaded in a safe interpreter.
A library that can be also loaded in safe interpreters is unloadable
if the function _pkg\_SafeUnload_ is also available.  These two
functions will accept two arguments, the interpreter under which the
library is unloaded and an integer, holding various flags.  The flags argument
can be either _TCL\_UNLOAD\_DETACH\_FROM\_INTERPRETER_ or
_TCL\_UNLOAD\_DETACH\_FROM\_PROCESS_. In case the library will remain attached to
the process after the unload procedure returns \(i.e. because the library is
used by other interpreters\), TCL\_UNLOAD\_DETACH\_FROM\_INTERPRETER will be defined.
However, if the library is used only by the target interpreter and the library
will be detached from the application as soon as the unload procedure returns,
the flags argument will be set to TCL\_UNLOAD\_DETACH\_FROM\_PROCESS. 

The main responsibility of these functions is to remove from the
interpreter they are unloaded under any reference to a function
residing inside the library.  For example, such a function must:

   1.  Unregister any commands that have been registered by the
       _Init\(\)_ function to the _interpreter_ given by the first
       argument.  In order to do this, the library should keep
       internally the tokens returned by each _Tcl\_Create\*Command_,
       as command may have been renamed.

   2.  Unregister any other commands that may have been registered to
       the interpreter during the use of the library \(usually used to
       represent special special data structures\).

If the flag _TCL\_UNLOAD\_DETACH\_FROM\_PROCESS_ is defined, the
developer must do additional task, that are not normally required when
the library gets unloaded from an interpreter:

   3.  Free any memory occupied by the internal structures of
       the library.

   4.  In general, try to remove any references Tcl may have
       to functions provided by the library.

If the developer cannot remove all reference to functions to the
library, its better to not provide at all these two functions, so as
unload to never attempt to unload the library.

# Dependencies Among Libraries

It is possible that a library A has been loaded that exports some
symbols.  Then a library B is loaded, that has dependencies \(i.e. uses
some exported symbols\) on A.  What if A gets unloaded?

Actually, most modern operating systems seem to provide a solution to
this problem, as reference counts are hold internally by the operating
system for each library.  Newer Windows, Solaris and Linux seem to
provide similar solutions and in reality they don't unload the library
if such symbols remain, even if the unload system call has been made
for the library.  Both libraries A and B have to be unloaded in order
for A to be really removed from the address space.

# Reference Implementation

A reference implementation can be found at:
<http://sf.net/tracker/?func=detail&aid=823486&group\_id=10894&atid=310894>

# Copyright

This document has been placed in the public domain.

# Appendix: The unload man page.

     NAME
     unload - Unload machine code.
     SYNOPSIS
     unload ?switches? fileName
     unload ?switches? fileName packageName
     unload ?switches? fileName packageName interp
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
This command tries to unload shared libraries previously
loaded with load from the application's address space.
fileName is the name of the file containing the library
file to be unload; it must be the same as the filename
provided to load for loading the library. packageName is
the name of the package, and is used to compute the name
of the unload procedure. interp is the path name of the
interpreter from which to unload the package (see the
interp manual entry for details); if interp is omitted,
it defaults to the interpreter in which the unload
command was invoked.

If the initial arguments to unload start with - then they
are treated as switches. The following switches are
currently supported:








|
|







252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
This command tries to unload shared libraries previously
loaded with load from the application's address space.
fileName is the name of the file containing the library
file to be unload; it must be the same as the filename
provided to load for loading the library. packageName is
the name of the package, and is used to compute the name
of the unload procedure. interp is the path name of the
interpreter from which to unload the package \(see the
interp manual entry for details\); if interp is omitted,
it defaults to the interpreter in which the unload
command was invoked.

If the initial arguments to unload start with - then they
are treated as switches. The following switches are
currently supported:

279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387

     Marks the end of switches. The argument following
     this one will be treated as a fileName even if it
     starts with a -.

When a file containing a shared library is loaded through
the load command, Tcl associates two reference counts to
the library file. The first counter shows how many times
the library has been loaded into normal (trusted)
interpreters while the second describes how many times
the library has been loaded into safe interpreters. As a
file containing a shared library can be loaded only once
by Tcl (with the first load call on the file), these
counters track how many interpreters use the library.
Each subsequent call to load after the first, simply
increaments the proper reference count.

unload works in the opposite direction. As a first step,
unload will check whether the library is unloadable: an
unloadable library exports a special unload procedure.
The name of the unload procedure is determined by
packageName and whether or not the target interpreter is
a safe one. For normal interpreters the name of the
initialization procedure will have the form pkg_Unload,
where pkg is the same as packageName except that the
first letter is converted to upper case and all other
letters are converted to lower case. For example, if
packageName is foo or FOo, the initialization procedure's
name will be Foo_Unload. If the target interpreter is a
safe interpreter, then the name of the initialization
procedure will be pkg_SafeUnload instead of pkg_Unload.

If unload determines that a library is not unloadable (or
unload functionality has been disabled during
compilation), an error will be returned. If the library
is unloadable, then unload will call the unload
procedure. If the unload procedure returns TCL_OK, unload
will proceed and decrease the proper reference count
(depending on the target interpreter type). When both
reference counts have reached 0, the library will be
detached from the process.

The unload procedure must match the following prototype:
typedef int Tcl_PackageUnloadProc(Tcl_Interp *interp, int
flags);

The interp argument identifies the interpreter from which
the library is to be unloaded. The unload procedure must
return TCL_OK or TCL_ERROR to indicate whether or not it
completed successfully; in the event of an error it
should set the interpreter's result to point to an error
message. In this case, the result of the unload command
will be the result returned by the unload procedure. The
flags argument can be either
TCL_UNLOAD_DETACH_FROM_INTERPRETER or
TCL_UNLOAD_DETACH_FROM_PROCESS. In case the library will
remain attached to the process after the unload procedure
returns (i.e. because the library is used by other
interpreters), TCL_UNLOAD_DETACH_FROM_INTERPRETER will be
defined. However, if the library is used only by the
target interpreter and the library will be detached from
the application as soon as the unload procedure returns,
the flags argument will be set to
TCL_UNLOAD_DETACH_FROM_PROCESS.

The unload command cannot unload libraries that are
statically linked with the application. If fileName is an
empty string, then packageName must be specified.
If packageName is omitted or specified as an empty
string, Tcl tries to guess the name of the package. This
may be done differently on different platforms. The
default guess, which is used on most UNIX platforms, is
to take the last element of fileName, strip off the first
three characters if they are lib, and use any following
alphabetic and underline characters as the module name.
For example, the command unload libxyz4.2.so uses the
module name xyz and the command unload bin/last.so {}
uses the module name last.

PORTABILITY ISSUES

Unix
     Not all unix operating systems support library
     unloading. Under such an operating system unload
     returns an error (unless -nocomplain has been
     specified).

Macintosh
     <Somebody to comment on this?>

BUGS

If the same file is loaded by different fileNames, it
will be loaded into the process's address space multiple
times. The behavior of this varies from system to system
(some systems may detect the redundant loads, others may
not). In case a library has been silently detached by the
operating system (and as a result Tcl thinks the library
is still loaded), it may be dangerous to use unload on
such a library (as the library will be completely
detached from the application while some interpreters
will continue to use it).

SEE ALSO

info sharedlibextension, load, safe

KEYWORDS

binary code, unloading, safe interpreter, shared library








|



|










|




|

|

|

|

|

|




|
|



|





|
|

|
|




|












|







|
|









|
|
|
|
|

|








>
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
     Marks the end of switches. The argument following
     this one will be treated as a fileName even if it
     starts with a -.

When a file containing a shared library is loaded through
the load command, Tcl associates two reference counts to
the library file. The first counter shows how many times
the library has been loaded into normal \(trusted\)
interpreters while the second describes how many times
the library has been loaded into safe interpreters. As a
file containing a shared library can be loaded only once
by Tcl \(with the first load call on the file\), these
counters track how many interpreters use the library.
Each subsequent call to load after the first, simply
increaments the proper reference count.

unload works in the opposite direction. As a first step,
unload will check whether the library is unloadable: an
unloadable library exports a special unload procedure.
The name of the unload procedure is determined by
packageName and whether or not the target interpreter is
a safe one. For normal interpreters the name of the
initialization procedure will have the form pkg\_Unload,
where pkg is the same as packageName except that the
first letter is converted to upper case and all other
letters are converted to lower case. For example, if
packageName is foo or FOo, the initialization procedure's
name will be Foo\_Unload. If the target interpreter is a
safe interpreter, then the name of the initialization
procedure will be pkg\_SafeUnload instead of pkg\_Unload.

If unload determines that a library is not unloadable \(or
unload functionality has been disabled during
compilation\), an error will be returned. If the library
is unloadable, then unload will call the unload
procedure. If the unload procedure returns TCL\_OK, unload
will proceed and decrease the proper reference count
\(depending on the target interpreter type\). When both
reference counts have reached 0, the library will be
detached from the process.

The unload procedure must match the following prototype:
typedef int Tcl\_PackageUnloadProc\(Tcl\_Interp \*interp, int
flags\);

The interp argument identifies the interpreter from which
the library is to be unloaded. The unload procedure must
return TCL\_OK or TCL\_ERROR to indicate whether or not it
completed successfully; in the event of an error it
should set the interpreter's result to point to an error
message. In this case, the result of the unload command
will be the result returned by the unload procedure. The
flags argument can be either
TCL\_UNLOAD\_DETACH\_FROM\_INTERPRETER or
TCL\_UNLOAD\_DETACH\_FROM\_PROCESS. In case the library will
remain attached to the process after the unload procedure
returns \(i.e. because the library is used by other
interpreters\), TCL\_UNLOAD\_DETACH\_FROM\_INTERPRETER will be
defined. However, if the library is used only by the
target interpreter and the library will be detached from
the application as soon as the unload procedure returns,
the flags argument will be set to
TCL\_UNLOAD\_DETACH\_FROM\_PROCESS.

The unload command cannot unload libraries that are
statically linked with the application. If fileName is an
empty string, then packageName must be specified.
If packageName is omitted or specified as an empty
string, Tcl tries to guess the name of the package. This
may be done differently on different platforms. The
default guess, which is used on most UNIX platforms, is
to take the last element of fileName, strip off the first
three characters if they are lib, and use any following
alphabetic and underline characters as the module name.
For example, the command unload libxyz4.2.so uses the
module name xyz and the command unload bin/last.so \{\}
uses the module name last.

PORTABILITY ISSUES

Unix
     Not all unix operating systems support library
     unloading. Under such an operating system unload
     returns an error \(unless -nocomplain has been
     specified\).

Macintosh
     <Somebody to comment on this?>

BUGS

If the same file is loaded by different fileNames, it
will be loaded into the process's address space multiple
times. The behavior of this varies from system to system
\(some systems may detect the redundant loads, others may
not\). In case a library has been silently detached by the
operating system \(and as a result Tcl thinks the library
is still loaded\), it may be dangerous to use unload on
such a library \(as the library will be completely
detached from the application while some interpreters
will continue to use it\).

SEE ALSO

info sharedlibextension, load, safe

KEYWORDS

binary code, unloading, safe interpreter, shared library

Name change from tip/101.tip to tip/101.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

TIP:		101
Title:		Export Tcltest Configuration
Version:	$Revision: 1.4 $
Author:		Don Porter <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	11-Jun-2002
Post-History:	
Tcl-Version:	8.4


~ Abstract

Proposes public command ''tcltest::configure'' to give programmatic
control to processing configuration options of the tcltest package.

~ Rationale

During ''package require tcltest'', the internal command
''ProcessCmdLineArgs'' is evaluated.  This command uses the contents
of ''$::argv'' as option-value pairs to configure several aspects of
the tcltest package.

This approach leaves two aspect of package configuration hardwired,
and outside of the control of users of ''tcltest''.  First, the timing
of configuration is fixed to package load time.  Second, the source of
configuration data is fixed to be the global variable ''argv''.

It would improve flexible use of tcltest to export a public command,
''tcltest::configure'', that will allow configuration of ''tcltest''
by its users at any time and from any source.

~ Proposal

Add and export the command ''tcltest::configure'', with the syntax:

|	tcltest::configure ?option? ?value option value ...?

With no options, ''configure'' returns a list of the available
configurable options.  With a single ''option'' argument,
''configure'' returns the corresponding value of that option, or an
error if no such option exists.  In the most general form,
''configure'' accepts an even number of arguments that are alternating
options and values, and sets each option to each value.

The list of options and acceptable values are to be the same as those
currently recognized by ''tcltest'' as its command line options.  The
difference is that this configuration can now be performed
programmatically, not only on the command line.

With complete programmatic access to ''tcltest'' configuration made
available, the special customization hooks ''processCmdLineArgsHook''
and ''processCmdLineArgsAddFlagsHook'' will be deprecated and removed
from the documentation.  Compatibility support for their existing use
will be provided as described below.

~ Compatibility

Many existing test suites have been written depending on the
auto-configuration from ''$::argv'' at package load time.  Some of
them may also be using the special customization hooks that allow the
addition of more command line options.  For compatibility, if the
presence of any of these hooks is detected, ''tcltest'' will fall back
to performing its load-time configuration.  Also, if any command that
can be influenced by configured values is called prior to any call to
''configure'', then automatic configuration from ''::argv'' will be
performed.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|


|

|
|
|



|

|


|


|

|

|

|
|
|

|



|



|
|
|



|


|


|


|


|


>

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

# TIP 101: Export Tcltest Configuration

	Author:		Don Porter <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	11-Jun-2002
	Post-History:	
	Tcl-Version:	8.4
-----

# Abstract

Proposes public command _tcltest::configure_ to give programmatic
control to processing configuration options of the tcltest package.

# Rationale

During _package require tcltest_, the internal command
_ProcessCmdLineArgs_ is evaluated.  This command uses the contents
of _$::argv_ as option-value pairs to configure several aspects of
the tcltest package.

This approach leaves two aspect of package configuration hardwired,
and outside of the control of users of _tcltest_.  First, the timing
of configuration is fixed to package load time.  Second, the source of
configuration data is fixed to be the global variable _argv_.

It would improve flexible use of tcltest to export a public command,
_tcltest::configure_, that will allow configuration of _tcltest_
by its users at any time and from any source.

# Proposal

Add and export the command _tcltest::configure_, with the syntax:

		tcltest::configure ?option? ?value option value ...?

With no options, _configure_ returns a list of the available
configurable options.  With a single _option_ argument,
_configure_ returns the corresponding value of that option, or an
error if no such option exists.  In the most general form,
_configure_ accepts an even number of arguments that are alternating
options and values, and sets each option to each value.

The list of options and acceptable values are to be the same as those
currently recognized by _tcltest_ as its command line options.  The
difference is that this configuration can now be performed
programmatically, not only on the command line.

With complete programmatic access to _tcltest_ configuration made
available, the special customization hooks _processCmdLineArgsHook_
and _processCmdLineArgsAddFlagsHook_ will be deprecated and removed
from the documentation.  Compatibility support for their existing use
will be provided as described below.

# Compatibility

Many existing test suites have been written depending on the
auto-configuration from _$::argv_ at package load time.  Some of
them may also be using the special customization hooks that allow the
addition of more command line options.  For compatibility, if the
presence of any of these hooks is detected, _tcltest_ will fall back
to performing its load-time configuration.  Also, if any command that
can be influenced by configured values is called prior to any call to
_configure_, then automatic configuration from _::argv_ will be
performed.

# Copyright

This document has been placed in the public domain.

Name change from tip/102.tip to tip/102.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

TIP:		102
Title:		Change [trace list] to [trace info]
Author:		Reinhard Max <[email protected]>
Type:		Project
Tcl-Version:	8.4
State:		Final
Created:	12-Jun-2002
Keywords:	trace, info, introspection
Version:	$Revision: 1.4 $
Vote:		Done
Post-History:	


~ Abstract

This TIP proposes to change the name of the introspection subcommand
of the ''trace'' command from ''list'' to ''info''.

~ Rationale

Although the functionality of the ''trace'' command (as extended by
[62]) is good, the name of the introspection subcommand, ''list'' is
not such a good choice:

 * The name ''info'' is already well known for introspection purposes
   in Tcl (e.g. [[info]] and [[after info]].)

 * The name [[trace list]] could be misunderstood as having to do with
   tracing lists.

 * The introspection subcommand to trace could be extended to allow
   more specific queries along the lines of [[info commands]], [[info
   procs]], and [[info vars]].  ''(This is outside the scope of this
   TIP.)''

Hence, this TIP calls for the ''list'' subcommand to be renamed to
''info''.  (Note that this also makes the subcommand for introspecting
on variable traces more similar to its old form ''vinfo''.)

~ Copyright

This document is placed in the public domain.

<
|
|
|
|
|
|
|
<
|
|
>

|


|

|

|
|


|
|

|



|
|
|

|
|
|

|


>

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

# TIP 102: Change [trace list] to [trace info]
	Author:		Reinhard Max <[email protected]>
	Type:		Project
	Tcl-Version:	8.4
	State:		Final
	Created:	12-Jun-2002
	Keywords:	trace, info, introspection

	Vote:		Done
	Post-History:	
-----

# Abstract

This TIP proposes to change the name of the introspection subcommand
of the _trace_ command from _list_ to _info_.

# Rationale

Although the functionality of the _trace_ command \(as extended by
[[62]](62.md)\) is good, the name of the introspection subcommand, _list_ is
not such a good choice:

 * The name _info_ is already well known for introspection purposes
   in Tcl \(e.g. [info] and [after info].\)

 * The name [trace list] could be misunderstood as having to do with
   tracing lists.

 * The introspection subcommand to trace could be extended to allow
   more specific queries along the lines of [info commands], [info
   procs], and [info vars].  _\(This is outside the scope of this
   TIP.\)_

Hence, this TIP calls for the _list_ subcommand to be renamed to
_info_.  \(Note that this also makes the subcommand for introspecting
on variable traces more similar to its old form _vinfo_.\)

# Copyright

This document is placed in the public domain.

Name change from tip/103.tip to tip/103.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178




179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222

TIP:            103
Title:          Argument Expansion Command
Version:        $Revision: 1.13 $
Author:         Peter Spjuth <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         Andreas Leitgeb <[email protected]>
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.

<
|
<
|
|
|
|
|
|
|
|
|
>

|




|






|





|













|
|
|





|



|
|
|




|
|
|



|
|
|








|


|


|
|
|









|





|









|
|











|


|

|

|



|

|








|






|
|

|
|
|
|
|
|
|
|
|

|
|

|
<
<
<
<
>
>
>
>
|

|
|
|
|

|
|
|
|



|
|
|




|
|

|




|



|

|

|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173




174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222

# TIP 103: Argument Expansion Command

	Author:         Peter Spjuth <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         Andreas Leitgeb <[email protected]>
	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.

Name change from tip/104.tip to tip/104.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

TIP:            104
Title:          Generalization of the Tk Undo Subsystem
Version:        $Revision: 1.6 $
Author:         Ludwig Callewaert <[email protected]>
Author:         Larry W. Virden. <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        19-Jun-2002
Post-History:   
Discussions-To: news:comp.lang.tcl
Tcl-Version:    8.4


~ Abstract

This TIP proposes a reimplementation of the Tk Text widget undo
feature.  The text widget interface is not affected.  No functional
changes are made at the Tcl level.  The purpose of the
reimplementation is to move the undo feature from a text only
implementation to a general implementation also usable by other
widgets.  This opens the door to undoing also tag, mark and other
operations, and allows for an exposure of the undo stack at the Tcl
level.  These new features are however not part of this TIP.

~ Rationale

As stated in the abstract, the current implementation of the text
widget undo feature only allows for text changes to be undone.  The
usefulness of the undo feature would increase tremendously if
other operations could be undone (tags, marks, embedded windows, ...).
This was already part of the [26] discussions.  This TIP deals with
the generalization of the undo stack to cope with these requirements.

~ Specification

As the undo functionality is no longer text widget specific, it has
been put in a separate file ''generic/tkUndo.c'' along with its header
file ''generic/tkUndo.h''.  The ''TkUndoRedoStack'' is a structure
containing the undo and redo stacks.  These undo and redo stacks are
linked lists of ''TkUndoAtom'' structures.  There are two types of
these atoms: the separator (similar to the previous implementation)
and the command.  When the type is command, both an ''apply'' and a
''revert'' action need to be provided.  The apply action is for the
redo.  The revert action is for the undo.  Both are pointers to a
''Tcl_Obj'', so they can (and should) contain a Tcl script.

The following functions all operating on a ''TkUndoRedoStack''
stack are provided to implement the undo/redo functionality.

   1. ''TkUndoInitStack(interp)'': returns a pointer to an initialized
      TkUndoRedoStack and stores ''interp'' in that stack for script
      evaluation.

   2. ''TkUndoClearStacks(stack)'': clears both the undo and the redo
      stacks.

   3. ''TkUndoFreeStack(stack)'': clears both undo and redo stacks and
      frees any memory allocated to ''stack''.

   4. ''TkUndoInsertUndoSeparator(stack)'': inserts a
      separator on the undo stack.  Note that there is currently no
      need for a ''TkUndoInsertRedoSeparator'' function, as the redo
      stack is managed by the internals of ''TkUndo''.

   5. ''TkUndoPushAction(stack, actionScript, revertScript)'': pushes 
      an action of the undo stack (an atom of type command).
      ''actionScript'' and ''revertScript'' are ''Tcl_DString''
      pointers that provide the script to redo and undo the action
      respectively.  The redo stack is cleared.

   6. ''TkUndoRevert(stack)'': undo a compound action.
      Compound means all revert script of action between two
      separators on the undo stack are evaluated in the stack's 
      interpreter and the actions are moved to the redo stack.
      Returns TCL_ERROR when unsuccessful (stack empty for instance),
      and TCL_OK otherwise.

   7. ''TkUndoApply(stack)'': redo a compound action.  The
      apply script of all actions between two separators on the redo
      stack is evaluated in the stack's interpreter.  The actions are
      moved to the undo stack.  Returns TCL_ERROR when unsuccessful
      (stack empty for instance), and TCL_OK otherwise.

   8. ''TkUndoSetDepth(stack, maxDepth)'': sets the maximum number
      of compound actions stored on the stack to ''maxDepth''.  By
      default, stacks are unlimited, and a value of ''maxDepth'' <= 0
      resets the stack to be unlimited.

   9. The option ''-maxundo'' is added to the text widget to access the
      stack limit feature of the text widget's undo stack from the
      script level.

These functions are sufficient to implement the current undo
functionality of the text widget, and they have been used for this
purpose.

~ Reference Implementation

See patch #554763 on SourceForge: ''
https://sourceforge.net/tracker/?func=detail&atid=312997&aid=554763&group_id=12997
''


~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|










|




|
|


|


|
|

|
|
|
|

|

|


|
|


|


|
|

|

|
|

|
|
|



|



|
|

|


|
|

|
|
|


|







|

|
|
<
|
>
|


>

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

# TIP 104: Generalization of the Tk Undo Subsystem

	Author:         Ludwig Callewaert <[email protected]>
	Author:         Larry W. Virden. <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        19-Jun-2002
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Tcl-Version:    8.4
-----

# Abstract

This TIP proposes a reimplementation of the Tk Text widget undo
feature.  The text widget interface is not affected.  No functional
changes are made at the Tcl level.  The purpose of the
reimplementation is to move the undo feature from a text only
implementation to a general implementation also usable by other
widgets.  This opens the door to undoing also tag, mark and other
operations, and allows for an exposure of the undo stack at the Tcl
level.  These new features are however not part of this TIP.

# Rationale

As stated in the abstract, the current implementation of the text
widget undo feature only allows for text changes to be undone.  The
usefulness of the undo feature would increase tremendously if
other operations could be undone \(tags, marks, embedded windows, ...\).
This was already part of the [[26]](26.md) discussions.  This TIP deals with
the generalization of the undo stack to cope with these requirements.

# Specification

As the undo functionality is no longer text widget specific, it has
been put in a separate file _generic/tkUndo.c_ along with its header
file _generic/tkUndo.h_.  The _TkUndoRedoStack_ is a structure
containing the undo and redo stacks.  These undo and redo stacks are
linked lists of _TkUndoAtom_ structures.  There are two types of
these atoms: the separator \(similar to the previous implementation\)
and the command.  When the type is command, both an _apply_ and a
_revert_ action need to be provided.  The apply action is for the
redo.  The revert action is for the undo.  Both are pointers to a
_Tcl\_Obj_, so they can \(and should\) contain a Tcl script.

The following functions all operating on a _TkUndoRedoStack_
stack are provided to implement the undo/redo functionality.

   1. _TkUndoInitStack\(interp\)_: returns a pointer to an initialized
      TkUndoRedoStack and stores _interp_ in that stack for script
      evaluation.

   2. _TkUndoClearStacks\(stack\)_: clears both the undo and the redo
      stacks.

   3. _TkUndoFreeStack\(stack\)_: clears both undo and redo stacks and
      frees any memory allocated to _stack_.

   4. _TkUndoInsertUndoSeparator\(stack\)_: inserts a
      separator on the undo stack.  Note that there is currently no
      need for a _TkUndoInsertRedoSeparator_ function, as the redo
      stack is managed by the internals of _TkUndo_.

   5. _TkUndoPushAction\(stack, actionScript, revertScript\)_: pushes 
      an action of the undo stack \(an atom of type command\).
      _actionScript_ and _revertScript_ are _Tcl\_DString_
      pointers that provide the script to redo and undo the action
      respectively.  The redo stack is cleared.

   6. _TkUndoRevert\(stack\)_: undo a compound action.
      Compound means all revert script of action between two
      separators on the undo stack are evaluated in the stack's 
      interpreter and the actions are moved to the redo stack.
      Returns TCL\_ERROR when unsuccessful \(stack empty for instance\),
      and TCL\_OK otherwise.

   7. _TkUndoApply\(stack\)_: redo a compound action.  The
      apply script of all actions between two separators on the redo
      stack is evaluated in the stack's interpreter.  The actions are
      moved to the undo stack.  Returns TCL\_ERROR when unsuccessful
      \(stack empty for instance\), and TCL\_OK otherwise.

   8. _TkUndoSetDepth\(stack, maxDepth\)_: sets the maximum number
      of compound actions stored on the stack to _maxDepth_.  By
      default, stacks are unlimited, and a value of _maxDepth_ <= 0
      resets the stack to be unlimited.

   9. The option _-maxundo_ is added to the text widget to access the
      stack limit feature of the text widget's undo stack from the
      script level.

These functions are sufficient to implement the current undo
functionality of the text widget, and they have been used for this
purpose.

# Reference Implementation

See patch \#554763 on SourceForge: _
<https://sourceforge.net/tracker/?func=detail&atid=312997&aid=554763&group\_id=12997>

_

# Copyright

This document has been placed in the public domain.

Name change from tip/105.tip to tip/105.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

TIP:		105
Title:		Add Prefix Matching for Switch
State:		Withdrawn
Type:		Project
Tcl-Version:	8.5
Vote:		Pending
Post-History:	
Version:	$Revision: 1.4 $
Author:		Donal K. Fellows <[email protected]>
Created:	03-Jul-2002
Obsoleted-By:	195


~ Abstract

This TIP adds a new option to the [[switch]] command to support
matching of strings to unique prefixes of patterns, similar to Tcl's
existing subcommand-name matching or Tk's option-name matching.

~ Rationale

When code (particularly in script libraries) wants to support shortest
unique prefix matching in the manner of the Tcl core (as provided by
''Tcl_GetIndexFromObj'') currently either the prefixes have to be
precomputed (by hand or by script) or the matching has to be done
backwards.  In the first case, this is either error-prone or requires
an extra piece of code that has to be developed by the programmer.  In
the second case, the code has to be converted into a pattern which is
matched against the list of supported options in some way, which is
either inefficient or has hazards if the string being matched contains
characters that are meaningful to the matching engine being used.
Instead, it would be far nicer if we could make the core support this
directly, so that script authors could just say what they mean.

~ Proposed Change

To support this, I propose modifying the ''switch'' command to take an
extra option ''-prefix'' (which should be mutually exclusive with
''-exact'', ''-glob'' and ''-regexp'' of course) to enable prefix
matching.  When prefix matching is enabled, the arm chosen for
execution will be the one such that the switch value is identical to
or an unambiguous prefix of its pattern (i.e. it will not be a prefix
of any other pattern listed, unless the pattern of the arm chosen is
exactly equal to the switch value.)  If there is no arm whose pattern
is an unambiguous prefix of the switch value, the default arm will be
selected for execution, or if there is no default arm, the switch
command will terminate without an error and with an empty result (this
is in contrast to the behaviour of ''Tcl_GetIndexFromObj''.)

~ Examples

The command:

|switch -prefix f {
|   foo {
|      puts "matched foo"
|   }

|   bar {
|      puts "matched bar"
|   }
|}



prints "matched foo".  The command:

|switch -prefix b {
|   bar {
|      puts "matched bar"
|   }

|   boo {
|      puts "matched boo"
|   }

|   default {
|      puts "the default action"
|   }
|}



prints "the default action" ("b" is a prefix of two patterns.)  The
command:

|switch -prefix tcl {
|   tcl {
|      puts "The Tool Command Language"
|   }

|   tk {
|      puts "The Tk Toolkit"
|   }

|   tcl/tk {
|      puts "A cool combination"
|   }
|}



prints "The Tool Command Language" (although "tcl" is a prefix of two
patterns, it matches one of them exactly.)

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|

|



|

|
|
|
|









|

|
|
|


|

|


|
|

|



|
|
|
<
>
|
|
<
<
|
>
>


|
|
|
<
>
|
|
<
>
|
|
<
<
|
>
>
|


|
|
|
<
>
|
|
<
>
|
|
<
<
|
>
>
|
|

|


>

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

# TIP 105: Add Prefix Matching for Switch
	State:		Withdrawn
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Pending
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	03-Jul-2002
	Obsoleted-By:	195
-----

# Abstract

This TIP adds a new option to the [switch] command to support
matching of strings to unique prefixes of patterns, similar to Tcl's
existing subcommand-name matching or Tk's option-name matching.

# Rationale

When code \(particularly in script libraries\) wants to support shortest
unique prefix matching in the manner of the Tcl core \(as provided by
_Tcl\_GetIndexFromObj_\) currently either the prefixes have to be
precomputed \(by hand or by script\) or the matching has to be done
backwards.  In the first case, this is either error-prone or requires
an extra piece of code that has to be developed by the programmer.  In
the second case, the code has to be converted into a pattern which is
matched against the list of supported options in some way, which is
either inefficient or has hazards if the string being matched contains
characters that are meaningful to the matching engine being used.
Instead, it would be far nicer if we could make the core support this
directly, so that script authors could just say what they mean.

# Proposed Change

To support this, I propose modifying the _switch_ command to take an
extra option _-prefix_ \(which should be mutually exclusive with
_-exact_, _-glob_ and _-regexp_ of course\) to enable prefix
matching.  When prefix matching is enabled, the arm chosen for
execution will be the one such that the switch value is identical to
or an unambiguous prefix of its pattern \(i.e. it will not be a prefix
of any other pattern listed, unless the pattern of the arm chosen is
exactly equal to the switch value.\)  If there is no arm whose pattern
is an unambiguous prefix of the switch value, the default arm will be
selected for execution, or if there is no default arm, the switch
command will terminate without an error and with an empty result \(this
is in contrast to the behaviour of _Tcl\_GetIndexFromObj_.\)

# Examples

The command:

	switch -prefix f {
	   foo {
	      puts "matched foo"

	   }
	   bar {
	      puts "matched bar"


	   }
	}

prints "matched foo".  The command:

	switch -prefix b {
	   bar {
	      puts "matched bar"

	   }
	   boo {
	      puts "matched boo"

	   }
	   default {
	      puts "the default action"


	   }
	}

prints "the default action" \("b" is a prefix of two patterns.\)  The
command:

	switch -prefix tcl {
	   tcl {
	      puts "The Tool Command Language"

	   }
	   tk {
	      puts "The Tk Toolkit"

	   }
	   tcl/tk {
	      puts "A cool combination"


	   }
	}

prints "The Tool Command Language" \(although "tcl" is a prefix of two
patterns, it matches one of them exactly.\)

# Copyright

This document has been placed in the public domain.

Name change from tip/106.tip to tip/106.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

TIP:            106
Title:          Add Encoding Abilities to the [dde] Command
Version:        $Revision: 1.14 $
Author:         Harald Oehlmann <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        13-Aug-2002
Post-History:   
Tcl-Version:    8.6


~ Abstract

When using Windows DDE communication with non-Tcl programs, the encoding of
the exchanged strings is mostly needed to be the system encoding.  Selection
of this behaviour should be possible with in the '''dde''' command should be
done by a parameter.

~ Specification

Extend the '''dde''' commands taking a data argument by the switch
'''-binary''':

 > '''dde execute''' ?'''-async'''? ?'''-binary'''? ''service topic data''

 > '''dde poke''' ?'''-binary'''? ''service topic item data''

The argument ''data'' is taken as a binary string if the '''-binary''' switch
is given.  Otherwise, it is interpreted as utf-8.

Examples:

| dde execute -binary CS CS [encoding convertto [encoding system] �pfel]\0
| dde poke -binary CS CS I [encoding convertto [encoding system] �pfel]\0

~ Rationale

The communication with DDE with external programs uses the format clipboard
''CF_TEXT'' and the sent text should be coded in the system encoding
(''cp1252'' in my locale).

Most people who use DDE to communicate with, for example, Excel use the fact
that what Excel expects (''cp1252'') and what Tcl actually sends (''utf-8'')
is identical for 7-bit values and they don't use 8-bit values.  Unfortunately,
characters used in languages like German, French, etc., are located over this
limit and thus are not transferable.

Peter Hardie addressed this point on 2000-10-26 in the Tcl Feature Request at
SourceForge (#219185: "dde only handles UTF-8 data (-binary patch available)"
[http://sf.net/tracker/?func=detail&aid=219185&group_id=10894&atid=360894]).
His proposal was to add a '''-binary''' option.

This is a reasonable solution, because any encoding including the system
encoding may be used as shown in the upper example.

~ Reference Implementation

See the ''tip-106-impl'' branch in Tcl's fossil repository
[https://core.tcl.tk/tcl/timeline?r=tip-106-impl].

~ Rejected Alternatives

I proposed to use a switch ?'''-encoding''' ''encoding''? which would
avoid the preparation of an encoded string by '''encoding convertto'''.
DDE is so little used at those days so a minimal support is sufficient.

The '''dde request''' subcommand already has a parameter ''-binary''.
It is more logical to extend this to the other commands.

~ Copyright

This document has been placed in the public domain

<
|
<
|
|
|
|
|
|
|
>

|



|


|

|
|

|

|

|




|
|

|


|
|


|





|
|
|




|

|
|

|

|
|


|


|


>

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

# TIP 106: Add Encoding Abilities to the [dde] Command

	Author:         Harald Oehlmann <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        13-Aug-2002
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

When using Windows DDE communication with non-Tcl programs, the encoding of
the exchanged strings is mostly needed to be the system encoding.  Selection
of this behaviour should be possible with in the **dde** command should be
done by a parameter.

# Specification

Extend the **dde** commands taking a data argument by the switch
**-binary**:

 > **dde execute** ?**-async**? ?**-binary**? _service topic data_

 > **dde poke** ?**-binary**? _service topic item data_

The argument _data_ is taken as a binary string if the **-binary** switch
is given.  Otherwise, it is interpreted as utf-8.

Examples:

	 dde execute -binary CS CS [encoding convertto [encoding system] Äpfel]\0
	 dde poke -binary CS CS I [encoding convertto [encoding system] Äpfel]\0

# Rationale

The communication with DDE with external programs uses the format clipboard
_CF\_TEXT_ and the sent text should be coded in the system encoding
\(_cp1252_ in my locale\).

Most people who use DDE to communicate with, for example, Excel use the fact
that what Excel expects \(_cp1252_\) and what Tcl actually sends \(_utf-8_\)
is identical for 7-bit values and they don't use 8-bit values.  Unfortunately,
characters used in languages like German, French, etc., are located over this
limit and thus are not transferable.

Peter Hardie addressed this point on 2000-10-26 in the Tcl Feature Request at
SourceForge \(\#219185: "dde only handles UTF-8 data \(-binary patch available\)"
<http://sf.net/tracker/?func=detail&aid=219185&group_id=10894&atid=360894> \).
His proposal was to add a **-binary** option.

This is a reasonable solution, because any encoding including the system
encoding may be used as shown in the upper example.

# Reference Implementation

See the _tip-106-impl_ branch in Tcl's fossil repository
<https://core.tcl.tk/tcl/timeline?r=tip-106-impl> .

# Rejected Alternatives

I proposed to use a switch ?**-encoding** _encoding_? which would
avoid the preparation of an encoded string by **encoding convertto**.
DDE is so little used at those days so a minimal support is sufficient.

The **dde request** subcommand already has a parameter _-binary_.
It is more logical to extend this to the other commands.

# Copyright

This document has been placed in the public domain

Name change from tip/107.tip to tip/107.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

TIP:		107
Title:		Fix the 2-second "raise delay" in Tk
Version:	$Revision: 1.4 $
Author:		Joe English <[email protected]>
State:		Final
Type:		Project
Created:	28-Aug-2002
Tcl-Version:	8.4
Vote:		Done
Post-History:	


~ Abstract

This TIP explains the genesis of the long delays often associated with
the [[raise]] and [[lower]] commands under Unix/X with some window
managers, as well as describing the solution.

~ Rationale

Currently, Tk's [[raise]] and [[lower]] commands do not return to the
caller until the operation has completed.  Under Unix, the window
manager is responsible for changing the stacking order of toplevel
windows, so [[raise]] and [[lower]] must wait for a notification from
the WM before returning.  Not all window managers are ICCCM-compliant
in this regard, however, so the operation may time out instead.

This two-second "raise delay" has been a longstanding, persistent
problem in Tk.  It has supposedly been fixed several times, but the
problem keeps reoccurring under new window managers and new
environments.  At present, the problem is most noticeable under KDE 2
and KDE 3.

~ Proposal

Change Tk so that [[raise]] and [[lower]] return immediately, without
waiting for a notification that may not be forthcoming.

This should not be be a controversial change.  This behaviour is not
documented anywhere, and is not observable by Tk programs except via
[[wm stackorder]] (see [74]).

Moreover, the guarantee is largely meaningless.  After [[raise]]
returns, the window ''contents'' may still not be visible (there may
be pending <Expose> events, for example), and the actual position in
the stacking order is still subject to window manager intervention.

~ Compatibility Issues

The only Tk programs that would break with this change are ones which
expect the return value of [[wm stackorder]] to reflect the results of
any immediately-preceding [[raise]] and [[lower]] commands.  (The Tk
test suite is one such program, and would need to be modified).

Unfortunately there is no reliable way to fix such programs -
[[update]] will not work, and the ICCCM does not, to the author's
knowledge, provide a way to synchronize with the window manager to
make sure it has processed all outstanding client requests.  Even if
it did, this wouldn't help - the raise delay problem only occurs under
non-compliant window managers to begin with!

Since the stacking order is not observable except through [[wm
stackorder]] - that was the whole point of [74] - no other programs
will be affected.  (Note that [[wm stackorder]] will still work: the
only difference is that it may return soon-to-be out-of-date
information.  Since this is the case already - the user may restack or
iconify windows at any time - this change should be low-impact.)

~ Reference Implementation

See Sourceforge Tk Patch #601518.
http://sourceforge.net/tracker/index.php?func=detail&aid=601518&group_id=12997&atid=312997

~ Author's Note

Could we fast-track this?  It's a longstanding problem with a simple
fix and ought to make it in before 8.4 goes final.

~ Detailed Analysis

First, some terminology:

    *	''toplevel'': a Tk [[toplevel]] window.

    *	''wrapper'': an auxiliary window created by Tk to hold the
	toplevel and its (optional) menubar.  Initially created as a
	child of the root window.

    *	''client window'': From the window manager's perspective, any
	window created as a child of the root window by an X client.
	Tk wrapper windows are client windows.  Most window managers
	reparent client windows under a new frame window which holds
	window manager decorations.

    *	''reparent'': Used as a noun, the immediate parent of a
	wrapper which has been reparented by a window manager.

    *	''frame'': The immediate child of the root window (or virtual
	root window) created by the window manager to hold a client
	window and its decorations.  May or may not be the same as the
	reparent window.

Next, some methodology:

The correct way to change the stacking order of a client window is to
make a ''ConfigureRequest'' on the client window with ''stack_mode''
set appropriately.  If the client has not been reparented, then the X
server performs the operation directly, and will send a
''ConfigureNotify'' back to the client if, and only if, the actual
stacking order has changed.  (Raising a window which is already at the
top of the stacking order will not result in a ''ConfigureNotify'',
for example).

If the client window ''has'' been reparented (which is usually the
case), then the window manager intercepts the request and, at its
discretion, restacks the frame window instead.  It then sends a
synthetic ''ConfigureNotify'' back to the client, regardless of
whether or not it honored the request.

If the stacking order is to be changed relative to some other window -
that is, if the ''sibling'' field is also set - and the client has
been reparented, then the ''ConfigureRequest'' will fail with a
''BadMatch'' error before it gets to the WM.  Clients must be prepared
to handle this case by catching the error and re-sending a synthetic
''ConfigureRequest'' to the root window, which the WM receives and
handles as above.

See ICCCM section 4.1.5 "Configuring the Window" for the full
specification.  The Xlib function ''XReconfigureWMWindow()'' takes
care of all these details.

Now, some archaeology:

Tk 4.0 did not do this: instead, it called ''XConfigureWindow()'' on
the ''reparent'' window, then waited for a ''ConfigureNotify'' on that
window.

This was wrong on at least two counts.  First, the reparent window
might not be the same as the frame window, in which case this would
have no effect at all.  (In 4DWm and Sawfish, for example, the
reparent window is a child of an outer frame window).  Second, it's
not ICCCM-compliant (Tk doesn't own the reparent window and shouldn't
be mucking with it).

Tk 4.0 also included several heuristics that attempted to determine
when the operation was unnecessary, to avoid waiting for a
''ConfigureNotify'' on the reparent that was not forthcoming.

In Tk 4.1, the (incorrect) call to ''XConfigureWindow()'' on the
reparent was changed to a (correct) call to ''XReconfigureWMWindow()''
on the wrapper, but the old heuristic code was left mostly intact.

Browsing the CVS logs and the older Tk Changelog, we see that this
code has been updated several times to account for new conditions, but
ultimately without success: the problem persists.

These heuristics are not needed at all under WMs which send a
synthetic ''ConfigureNotify'' in response to client window stacking
order changes.  On some non-compliant WMs, however, they may help
lessen the problem - more by accident than by design - if the reparent
is the same as the frame window then the Tk 4.0 heuristics sometimes
still work.  But even then the heuristics are not reliable.  For
instance under KDE 2.2 and KDE 3, calling [[raise]] twice in
succession always results in a 2-second delay.

It is the author's opinion that the only way forward is to let
[[raise]] and [[lower]] run asynchronously, and fix the two-second
raise delay once and for all.

~ Copyright

This document is hereby placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|


|

|


|









|

|




|

|
|
|


|


|
|
|


|





|
|
|


|

|

|
|

|




|



|

|
|


|





|


|
|






|


|
|
|
|

|
|

|



|
|
|

|



|




|
|




|
|
|
|



|

|
|







|




|



|


|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

# TIP 107: Fix the 2-second "raise delay" in Tk

	Author:		Joe English <[email protected]>
	State:		Final
	Type:		Project
	Created:	28-Aug-2002
	Tcl-Version:	8.4
	Vote:		Done
	Post-History:	
-----

# Abstract

This TIP explains the genesis of the long delays often associated with
the [raise] and [lower] commands under Unix/X with some window
managers, as well as describing the solution.

# Rationale

Currently, Tk's [raise] and [lower] commands do not return to the
caller until the operation has completed.  Under Unix, the window
manager is responsible for changing the stacking order of toplevel
windows, so [raise] and [lower] must wait for a notification from
the WM before returning.  Not all window managers are ICCCM-compliant
in this regard, however, so the operation may time out instead.

This two-second "raise delay" has been a longstanding, persistent
problem in Tk.  It has supposedly been fixed several times, but the
problem keeps reoccurring under new window managers and new
environments.  At present, the problem is most noticeable under KDE 2
and KDE 3.

# Proposal

Change Tk so that [raise] and [lower] return immediately, without
waiting for a notification that may not be forthcoming.

This should not be be a controversial change.  This behaviour is not
documented anywhere, and is not observable by Tk programs except via
[wm stackorder] \(see [[74]](74.md)\).

Moreover, the guarantee is largely meaningless.  After [raise]
returns, the window _contents_ may still not be visible \(there may
be pending <Expose> events, for example\), and the actual position in
the stacking order is still subject to window manager intervention.

# Compatibility Issues

The only Tk programs that would break with this change are ones which
expect the return value of [wm stackorder] to reflect the results of
any immediately-preceding [raise] and [lower] commands.  \(The Tk
test suite is one such program, and would need to be modified\).

Unfortunately there is no reliable way to fix such programs -
[update] will not work, and the ICCCM does not, to the author's
knowledge, provide a way to synchronize with the window manager to
make sure it has processed all outstanding client requests.  Even if
it did, this wouldn't help - the raise delay problem only occurs under
non-compliant window managers to begin with!

Since the stacking order is not observable except through [wm
stackorder] - that was the whole point of [[74]](74.md) - no other programs
will be affected.  \(Note that [wm stackorder] will still work: the
only difference is that it may return soon-to-be out-of-date
information.  Since this is the case already - the user may restack or
iconify windows at any time - this change should be low-impact.\)

# Reference Implementation

See Sourceforge Tk Patch \#601518.
<http://sourceforge.net/tracker/index.php?func=detail&aid=601518&group\_id=12997&atid=312997>

# Author's Note

Could we fast-track this?  It's a longstanding problem with a simple
fix and ought to make it in before 8.4 goes final.

# Detailed Analysis

First, some terminology:

    *	_toplevel_: a Tk [toplevel] window.

    *	_wrapper_: an auxiliary window created by Tk to hold the
	toplevel and its \(optional\) menubar.  Initially created as a
	child of the root window.

    *	_client window_: From the window manager's perspective, any
	window created as a child of the root window by an X client.
	Tk wrapper windows are client windows.  Most window managers
	reparent client windows under a new frame window which holds
	window manager decorations.

    *	_reparent_: Used as a noun, the immediate parent of a
	wrapper which has been reparented by a window manager.

    *	_frame_: The immediate child of the root window \(or virtual
	root window\) created by the window manager to hold a client
	window and its decorations.  May or may not be the same as the
	reparent window.

Next, some methodology:

The correct way to change the stacking order of a client window is to
make a _ConfigureRequest_ on the client window with _stack\_mode_
set appropriately.  If the client has not been reparented, then the X
server performs the operation directly, and will send a
_ConfigureNotify_ back to the client if, and only if, the actual
stacking order has changed.  \(Raising a window which is already at the
top of the stacking order will not result in a _ConfigureNotify_,
for example\).

If the client window _has_ been reparented \(which is usually the
case\), then the window manager intercepts the request and, at its
discretion, restacks the frame window instead.  It then sends a
synthetic _ConfigureNotify_ back to the client, regardless of
whether or not it honored the request.

If the stacking order is to be changed relative to some other window -
that is, if the _sibling_ field is also set - and the client has
been reparented, then the _ConfigureRequest_ will fail with a
_BadMatch_ error before it gets to the WM.  Clients must be prepared
to handle this case by catching the error and re-sending a synthetic
_ConfigureRequest_ to the root window, which the WM receives and
handles as above.

See ICCCM section 4.1.5 "Configuring the Window" for the full
specification.  The Xlib function _XReconfigureWMWindow\(\)_ takes
care of all these details.

Now, some archaeology:

Tk 4.0 did not do this: instead, it called _XConfigureWindow\(\)_ on
the _reparent_ window, then waited for a _ConfigureNotify_ on that
window.

This was wrong on at least two counts.  First, the reparent window
might not be the same as the frame window, in which case this would
have no effect at all.  \(In 4DWm and Sawfish, for example, the
reparent window is a child of an outer frame window\).  Second, it's
not ICCCM-compliant \(Tk doesn't own the reparent window and shouldn't
be mucking with it\).

Tk 4.0 also included several heuristics that attempted to determine
when the operation was unnecessary, to avoid waiting for a
_ConfigureNotify_ on the reparent that was not forthcoming.

In Tk 4.1, the \(incorrect\) call to _XConfigureWindow\(\)_ on the
reparent was changed to a \(correct\) call to _XReconfigureWMWindow\(\)_
on the wrapper, but the old heuristic code was left mostly intact.

Browsing the CVS logs and the older Tk Changelog, we see that this
code has been updated several times to account for new conditions, but
ultimately without success: the problem persists.

These heuristics are not needed at all under WMs which send a
synthetic _ConfigureNotify_ in response to client window stacking
order changes.  On some non-compliant WMs, however, they may help
lessen the problem - more by accident than by design - if the reparent
is the same as the frame window then the Tk 4.0 heuristics sometimes
still work.  But even then the heuristics are not reliable.  For
instance under KDE 2.2 and KDE 3, calling [raise] twice in
succession always results in a 2-second delay.

It is the author's opinion that the only way forward is to let
[raise] and [lower] run asynchronously, and fix the two-second
raise delay once and for all.

# Copyright

This document is hereby placed in the public domain.

Name change from tip/108.tip to tip/108.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

TIP:            108
Title:          Summary of Changes to Generic Tcl/Tk Code to Enable Mac OS X Port
Version:        $Revision: 1.2 $
Author:         Jim Ingham <[email protected]>
State:          Final
Type:           Informative
Vote:           No voting
Created:        29-Aug-2002
Post-History:   


~ Abstract

The submission of the changes to generic Tcl/Tk necessary for the Mac
OS X port was discussed on the Tcl Core mailing list.  In light of the
very minor changes to shared code involved, and to facilitate
including the port in the 8.4 release, it was decided that we would
not hold a formal vote.  This informational TIP is offered to
summarize the work done, however, and to maintain a more complete
record.

~ What Changes are Required for the Mac OS X Port?

These fall into two parts: macosx only changes, and changes that
effect generic code.

The Mac OS X-only changes again fall into two parts.  On the one hand,
we introduced new macosx directories to the Tcl and Tk trees, at the
same level as the win, unix and mac directories.  At present, the
''tcl/macosx'' directory only contains one ''.c'' file and a project
file.  The ''tk/macosx'' directory is much more substantial.  This set
of changes manifestly only effects this port, and since something is
better than nothing, should be uncontroversial.

The other Mac OS X-only part is the addition of Mac OS X specific
elements to the ''.decls'' files.  This should also be
uncontroversial, though I had to add some slightly non-trivial code to
the ''genStubs.tcl'' file to handle the fact that Tk loosely uses
"unix" to mean "X11", which for Mac OS X is not the case.

The Tcl side of Mac OS X is clearly unix, but the same Tcl can in fact
be used with X11 (there is a native X Server in quite common use on
Mac OS X) and with the Aqua based Tk port.

In the end, however, the stubs generated for the generic, mac, win &
X11 parts of Tcl/Tk are the same, and there is just some extra logic
for the aqua part, so the result effects only Mac OS X code.

The generic code changes are quite small - a testament to the design
of the Tcl/Tk porting layers.

 1. We changed the ''configure.in'', ''Makefile.in'' and ''tcl.m4'' to
    handle building Tcl in a the Framework form that is common on Mac
    OS X.

 2. I added a bit of code (conditionalized to Mac OS X) to
    ''tclUnixInit.c'' (in the ''TclpSetVariables'' function) to
    support looking for script files embedded in the Mac OS X
    Framework bundle.  This fits the Mac OS X model better than
    putting files in ''/usr/local'' or such-like.

 3. I added a few more elements to the ''notifierProcPtr''.  For the
    aqua Tk, we need to swap the Unix notifier with our own, and so we
    needed more control over the notifier than was allowed.  This
    change has no effect if you don't use it, however.

 4. I added a function, ''TkGetFirstTextLayout'', which gets the run
    of text up the the first wrap.  I have to get this because the Mac
    OS X button control doesn't like a newline in the button text.  It
    is a private function, however, so it doesn't cause any
    incompatibilities.

 5. We had to change various places in the Tk script code and the
    demos where the implicit assumption was made that [[string equal
    $tcl_platform(platform) "unix"]] meant you were using X11.  To
    this end, we will add a ''windowingsystem'' subcommand to the
    ''tk'' command, and then using it to replace the cases where
    ''tcl_platform'' was being erroneously checked.  This command will
    return "x11" for an X11 server, "aqua" for the native Mac OS X
    window manager, "win32" for Windows, and "classic" for Classic
    MacOS.

~ Reference Implementation

The reference implementation is on the ''macosx-8-4-branch'' in the
SourceForge CVS repository.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
>

|









|







|
|




|

|



|
|








|



|
|


|

|




|






|
|
|
|
|




|

|


|


>

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

# TIP 108: Summary of Changes to Generic Tcl/Tk Code to Enable Mac OS X Port

	Author:         Jim Ingham <[email protected]>
	State:          Final
	Type:           Informative
	Vote:           No voting
	Created:        29-Aug-2002
	Post-History:   
-----

# Abstract

The submission of the changes to generic Tcl/Tk necessary for the Mac
OS X port was discussed on the Tcl Core mailing list.  In light of the
very minor changes to shared code involved, and to facilitate
including the port in the 8.4 release, it was decided that we would
not hold a formal vote.  This informational TIP is offered to
summarize the work done, however, and to maintain a more complete
record.

# What Changes are Required for the Mac OS X Port?

These fall into two parts: macosx only changes, and changes that
effect generic code.

The Mac OS X-only changes again fall into two parts.  On the one hand,
we introduced new macosx directories to the Tcl and Tk trees, at the
same level as the win, unix and mac directories.  At present, the
_tcl/macosx_ directory only contains one _.c_ file and a project
file.  The _tk/macosx_ directory is much more substantial.  This set
of changes manifestly only effects this port, and since something is
better than nothing, should be uncontroversial.

The other Mac OS X-only part is the addition of Mac OS X specific
elements to the _.decls_ files.  This should also be
uncontroversial, though I had to add some slightly non-trivial code to
the _genStubs.tcl_ file to handle the fact that Tk loosely uses
"unix" to mean "X11", which for Mac OS X is not the case.

The Tcl side of Mac OS X is clearly unix, but the same Tcl can in fact
be used with X11 \(there is a native X Server in quite common use on
Mac OS X\) and with the Aqua based Tk port.

In the end, however, the stubs generated for the generic, mac, win &
X11 parts of Tcl/Tk are the same, and there is just some extra logic
for the aqua part, so the result effects only Mac OS X code.

The generic code changes are quite small - a testament to the design
of the Tcl/Tk porting layers.

 1. We changed the _configure.in_, _Makefile.in_ and _tcl.m4_ to
    handle building Tcl in a the Framework form that is common on Mac
    OS X.

 2. I added a bit of code \(conditionalized to Mac OS X\) to
    _tclUnixInit.c_ \(in the _TclpSetVariables_ function\) to
    support looking for script files embedded in the Mac OS X
    Framework bundle.  This fits the Mac OS X model better than
    putting files in _/usr/local_ or such-like.

 3. I added a few more elements to the _notifierProcPtr_.  For the
    aqua Tk, we need to swap the Unix notifier with our own, and so we
    needed more control over the notifier than was allowed.  This
    change has no effect if you don't use it, however.

 4. I added a function, _TkGetFirstTextLayout_, which gets the run
    of text up the the first wrap.  I have to get this because the Mac
    OS X button control doesn't like a newline in the button text.  It
    is a private function, however, so it doesn't cause any
    incompatibilities.

 5. We had to change various places in the Tk script code and the
    demos where the implicit assumption was made that [string equal
    $tcl\_platform\(platform\) "unix"] meant you were using X11.  To
    this end, we will add a _windowingsystem_ subcommand to the
    _tk_ command, and then using it to replace the cases where
    _tcl\_platform_ was being erroneously checked.  This command will
    return "x11" for an X11 server, "aqua" for the native Mac OS X
    window manager, "win32" for Windows, and "classic" for Classic
    MacOS.

# Reference Implementation

The reference implementation is on the _macosx-8-4-branch_ in the
SourceForge CVS repository.

# Copyright

This document has been placed in the public domain.

Name change from tip/109.tip to tip/109.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

TIP:		109
Title:		New Look for Checkbutton and Radiobutton on Unix
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Post-History:	
Version:	$Revision: 1.4 $
Author:		Brian Griffin <[email protected]>
Created:	01-Oct-2002


~ Abstract

This TIP proposes changing the look of the Tk checkbutton and
radiobutton widgets on Unix to more closely match the Windows
counterparts.

~ Rationale

The current visual aspect of the Unix version checkbutton and
radiobutton has proved to be confusing to users.  The distinction
between selected (On) and unselected (Off) states are not visually
different enough to clearly identify one from another.  Indeed, in the
rare case where only one checkbutton is present, one cannot tell for
certain if the state is On or Off.  With a check or dot mark icon
(dependent on the type of widget) displayed in the Windows version,
there is no question about the state of the widget.

~ Proposed Changes

The checkbutton shall (when the indicator is turned on) display an
check-mark or other distinguishing icon/symbol that clearly indicates
an On state.  The Off state will be displayed with an empty box.  The
state values will ''not'' be indicated by changing relief or
background color.

The radiobutton shall (when the indicator is turned on) display an dot
mark or other distinguishing icon/symbol that clearly indicates a
selected or On state.  The unselected or Off state shall be displayed
with an empty diamond.  The state values will ''not'' be indicated by
changing relief or background color.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
>

|





|



|



|


|

|


|


|


|


|


>

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

# TIP 109: New Look for Checkbutton and Radiobutton on Unix
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Post-History:	

	Author:		Brian Griffin <[email protected]>
	Created:	01-Oct-2002
-----

# Abstract

This TIP proposes changing the look of the Tk checkbutton and
radiobutton widgets on Unix to more closely match the Windows
counterparts.

# Rationale

The current visual aspect of the Unix version checkbutton and
radiobutton has proved to be confusing to users.  The distinction
between selected \(On\) and unselected \(Off\) states are not visually
different enough to clearly identify one from another.  Indeed, in the
rare case where only one checkbutton is present, one cannot tell for
certain if the state is On or Off.  With a check or dot mark icon
\(dependent on the type of widget\) displayed in the Windows version,
there is no question about the state of the widget.

# Proposed Changes

The checkbutton shall \(when the indicator is turned on\) display an
check-mark or other distinguishing icon/symbol that clearly indicates
an On state.  The Off state will be displayed with an empty box.  The
state values will _not_ be indicated by changing relief or
background color.

The radiobutton shall \(when the indicator is turned on\) display an dot
mark or other distinguishing icon/symbol that clearly indicates a
selected or On state.  The unselected or Off state shall be displayed
with an empty diamond.  The state values will _not_ be indicated by
changing relief or background color.

# Copyright

This document has been placed in the public domain.

Name change from tip/11.tip to tip/11.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
136

137






138
139
140
141
142
143
144
145
146
147
148

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

214
215
216
217
218
219
220
221
222
223

224
225
226
227
228
229
230
231
232

233
234
235
236
237
238
239

240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261

262
263
264
265
266
267
268
269
270
271
272
273
274
275

276
277

278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323

324
325
326
327

328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368

369
370
371
372
373
374

375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409

410
411
412

413
414
415
416
417
418
419
420
421
422
423
424

425
426
427
428
429

430
431
432
433
434
435
436

437
438
439
440
441
442

443
444
445
446
447
448

449
450

451
452
453

454
455
456
457
458
459
460
461
462
463

464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520

521
522

523
524
525
526

527
528
529
530
531
532
533
534
535
536
537
538

539
540

TIP:            11
Title:          Tk Menubutton Enhancement: -compound option for menubutton
Version:        $Revision: 1.5 $
Author:         Todd Helfter <[email protected]>
State:          Final
Type:           Project
Tcl-Version:    8.4
Vote:           Done
Created:        16-Nov-2000
Post-History:


~ Abstract

This TIP describes how to change the menubutton in the Tk core to add
a -compound option to display both text and images.  This behavior
already exists in the button widget.

~ Rationale

In order to have a menubutton with both text and images, this change
is needed.  This change facilitates the use of an image for the
menubutton face with text on top.  Like the button widget, the
-compound option will accept these values: none, center, left, right,
top, bottom.

~ Reference Implementation

This TIP proposes to change the internals of the menubutton.

The changes necessary to accomplish this are:

   1. Extend the structure ''TkMenuButton'' in
      ''generic/tkMenubutton.h'' with a new field of type ''int'' to
      hold the value of the compound setting.

   2. Add an enumeration of valid -compound options in
      ''generic/tkMenubutton.h''.

   3. Modify ''generic/tkMenuButton.c'' and ''unix/tkUnixMenubu.c'' in
      such a way to process this new option.  Note: The windows port
      of Tk uses the ''unix/tkUnixMenubu.c'' file.  So this change is
      portable to both Unix and windows.

   4. Change ''tests/menubut.test'' so that the test for configure
      options checks for 33 instead of the current 32.

   5. Change ''doc/menubutton.n'' to show the new option under widget
      specific options.

~ Copyright

This document has been placed in the public domain.

~ Patch

|Index: doc/menubutton.n
|===================================================================
|RCS file: /cvsroot/tk/doc/menubutton.n,v
|retrieving revision 1.3
|diff -c -r1.3 menubutton.n
|*** menubutton.n	2000/08/25 06:58:32	1.3
|--- menubutton.n	2000/11/16 14:37:15
|***************
|*** 26,31 ****
|--- 26,39 ----
|  \-disabledforeground	\-padx
|  .SE
|  .SH "WIDGET-SPECIFIC OPTIONS"
|+ .OP \-compound compound Compound
|+ Specifies whether the menubutton should display both an image and text,
|+ and if so, where the image should be placed relative to the text.
|+ Valid values for this option are \fBbottom\fR, \fBcenter\fR,
|+ \fBleft\fR, \fBnone\fR, \fBright\fR and \fBtop\fR.  The default value
|+ is \fBnone\fR, meaning that the menubutton will display either an image or
|+ text, depending on the values of the \fB\-image\fR and \fB\-bitmap\fR
|+ options.
|  .VS
|  .OP \-direction direction Height
|  Specifies where the menu is going to be popup up. \fBabove\fR tries to
|Index: generic/tkMenubutton.c
|===================================================================
|RCS file: /cvsroot/tk/generic/tkMenubutton.c,v
|retrieving revision 1.4
|diff -c -r1.4 tkMenubutton.c
|*** tkMenubutton.c	1999/04/24 01:50:49	1.4
|--- tkMenubutton.c	2000/11/16 14:37:16
|***************
|*** 37,42 ****
|--- 37,51 ----
|  };
|  
|  /*
|+  * The following table defines the legal values for the -compound option.
|+  * It is used with the "enum compound" declaration in tkButton.h
|+  */
|+ 

|+ static char *compoundStrings[] = {
|+     "bottom", "center", "left", "none", "right", "top", (char *) NULL
|+ };
|+ 

|+ /*
|   * Information used for parsing configuration specs:
|   */
|  
|***************
|*** 113,118 ****
|--- 122,130 ----
|      {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
|	 DEF_MENUBUTTON_RELIEF, -1, Tk_Offset(TkMenuButton, relief), 
|	   0, 0, 0},
|+     {TK_OPTION_STRING_TABLE, "-compound", "compound", "Compound",
|+          DEF_BUTTON_COMPOUND, -1, Tk_Offset(TkMenuButton, compound), 0,
|+          (ClientData) compoundStrings, 0},
|      {TK_OPTION_STRING_TABLE, "-state", "state", "State",
|	 DEF_MENUBUTTON_STATE, -1, Tk_Offset(TkMenuButton, state),
|	 0, (ClientData) stateStrings, 0},
|Index: generic/tkMenubutton.h
|===================================================================
|RCS file: /cvsroot/tk/generic/tkMenubutton.h,v
|retrieving revision 1.5
|diff -c -r1.5 tkMenubutton.h
|*** tkMenubutton.h	1999/04/16 01:51:19	1.5
|--- tkMenubutton.h	2000/11/16 14:37:16
|***************
|*** 25,30 ****
|--- 25,39 ----
|  #endif
|  
|  /*
|+  * Legal values for the "compound" field of TkButton records.
|+  */
|+ 

|+ enum compound {
|+     COMPOUND_BOTTOM, COMPOUND_CENTER, COMPOUND_LEFT, COMPOUND_NONE,
|+         COMPOUND_RIGHT, COMPOUND_TOP
|+ };

|+ 






|+ /*
|   * Legal values for the "orient" field of TkMenubutton records.
|   */
|  
|***************
|*** 161,166 ****
|--- 170,179 ----
|      /*
|	* Miscellaneous information:
|	*/
|+ 

|+     int compound;               /* Value of -compound option; specifies whether
|+                                  * the button should show both an image and
|+                                  * text, and, if so, how. */
|  
|      enum direction direction;	/* Direction for where to pop the menu.
|				  * Valid directions are "above", "below",
|Index: tests/menubut.test
|===================================================================
|RCS file: /cvsroot/tk/tests/menubut.test,v
|retrieving revision 1.5
|diff -c -r1.5 menubut.test
|*** menubut.test	1999/04/21 21:53:29	1.5
|--- menubut.test	2000/11/16 14:37:18
|***************
|*** 138,144 ****
|  } {3}
|  test menubutton-3.7 {ButtonWidgetCmd procedure, "configure" option} {
|      llength [.mb configure]
|! } {32}
|  test menubutton-3.8 {ButtonWidgetCmd procedure, "configure" option} {
|      list [catch {.mb configure -gorp} msg] $msg
|  } {1 {unknown option "-gorp"}}
|--- 138,144 ----
|  } {3}
|  test menubutton-3.7 {ButtonWidgetCmd procedure, "configure" option} {
|      llength [.mb configure]
|! } {33}
|  test menubutton-3.8 {ButtonWidgetCmd procedure, "configure" option} {
|      list [catch {.mb configure -gorp} msg] $msg
|  } {1 {unknown option "-gorp"}}
|Index: unix/tkUnixMenubu.c
|===================================================================
|RCS file: /cvsroot/tk/unix/tkUnixMenubu.c,v
|retrieving revision 1.4
|diff -c -r1.4 tkUnixMenubu.c
|*** tkUnixMenubu.c	1999/09/21 06:43:01	1.4
|--- tkUnixMenubu.c	2000/11/16 14:37:18
|***************
|*** 75,83 ****
|      Pixmap pixmap;
|      int x = 0;			/* Initialization needed only to stop
|				  * compiler warning. */
|!     int y;
|      register Tk_Window tkwin = mbPtr->tkwin;
|!     int width, height;
|  
|      mbPtr->flags &= ~REDRAW_PENDING;
|      if ((mbPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
|--- 75,85 ----
|      Pixmap pixmap;
|      int x = 0;			/* Initialization needed only to stop
|				  * compiler warning. */
|!     int y = 0;
|      register Tk_Window tkwin = mbPtr->tkwin;
|!     int width, height, fullWidth, fullHeight;
|!     int imageXOffset, imageYOffset, textXOffset, textYOffset;
|!     int haveImage = 0, haveText = 0;
|  
|      mbPtr->flags &= ~REDRAW_PENDING;
|      if ((mbPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
|***************
|*** 96,101 ****
|--- 98,112 ----
|	 border = mbPtr->normalBorder;
|      }

|  
|+     if (mbPtr->image != None) {
|+ 	Tk_SizeOfImage(mbPtr->image, &width, &height);
|+ 	haveImage = 1;
|+     } else if (mbPtr->bitmap != None) {
|+ 	Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
|+ 	haveImage = 1;
|+     }
|+     haveText = (mbPtr->textWidth != 0 && mbPtr->textHeight != 0);
|+ 

|      /*
|	* In order to avoid screen flashes, this procedure redraws
|	* the menu button in a pixmap, then copies the pixmap to the
|***************
|*** 107,141 ****
|	     Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
|      Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin),
|	     Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
|- 

|-     /*
|-      * Display image or bitmap or text for button.
|-      */
|  
|!     if (mbPtr->image != None) {
|! 	Tk_SizeOfImage(mbPtr->image, &width, &height);
|! 

|! 	imageOrBitmap:
|! 	TkComputeAnchor(mbPtr->anchor, tkwin, 0, 0, 
|! 		width + mbPtr->indicatorWidth, height, &x, &y);
|! 	if (mbPtr->image != NULL) {
|! 	    Tk_RedrawImage(mbPtr->image, 0, 0, width, height, pixmap,
|! 		    x, y);
|! 	} else {
|! 	    XCopyPlane(mbPtr->display, mbPtr->bitmap, pixmap,
|! 		    gc, 0, 0, (unsigned) width, (unsigned) height, x, y, 1);
|! 	}
|!     } else if (mbPtr->bitmap != None) {
|! 	Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
|! 	goto imageOrBitmap;
|      } else {
|! 	TkComputeAnchor(mbPtr->anchor, tkwin, mbPtr->padX, mbPtr->padY,
|! 		mbPtr->textWidth + mbPtr->indicatorWidth,
|! 		mbPtr->textHeight, &x, &y);
|! 	Tk_DrawTextLayout(mbPtr->display, pixmap, gc, mbPtr->textLayout, x, y,
|! 		0, -1);
|! 	Tk_UnderlineTextLayout(mbPtr->display, pixmap, gc, mbPtr->textLayout,
|! 		x, y, mbPtr->underline);
|      }

|  
|      /*
|--- 118,223 ----
|	     Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
|      Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin),
|	     Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
|  
|!     imageXOffset = 0;
|!     imageYOffset = 0;
|!     textXOffset = 0;
|!     textYOffset = 0;
|!     fullWidth = 0;
|!     fullHeight = 0;
|! 

|!     if (mbPtr->compound != COMPOUND_NONE && haveImage && haveText) {
|! 

|!         switch ((enum compound) mbPtr->compound) {
|!             case COMPOUND_TOP:
|!             case COMPOUND_BOTTOM: {
|!                 /* Image is above or below text */
|!                 if (mbPtr->compound == COMPOUND_TOP) {
|!                     textYOffset = height + mbPtr->padY;
|!                 } else {
|!                     imageYOffset = mbPtr->textHeight + mbPtr->padY;
|!                 }
|!                 fullHeight = height + mbPtr->textHeight + mbPtr->padY;
|!                 fullWidth = (width > mbPtr->textWidth ? width :
|!                         mbPtr->textWidth);
|!                 textXOffset = (fullWidth - mbPtr->textWidth)/2;
|!                 imageXOffset = (fullWidth - width)/2;
|!                 break;
|!             }
|!             case COMPOUND_LEFT:
|!             case COMPOUND_RIGHT: {
|!                 /* Image is left or right of text */
|!                 if (mbPtr->compound == COMPOUND_LEFT) {
|!                     textXOffset = width + mbPtr->padX;
|!                 } else {
|!                     imageXOffset = mbPtr->textWidth + mbPtr->padX;
|!                 }
|!                 fullWidth = mbPtr->textWidth + mbPtr->padX + width;
|!                 fullHeight = (height > mbPtr->textHeight ? height :
|!                         mbPtr->textHeight);
|!                 textYOffset = (fullHeight - mbPtr->textHeight)/2;
|!                 imageYOffset = (fullHeight - height)/2;
|!                 break;
|!             }
|!             case COMPOUND_CENTER: {
|!                 /* Image and text are superimposed */
|!                 fullWidth = (width > mbPtr->textWidth ? width :
|!                         mbPtr->textWidth);
|!                 fullHeight = (height > mbPtr->textHeight ? height :
|!                         mbPtr->textHeight);
|!                 textXOffset = (fullWidth - mbPtr->textWidth)/2;
|!                 imageXOffset = (fullWidth - width)/2;
|!                 textYOffset = (fullHeight - mbPtr->textHeight)/2;
|!                 imageYOffset = (fullHeight - height)/2;
|!                 break;
|!             }
|!             case COMPOUND_NONE: {break;}
|!         }
|! 

|!         TkComputeAnchor(mbPtr->anchor, tkwin, 0, 0,
|!                 mbPtr->indicatorWidth + fullWidth, fullHeight,
|! 		&x, &y);
|! 

|!         if (mbPtr->image != NULL) {
|!             Tk_RedrawImage(mbPtr->image, 0, 0, width, height, pixmap,
|!                     x + imageXOffset, y + imageYOffset);
|!         }
|!         if (mbPtr->bitmap != None) {
|!             XCopyPlane(mbPtr->display, mbPtr->bitmap, pixmap,
|!                     gc, 0, 0, (unsigned) width, (unsigned) height, 
|! 		    x + imageXOffset, y + imageYOffset, 1);
|!         }
|!         if (haveText) {
|!             Tk_DrawTextLayout(mbPtr->display, pixmap, gc, mbPtr->textLayout, 
|! 		    x  + textXOffset, y + textYOffset ,
|!                     0, -1);
|!             Tk_UnderlineTextLayout(mbPtr->display, pixmap, gc, 
|! 		    mbPtr->textLayout, x + textXOffset, y + textYOffset ,
|! 		    mbPtr->underline);
|!         }
|      } else {
|!        if (mbPtr->image != NULL) {
|!            TkComputeAnchor(mbPtr->anchor, tkwin, 0, 0,
|!                    width + mbPtr->indicatorWidth, height, &x, &y);
|!            Tk_RedrawImage(mbPtr->image, 0, 0, width, height, pixmap,
|!                    x + imageXOffset, y + imageYOffset);
|!        } else if (mbPtr->bitmap != None) {
|!            TkComputeAnchor(mbPtr->anchor, tkwin, 0, 0,
|!                    width + mbPtr->indicatorWidth, height, &x, &y);
|!            XCopyPlane(mbPtr->display, mbPtr->bitmap, pixmap,
|!                    gc, 0, 0, (unsigned) width, (unsigned) height, 
|! 		   x + imageXOffset, y + imageYOffset, 1);
|!        } else {
|!            TkComputeAnchor(mbPtr->anchor, tkwin, mbPtr->padX, mbPtr->padY,
|!                    mbPtr->textWidth + mbPtr->indicatorWidth,
|!                    mbPtr->textHeight, &x, &y);
|!            Tk_DrawTextLayout(mbPtr->display, pixmap, gc, mbPtr->textLayout, 
|! 		   x  + textXOffset, y + textYOffset ,
|!                    0, -1);
|!            Tk_UnderlineTextLayout(mbPtr->display, pixmap, gc, 
|! 		   mbPtr->textLayout, x + textXOffset, y + textYOffset ,
|! 		   mbPtr->underline);
|!         }
|      }

|  
|      /*
|***************
|*** 252,305 ****
|      TkMenuButton *mbPtr;	/* Widget record for menu button. */
|  {

|      int width, height, mm, pixels;
|  
|      mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth;
|      if (mbPtr->image != None) {
|	 Tk_SizeOfImage(mbPtr->image, &width, &height);
|! 	if (mbPtr->width > 0) {
|! 	    width = mbPtr->width;
|! 	}
|! 	if (mbPtr->height > 0) {
|! 	    height = mbPtr->height;
|! 	}
|      } else if (mbPtr->bitmap != None) {
|	 Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
|! 	if (mbPtr->width > 0) {
|! 	    width = mbPtr->width;
|! 	}
|! 	if (mbPtr->height > 0) {
|! 	    height = mbPtr->height;
|! 	}
|!     } else {
|	 Tk_FreeTextLayout(mbPtr->textLayout);
|	 mbPtr->textLayout = Tk_ComputeTextLayout(mbPtr->tkfont, mbPtr->text,
|		 -1, mbPtr->wrapLength, mbPtr->justify, 0, &mbPtr->textWidth,
|		 &mbPtr->textHeight);
|! 	width = mbPtr->textWidth;
|! 	height = mbPtr->textHeight;
|! 	if (mbPtr->width > 0) {
|! 	    width = mbPtr->width * Tk_TextWidth(mbPtr->tkfont, "0", 1);
|! 	}
|! 	if (mbPtr->height > 0) {
|! 	    Tk_FontMetrics fm;
|  
|! 	    Tk_GetFontMetrics(mbPtr->tkfont, &fm);
|! 	    height = mbPtr->height * fm.linespace;
|	 }

|! 	width += 2*mbPtr->padX;
|! 	height += 2*mbPtr->padY;
|      }

|  
|      if (mbPtr->indicatorOn) {
|! 	mm = WidthMMOfScreen(Tk_Screen(mbPtr->tkwin));
|! 	pixels = WidthOfScreen(Tk_Screen(mbPtr->tkwin));
|! 	mbPtr->indicatorHeight= (INDICATOR_HEIGHT * pixels)/(10*mm);
|! 	mbPtr->indicatorWidth = (INDICATOR_WIDTH * pixels)/(10*mm)
|! 		+ 2*mbPtr->indicatorHeight;
|! 	width += mbPtr->indicatorWidth;
|      } else {
|! 	mbPtr->indicatorHeight = 0;
|! 	mbPtr->indicatorWidth = 0;
|      }

|  
|      Tk_GeometryRequest(mbPtr->tkwin, (int) (width + 2*mbPtr->inset),
|--- 334,446 ----
|      TkMenuButton *mbPtr;	/* Widget record for menu button. */
|  {

|      int width, height, mm, pixels;
|+     int  avgWidth, txtWidth, txtHeight;
|+     int haveImage = 0, haveText = 0;
|+     Tk_FontMetrics fm;
|  
|      mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth;
|+ 

|+     width = 0;
|+     height = 0;
|+     txtWidth = 0;
|+     txtHeight = 0;
|+     avgWidth = 0;
|+ 

|      if (mbPtr->image != None) {
|	 Tk_SizeOfImage(mbPtr->image, &width, &height);
|! 	haveImage = 1;
|      } else if (mbPtr->bitmap != None) {
|	 Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
|! 	haveImage = 1;

|!     }
|! 

|!     if (haveImage == 0 || mbPtr->compound != COMPOUND_NONE) {
|	 Tk_FreeTextLayout(mbPtr->textLayout);
|+ 

|	 mbPtr->textLayout = Tk_ComputeTextLayout(mbPtr->tkfont, mbPtr->text,
|		 -1, mbPtr->wrapLength, mbPtr->justify, 0, &mbPtr->textWidth,
|		 &mbPtr->textHeight);
|! 	txtWidth = mbPtr->textWidth;
|! 	txtHeight = mbPtr->textHeight;
|!         avgWidth = Tk_TextWidth(mbPtr->tkfont, "0", 1);
|!         Tk_GetFontMetrics(mbPtr->tkfont, &fm);
|!         haveText = (txtWidth != 0 && txtHeight != 0);
|!     }
|! 

|!     /*
|!      * If the menubutton is compound (ie, it shows both an image and text),
|!      * the new geometry is a combination of the image and text geometry.
|!      * We only honor the compound bit if the menubutton has both text and
|!      * an image, because otherwise it is not really a compound menubutton.
|!      */
|  
|!     if (mbPtr->compound != COMPOUND_NONE && haveImage && haveText) {
|!         switch ((enum compound) mbPtr->compound) {
|!             case COMPOUND_TOP:
|!             case COMPOUND_BOTTOM: {
|!                 /* Image is above or below text */
|!                 height += txtHeight + mbPtr->padY;
|!                 width = (width > txtWidth ? width : txtWidth);
|!                 break;
|!             }
|!             case COMPOUND_LEFT:
|!             case COMPOUND_RIGHT: {
|!                 /* Image is left or right of text */
|!                 width += txtWidth + mbPtr->padX;
|!                 height = (height > txtHeight ? height : txtHeight);
|!                 break;
|!             }
|!             case COMPOUND_CENTER: {
|!                 /* Image and text are superimposed */
|!                 width = (width > txtWidth ? width : txtWidth);
|!                 height = (height > txtHeight ? height : txtHeight);
|!                 break;
|!             }
|!             case COMPOUND_NONE: {break;}
|!         }
|!         if (mbPtr->width > 0) {
|!             width = mbPtr->width;
|!         }
|!         if (mbPtr->height > 0) {
|!             height = mbPtr->height;
|!         }
|!         width += 2*mbPtr->padX;
|!         height += 2*mbPtr->padY;
|!     } else {
|! 	if (haveImage) {
|!             if (mbPtr->width > 0) {
|!                 width = mbPtr->width;
|!             }
|!             if (mbPtr->height > 0) {
|!                 height = mbPtr->height;
|!             }
|! 	} else {
|! 	    width = txtWidth;
|! 	    height = txtHeight;
|!             if (mbPtr->width > 0) {
|!                 width = mbPtr->width * avgWidth;
|!             }
|!             if (mbPtr->height > 0) {
|!                 height = mbPtr->height * fm.linespace;
|!             }
|	 }

|!     }
|! 

|!     if (! haveImage) {
|!         width += 2*mbPtr->padX;
|!         height += 2*mbPtr->padY;
|      }

|  
|      if (mbPtr->indicatorOn) {
|!         mm = WidthMMOfScreen(Tk_Screen(mbPtr->tkwin));
|!         pixels = WidthOfScreen(Tk_Screen(mbPtr->tkwin));
|!         mbPtr->indicatorHeight= (INDICATOR_HEIGHT * pixels)/(10*mm);
|!         mbPtr->indicatorWidth = (INDICATOR_WIDTH * pixels)/(10*mm)
|!     	    + 2*mbPtr->indicatorHeight;
|!         width += mbPtr->indicatorWidth;
|      } else {
|!         mbPtr->indicatorHeight = 0;
|!         mbPtr->indicatorWidth = 0;
|      }

|  
|      Tk_GeometryRequest(mbPtr->tkwin, (int) (width + 2*mbPtr->inset),

<
|
<
|
|
|
|
|
|
|
>

|





|







|





|
|



|

|

|


|


|


|



|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
>
|
>
>
>
>
>
>
|
<
<
<
<
<
<
<
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
|
>
<
<
>
|
|
<
>
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
<
>
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
>

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
136
137
138
139
140
141
142
143
144







145
146

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

212
213
214
215
216
217
218
219
220
221

222
223
224
225
226
227
228
229
230

231
232
233
234
235
236
237

238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259

260
261
262
263
264
265
266
267
268
269
270
271
272
273

274
275

276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321

322
323
324
325

326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366

367
368
369
370
371
372

373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407

408
409
410

411
412
413
414
415
416
417
418
419
420
421
422

423
424
425
426
427

428
429
430
431
432
433
434

435
436
437
438
439
440

441
442
443
444
445
446
447
448


449
450
451

452
453
454
455
456
457
458
459
460
461

462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518

519
520

521
522
523
524

525
526
527
528
529
530
531
532
533
534
535
536

537
538
539
540

# TIP 11: Tk Menubutton Enhancement: -compound option for menubutton

	Author:         Todd Helfter <[email protected]>
	State:          Final
	Type:           Project
	Tcl-Version:    8.4
	Vote:           Done
	Created:        16-Nov-2000
	Post-History:
-----

# Abstract

This TIP describes how to change the menubutton in the Tk core to add
a -compound option to display both text and images.  This behavior
already exists in the button widget.

# Rationale

In order to have a menubutton with both text and images, this change
is needed.  This change facilitates the use of an image for the
menubutton face with text on top.  Like the button widget, the
-compound option will accept these values: none, center, left, right,
top, bottom.

# Reference Implementation

This TIP proposes to change the internals of the menubutton.

The changes necessary to accomplish this are:

   1. Extend the structure _TkMenuButton_ in
      _generic/tkMenubutton.h_ with a new field of type _int_ to
      hold the value of the compound setting.

   2. Add an enumeration of valid -compound options in
      _generic/tkMenubutton.h_.

   3. Modify _generic/tkMenuButton.c_ and _unix/tkUnixMenubu.c_ in
      such a way to process this new option.  Note: The windows port
      of Tk uses the _unix/tkUnixMenubu.c_ file.  So this change is
      portable to both Unix and windows.

   4. Change _tests/menubut.test_ so that the test for configure
      options checks for 33 instead of the current 32.

   5. Change _doc/menubutton.n_ to show the new option under widget
      specific options.

# Copyright

This document has been placed in the public domain.

# Patch

	Index: doc/menubutton.n
	===================================================================
	RCS file: /cvsroot/tk/doc/menubutton.n,v
	retrieving revision 1.3
	diff -c -r1.3 menubutton.n
	*** menubutton.n	2000/08/25 06:58:32	1.3
	--- menubutton.n	2000/11/16 14:37:15
	***************
	*** 26,31 ****
	--- 26,39 ----
	  \-disabledforeground	\-padx
	  .SE
	  .SH "WIDGET-SPECIFIC OPTIONS"
	+ .OP \-compound compound Compound
	+ Specifies whether the menubutton should display both an image and text,
	+ and if so, where the image should be placed relative to the text.
	+ Valid values for this option are \fBbottom\fR, \fBcenter\fR,
	+ \fBleft\fR, \fBnone\fR, \fBright\fR and \fBtop\fR.  The default value
	+ is \fBnone\fR, meaning that the menubutton will display either an image or
	+ text, depending on the values of the \fB\-image\fR and \fB\-bitmap\fR
	+ options.
	  .VS
	  .OP \-direction direction Height
	  Specifies where the menu is going to be popup up. \fBabove\fR tries to
	Index: generic/tkMenubutton.c
	===================================================================
	RCS file: /cvsroot/tk/generic/tkMenubutton.c,v
	retrieving revision 1.4
	diff -c -r1.4 tkMenubutton.c
	*** tkMenubutton.c	1999/04/24 01:50:49	1.4
	--- tkMenubutton.c	2000/11/16 14:37:16
	***************
	*** 37,42 ****
	--- 37,51 ----
	  };
	  
	  /*
	+  * The following table defines the legal values for the -compound option.
	+  * It is used with the "enum compound" declaration in tkButton.h
	+  */

	+ 
	+ static char *compoundStrings[] = {
	+     "bottom", "center", "left", "none", "right", "top", (char *) NULL
	+ };

	+ 
	+ /*
	   * Information used for parsing configuration specs:
	   */
	  
	***************
	*** 113,118 ****
	--- 122,130 ----
	      {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
		 DEF_MENUBUTTON_RELIEF, -1, Tk_Offset(TkMenuButton, relief), 
		   0, 0, 0},
	+     {TK_OPTION_STRING_TABLE, "-compound", "compound", "Compound",
	+          DEF_BUTTON_COMPOUND, -1, Tk_Offset(TkMenuButton, compound), 0,
	+          (ClientData) compoundStrings, 0},
	      {TK_OPTION_STRING_TABLE, "-state", "state", "State",
		 DEF_MENUBUTTON_STATE, -1, Tk_Offset(TkMenuButton, state),
		 0, (ClientData) stateStrings, 0},
	Index: generic/tkMenubutton.h
	===================================================================
	RCS file: /cvsroot/tk/generic/tkMenubutton.h,v
	retrieving revision 1.5
	diff -c -r1.5 tkMenubutton.h
	*** tkMenubutton.h	1999/04/16 01:51:19	1.5
	--- tkMenubutton.h	2000/11/16 14:37:16
	***************
	*** 25,30 ****
	--- 25,39 ----
	  #endif
	  
	  /*
	+  * Legal values for the "compound" field of TkButton records.
	+  */

	+ 
	+ enum compound {
	+     COMPOUND_BOTTOM, COMPOUND_CENTER, COMPOUND_LEFT, COMPOUND_NONE,
	+         COMPOUND_RIGHT, COMPOUND_TOP
	+ };
	+ 
	+ /*
	   * Legal values for the "orient" field of TkMenubutton records.
	   */
	  
	***************
	*** 161,166 ****
	--- 170,179 ----
	      /*







		* Miscellaneous information:
		*/

	+ 
	+     int compound;               /* Value of -compound option; specifies whether
	+                                  * the button should show both an image and
	+                                  * text, and, if so, how. */
	  
	      enum direction direction;	/* Direction for where to pop the menu.
					  * Valid directions are "above", "below",
	Index: tests/menubut.test
	===================================================================
	RCS file: /cvsroot/tk/tests/menubut.test,v
	retrieving revision 1.5
	diff -c -r1.5 menubut.test
	*** menubut.test	1999/04/21 21:53:29	1.5
	--- menubut.test	2000/11/16 14:37:18
	***************
	*** 138,144 ****
	  } {3}
	  test menubutton-3.7 {ButtonWidgetCmd procedure, "configure" option} {
	      llength [.mb configure]
	! } {32}
	  test menubutton-3.8 {ButtonWidgetCmd procedure, "configure" option} {
	      list [catch {.mb configure -gorp} msg] $msg
	  } {1 {unknown option "-gorp"}}
	--- 138,144 ----
	  } {3}
	  test menubutton-3.7 {ButtonWidgetCmd procedure, "configure" option} {
	      llength [.mb configure]
	! } {33}
	  test menubutton-3.8 {ButtonWidgetCmd procedure, "configure" option} {
	      list [catch {.mb configure -gorp} msg] $msg
	  } {1 {unknown option "-gorp"}}
	Index: unix/tkUnixMenubu.c
	===================================================================
	RCS file: /cvsroot/tk/unix/tkUnixMenubu.c,v
	retrieving revision 1.4
	diff -c -r1.4 tkUnixMenubu.c
	*** tkUnixMenubu.c	1999/09/21 06:43:01	1.4
	--- tkUnixMenubu.c	2000/11/16 14:37:18
	***************
	*** 75,83 ****
	      Pixmap pixmap;
	      int x = 0;			/* Initialization needed only to stop
					  * compiler warning. */
	!     int y;
	      register Tk_Window tkwin = mbPtr->tkwin;
	!     int width, height;
	  
	      mbPtr->flags &= ~REDRAW_PENDING;
	      if ((mbPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
	--- 75,85 ----
	      Pixmap pixmap;
	      int x = 0;			/* Initialization needed only to stop
					  * compiler warning. */
	!     int y = 0;
	      register Tk_Window tkwin = mbPtr->tkwin;
	!     int width, height, fullWidth, fullHeight;
	!     int imageXOffset, imageYOffset, textXOffset, textYOffset;
	!     int haveImage = 0, haveText = 0;
	  
	      mbPtr->flags &= ~REDRAW_PENDING;
	      if ((mbPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
	***************
	*** 96,101 ****
	--- 98,112 ----
		 border = mbPtr->normalBorder;

	      }
	  
	+     if (mbPtr->image != None) {
	+ 	Tk_SizeOfImage(mbPtr->image, &width, &height);
	+ 	haveImage = 1;
	+     } else if (mbPtr->bitmap != None) {
	+ 	Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
	+ 	haveImage = 1;
	+     }
	+     haveText = (mbPtr->textWidth != 0 && mbPtr->textHeight != 0);

	+ 
	      /*
		* In order to avoid screen flashes, this procedure redraws
		* the menu button in a pixmap, then copies the pixmap to the
	***************
	*** 107,141 ****
		     Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
	      Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin),
		     Tk_Height(tkwin), 0, TK_RELIEF_FLAT);

	- 
	-     /*
	-      * Display image or bitmap or text for button.
	-      */
	  
	!     if (mbPtr->image != None) {
	! 	Tk_SizeOfImage(mbPtr->image, &width, &height);

	! 
	! 	imageOrBitmap:
	! 	TkComputeAnchor(mbPtr->anchor, tkwin, 0, 0, 
	! 		width + mbPtr->indicatorWidth, height, &x, &y);
	! 	if (mbPtr->image != NULL) {
	! 	    Tk_RedrawImage(mbPtr->image, 0, 0, width, height, pixmap,
	! 		    x, y);
	! 	} else {
	! 	    XCopyPlane(mbPtr->display, mbPtr->bitmap, pixmap,
	! 		    gc, 0, 0, (unsigned) width, (unsigned) height, x, y, 1);
	! 	}
	!     } else if (mbPtr->bitmap != None) {
	! 	Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
	! 	goto imageOrBitmap;
	      } else {
	! 	TkComputeAnchor(mbPtr->anchor, tkwin, mbPtr->padX, mbPtr->padY,
	! 		mbPtr->textWidth + mbPtr->indicatorWidth,
	! 		mbPtr->textHeight, &x, &y);
	! 	Tk_DrawTextLayout(mbPtr->display, pixmap, gc, mbPtr->textLayout, x, y,
	! 		0, -1);
	! 	Tk_UnderlineTextLayout(mbPtr->display, pixmap, gc, mbPtr->textLayout,
	! 		x, y, mbPtr->underline);

	      }
	  
	      /*
	--- 118,223 ----
		     Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
	      Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin),
		     Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
	  
	!     imageXOffset = 0;
	!     imageYOffset = 0;
	!     textXOffset = 0;
	!     textYOffset = 0;
	!     fullWidth = 0;
	!     fullHeight = 0;

	! 
	!     if (mbPtr->compound != COMPOUND_NONE && haveImage && haveText) {

	! 
	!         switch ((enum compound) mbPtr->compound) {
	!             case COMPOUND_TOP:
	!             case COMPOUND_BOTTOM: {
	!                 /* Image is above or below text */
	!                 if (mbPtr->compound == COMPOUND_TOP) {
	!                     textYOffset = height + mbPtr->padY;
	!                 } else {
	!                     imageYOffset = mbPtr->textHeight + mbPtr->padY;
	!                 }
	!                 fullHeight = height + mbPtr->textHeight + mbPtr->padY;
	!                 fullWidth = (width > mbPtr->textWidth ? width :
	!                         mbPtr->textWidth);
	!                 textXOffset = (fullWidth - mbPtr->textWidth)/2;
	!                 imageXOffset = (fullWidth - width)/2;
	!                 break;
	!             }
	!             case COMPOUND_LEFT:
	!             case COMPOUND_RIGHT: {
	!                 /* Image is left or right of text */
	!                 if (mbPtr->compound == COMPOUND_LEFT) {
	!                     textXOffset = width + mbPtr->padX;
	!                 } else {
	!                     imageXOffset = mbPtr->textWidth + mbPtr->padX;
	!                 }
	!                 fullWidth = mbPtr->textWidth + mbPtr->padX + width;
	!                 fullHeight = (height > mbPtr->textHeight ? height :
	!                         mbPtr->textHeight);
	!                 textYOffset = (fullHeight - mbPtr->textHeight)/2;
	!                 imageYOffset = (fullHeight - height)/2;
	!                 break;
	!             }
	!             case COMPOUND_CENTER: {
	!                 /* Image and text are superimposed */
	!                 fullWidth = (width > mbPtr->textWidth ? width :
	!                         mbPtr->textWidth);
	!                 fullHeight = (height > mbPtr->textHeight ? height :
	!                         mbPtr->textHeight);
	!                 textXOffset = (fullWidth - mbPtr->textWidth)/2;
	!                 imageXOffset = (fullWidth - width)/2;
	!                 textYOffset = (fullHeight - mbPtr->textHeight)/2;
	!                 imageYOffset = (fullHeight - height)/2;
	!                 break;
	!             }
	!             case COMPOUND_NONE: {break;}
	!         }

	! 
	!         TkComputeAnchor(mbPtr->anchor, tkwin, 0, 0,
	!                 mbPtr->indicatorWidth + fullWidth, fullHeight,
	! 		&x, &y);

	! 
	!         if (mbPtr->image != NULL) {
	!             Tk_RedrawImage(mbPtr->image, 0, 0, width, height, pixmap,
	!                     x + imageXOffset, y + imageYOffset);
	!         }
	!         if (mbPtr->bitmap != None) {
	!             XCopyPlane(mbPtr->display, mbPtr->bitmap, pixmap,
	!                     gc, 0, 0, (unsigned) width, (unsigned) height, 
	! 		    x + imageXOffset, y + imageYOffset, 1);
	!         }
	!         if (haveText) {
	!             Tk_DrawTextLayout(mbPtr->display, pixmap, gc, mbPtr->textLayout, 
	! 		    x  + textXOffset, y + textYOffset ,
	!                     0, -1);
	!             Tk_UnderlineTextLayout(mbPtr->display, pixmap, gc, 
	! 		    mbPtr->textLayout, x + textXOffset, y + textYOffset ,
	! 		    mbPtr->underline);
	!         }
	      } else {
	!        if (mbPtr->image != NULL) {
	!            TkComputeAnchor(mbPtr->anchor, tkwin, 0, 0,
	!                    width + mbPtr->indicatorWidth, height, &x, &y);
	!            Tk_RedrawImage(mbPtr->image, 0, 0, width, height, pixmap,
	!                    x + imageXOffset, y + imageYOffset);
	!        } else if (mbPtr->bitmap != None) {
	!            TkComputeAnchor(mbPtr->anchor, tkwin, 0, 0,
	!                    width + mbPtr->indicatorWidth, height, &x, &y);
	!            XCopyPlane(mbPtr->display, mbPtr->bitmap, pixmap,
	!                    gc, 0, 0, (unsigned) width, (unsigned) height, 
	! 		   x + imageXOffset, y + imageYOffset, 1);
	!        } else {
	!            TkComputeAnchor(mbPtr->anchor, tkwin, mbPtr->padX, mbPtr->padY,
	!                    mbPtr->textWidth + mbPtr->indicatorWidth,
	!                    mbPtr->textHeight, &x, &y);
	!            Tk_DrawTextLayout(mbPtr->display, pixmap, gc, mbPtr->textLayout, 
	! 		   x  + textXOffset, y + textYOffset ,
	!                    0, -1);
	!            Tk_UnderlineTextLayout(mbPtr->display, pixmap, gc, 
	! 		   mbPtr->textLayout, x + textXOffset, y + textYOffset ,
	! 		   mbPtr->underline);
	!         }

	      }
	  
	      /*
	***************
	*** 252,305 ****
	      TkMenuButton *mbPtr;	/* Widget record for menu button. */

	  {
	      int width, height, mm, pixels;
	  
	      mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth;
	      if (mbPtr->image != None) {
		 Tk_SizeOfImage(mbPtr->image, &width, &height);
	! 	if (mbPtr->width > 0) {
	! 	    width = mbPtr->width;
	! 	}
	! 	if (mbPtr->height > 0) {
	! 	    height = mbPtr->height;
	! 	}
	      } else if (mbPtr->bitmap != None) {
		 Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
	! 	if (mbPtr->width > 0) {
	! 	    width = mbPtr->width;
	! 	}
	! 	if (mbPtr->height > 0) {
	! 	    height = mbPtr->height;
	! 	}
	!     } else {
		 Tk_FreeTextLayout(mbPtr->textLayout);
		 mbPtr->textLayout = Tk_ComputeTextLayout(mbPtr->tkfont, mbPtr->text,
			 -1, mbPtr->wrapLength, mbPtr->justify, 0, &mbPtr->textWidth,
			 &mbPtr->textHeight);
	! 	width = mbPtr->textWidth;
	! 	height = mbPtr->textHeight;
	! 	if (mbPtr->width > 0) {
	! 	    width = mbPtr->width * Tk_TextWidth(mbPtr->tkfont, "0", 1);
	! 	}
	! 	if (mbPtr->height > 0) {
	! 	    Tk_FontMetrics fm;
	  
	! 	    Tk_GetFontMetrics(mbPtr->tkfont, &fm);
	! 	    height = mbPtr->height * fm.linespace;

		 }
	! 	width += 2*mbPtr->padX;
	! 	height += 2*mbPtr->padY;

	      }
	  
	      if (mbPtr->indicatorOn) {
	! 	mm = WidthMMOfScreen(Tk_Screen(mbPtr->tkwin));
	! 	pixels = WidthOfScreen(Tk_Screen(mbPtr->tkwin));
	! 	mbPtr->indicatorHeight= (INDICATOR_HEIGHT * pixels)/(10*mm);
	! 	mbPtr->indicatorWidth = (INDICATOR_WIDTH * pixels)/(10*mm)
	! 		+ 2*mbPtr->indicatorHeight;
	! 	width += mbPtr->indicatorWidth;
	      } else {
	! 	mbPtr->indicatorHeight = 0;
	! 	mbPtr->indicatorWidth = 0;

	      }
	  
	      Tk_GeometryRequest(mbPtr->tkwin, (int) (width + 2*mbPtr->inset),
	--- 334,446 ----
	      TkMenuButton *mbPtr;	/* Widget record for menu button. */

	  {
	      int width, height, mm, pixels;
	+     int  avgWidth, txtWidth, txtHeight;
	+     int haveImage = 0, haveText = 0;
	+     Tk_FontMetrics fm;
	  
	      mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth;

	+ 
	+     width = 0;
	+     height = 0;
	+     txtWidth = 0;
	+     txtHeight = 0;
	+     avgWidth = 0;

	+ 
	      if (mbPtr->image != None) {
		 Tk_SizeOfImage(mbPtr->image, &width, &height);
	! 	haveImage = 1;
	      } else if (mbPtr->bitmap != None) {
		 Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
	! 	haveImage = 1;
	!     }


	! 
	!     if (haveImage == 0 || mbPtr->compound != COMPOUND_NONE) {
		 Tk_FreeTextLayout(mbPtr->textLayout);

	+ 
		 mbPtr->textLayout = Tk_ComputeTextLayout(mbPtr->tkfont, mbPtr->text,
			 -1, mbPtr->wrapLength, mbPtr->justify, 0, &mbPtr->textWidth,
			 &mbPtr->textHeight);
	! 	txtWidth = mbPtr->textWidth;
	! 	txtHeight = mbPtr->textHeight;
	!         avgWidth = Tk_TextWidth(mbPtr->tkfont, "0", 1);
	!         Tk_GetFontMetrics(mbPtr->tkfont, &fm);
	!         haveText = (txtWidth != 0 && txtHeight != 0);
	!     }

	! 
	!     /*
	!      * If the menubutton is compound (ie, it shows both an image and text),
	!      * the new geometry is a combination of the image and text geometry.
	!      * We only honor the compound bit if the menubutton has both text and
	!      * an image, because otherwise it is not really a compound menubutton.
	!      */
	  
	!     if (mbPtr->compound != COMPOUND_NONE && haveImage && haveText) {
	!         switch ((enum compound) mbPtr->compound) {
	!             case COMPOUND_TOP:
	!             case COMPOUND_BOTTOM: {
	!                 /* Image is above or below text */
	!                 height += txtHeight + mbPtr->padY;
	!                 width = (width > txtWidth ? width : txtWidth);
	!                 break;
	!             }
	!             case COMPOUND_LEFT:
	!             case COMPOUND_RIGHT: {
	!                 /* Image is left or right of text */
	!                 width += txtWidth + mbPtr->padX;
	!                 height = (height > txtHeight ? height : txtHeight);
	!                 break;
	!             }
	!             case COMPOUND_CENTER: {
	!                 /* Image and text are superimposed */
	!                 width = (width > txtWidth ? width : txtWidth);
	!                 height = (height > txtHeight ? height : txtHeight);
	!                 break;
	!             }
	!             case COMPOUND_NONE: {break;}
	!         }
	!         if (mbPtr->width > 0) {
	!             width = mbPtr->width;
	!         }
	!         if (mbPtr->height > 0) {
	!             height = mbPtr->height;
	!         }
	!         width += 2*mbPtr->padX;
	!         height += 2*mbPtr->padY;
	!     } else {
	! 	if (haveImage) {
	!             if (mbPtr->width > 0) {
	!                 width = mbPtr->width;
	!             }
	!             if (mbPtr->height > 0) {
	!                 height = mbPtr->height;
	!             }
	! 	} else {
	! 	    width = txtWidth;
	! 	    height = txtHeight;
	!             if (mbPtr->width > 0) {
	!                 width = mbPtr->width * avgWidth;
	!             }
	!             if (mbPtr->height > 0) {
	!                 height = mbPtr->height * fm.linespace;
	!             }

		 }
	!     }

	! 
	!     if (! haveImage) {
	!         width += 2*mbPtr->padX;
	!         height += 2*mbPtr->padY;

	      }
	  
	      if (mbPtr->indicatorOn) {
	!         mm = WidthMMOfScreen(Tk_Screen(mbPtr->tkwin));
	!         pixels = WidthOfScreen(Tk_Screen(mbPtr->tkwin));
	!         mbPtr->indicatorHeight= (INDICATOR_HEIGHT * pixels)/(10*mm);
	!         mbPtr->indicatorWidth = (INDICATOR_WIDTH * pixels)/(10*mm)
	!     	    + 2*mbPtr->indicatorHeight;
	!         width += mbPtr->indicatorWidth;
	      } else {
	!         mbPtr->indicatorHeight = 0;
	!         mbPtr->indicatorWidth = 0;

	      }
	  
	      Tk_GeometryRequest(mbPtr->tkwin, (int) (width + 2*mbPtr->inset),

Name change from tip/110.tip to tip/110.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

TIP:            110
Title:          Add a Tristate Mode to the Checkbutton and Radiobutton
Version:        $Revision: 1.12 $
Author:         Brian Griffin <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        01-Oct-2002
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes adding a third value (tristate) to the checkbutton
and radiobutton widgets and corresponding display.

~ Rationale

In order to meet more demanding requirements of todays complex
graphical user interfaces, it would help add to the functionality of
the basic checkbutton and radiobutton widgets. To support using
checkbuttons and radiobuttons along with multiple selection, it is
necessary for these buttons to be able to display a third state,
i.e., both On and Off.  This indicates the situation where a property
has a particular value for some members of a selection set, but
not others.

~ Proposed Change

The change would add a third "tristate" value to current On Off values
of the checkbutton and radiobutton widgets.  The widget would then
display the check/dot mark (as appropriate) along with a "grayed"
background, for example.  When the checkbutton or radiobutton is 
invoked (i.e. clicked on) it would behave exactly as it does currently, 
setting the variable to the On value.

There is a concern that the Unix version of these widgets do not have
a sufficiently different appearance when in the tristate state
compared with the On and Off states.  This issue is addressed in
[109].

~ Propsal Specifics

   1. Identify a third, platform specific, presentation (e.g. check
      with grayed background) to represent the tristate value,

   1. Add the option "-tristatevalue" to specify the match value
      only. The default value of this option will be "{}",

   1. Change the behavior to display the indeterminate or tristate
      presentation when the associated variable's value matches the
      -tristatevalue, and

   1. Add the option "-tristateimage" to specify an image to display
      (in place of the image option) when the checkbutton or
      radiobutton has the tristate value (as defined above.)

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|


|










|



|

|





|

|

|
|


|






|
|

|


>

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

# TIP 110: Add a Tristate Mode to the Checkbutton and Radiobutton

	Author:         Brian Griffin <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        01-Oct-2002
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes adding a third value \(tristate\) to the checkbutton
and radiobutton widgets and corresponding display.

# Rationale

In order to meet more demanding requirements of todays complex
graphical user interfaces, it would help add to the functionality of
the basic checkbutton and radiobutton widgets. To support using
checkbuttons and radiobuttons along with multiple selection, it is
necessary for these buttons to be able to display a third state,
i.e., both On and Off.  This indicates the situation where a property
has a particular value for some members of a selection set, but
not others.

# Proposed Change

The change would add a third "tristate" value to current On Off values
of the checkbutton and radiobutton widgets.  The widget would then
display the check/dot mark \(as appropriate\) along with a "grayed"
background, for example.  When the checkbutton or radiobutton is 
invoked \(i.e. clicked on\) it would behave exactly as it does currently, 
setting the variable to the On value.

There is a concern that the Unix version of these widgets do not have
a sufficiently different appearance when in the tristate state
compared with the On and Off states.  This issue is addressed in
[[109]](109.md).

# Propsal Specifics

   1. Identify a third, platform specific, presentation \(e.g. check
      with grayed background\) to represent the tristate value,

   1. Add the option "-tristatevalue" to specify the match value
      only. The default value of this option will be "\{\}",

   1. Change the behavior to display the indeterminate or tristate
      presentation when the associated variable's value matches the
      -tristatevalue, and

   1. Add the option "-tristateimage" to specify an image to display
      \(in place of the image option\) when the checkbutton or
      radiobutton has the tristate value \(as defined above.\)

# Copyright

This document has been placed in the public domain.

Name change from tip/111.tip to tip/111.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442

443
444
445
446
447
448

449
450
451
452
453

454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478

TIP:            111
Title:          Dictionary Values and Manipulators
Version:        $Revision: 1.12 $
Author:         Donal K. Fellows <[email protected]>
Author:         David S. Cargo <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        05-Oct-2002
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes adding a standard value format (and supporting
commands) to Tcl that implements a value-to-value mapping, just as
Tcl's list values can be regarded as implementing a number-to-value
mapping.

~ Rationale

What is a dictionary?  It is a translation from arbitrary values to
arbitrary values, often also known as an associative map.  Many
computer languages, especially higher-level ones, have them as part of
the language or the standard library.  It would be nice to have them
in Tcl too.

Now, I realise that Tcl already contains arrays which provide
dictionary functionality, but they are not quite the same thing.
Tcl's arrays are collections of variables indexable by name, and not
collections of values.  This has some far-reaching implications; it is
possible to set traces on individual elements of the array, but it is
not possible to pass the array by value.  However, one of the main
concerns is the sheer cost of arrays in terms of memory space; aside
from the hash table used as the core of the implementation (and the
representations of the keys and values, of course) there is a
substantial overhead for each array to support traces on the array as
a whole, plus a similar overhead ''per element'' that stems from the
fact that elements are variables in their own right.  By contrast, a
dictionary value should be a lot more frugal.

~ Value Syntax and Semantics

Naturally, it is desirable for dictionary values to have
human-readable forms that are similar to those that currently exist.
I propose using ''key value key value ...'' form with list-style
quoting for keys and values that contain characters that are
significant to Tcl, which should be immediately familiar to users of
the '''array get''' and '''array set''' commands.  No special
interpretation will be placed on the amount of whitespace separating
keys and values, just as with lists (indeed, any list with an even
number of elements can be regarded as a dictionary.)  For example, the
following value represents a mapping from selected languages to a
possible program to invoke to compile them:

|	C gcc C++ g++ FORTRAN f77 Java javac

Empty dictionaries are those that contain no mappings from keys to
values.  Any representation of an empty list will also be a
representation of an empty dictionary.  There is no upper bound on the
number of items that a dictionary may hold.

It should be specially noted that dictionary values have copy-on-write
semantics just like lists.  This means that if I hand a dictionary
value into a procedure as an argument, and that procedure updates the
variable containing that value, the value as seen by the caller will
not have changed.  This is in complete contrast with arrays which
cannot (currently) be passed by value other than through using '''array
get''' to convert the array to a list form and '''array set''' to convert
back again.

This specification does not state what order the keys and values are
listed in.  That depends on the implementation.

~ Command Syntax and Semantics

I propose that all operations that work with dictionary values (where
not done through adaptations of existing commands) will go through the
'''dict''' command.  The alternatives are "array" which is already in
use, "dictionary" which is rather long for what I believe will be a
fairly commonly used command, "alist" (association list) which is
probably too easy to confuse with existing commands, and "map" which
is probably better reserved for future use as something for applying
an operation to a list (or other collection of values), "hash" (which
is perhaps too common), and "table" (which is used for this type of
data structure in the Icon programming language).

Most subcommands operate on either a dictionary value (''exists'',
''for'', ''get'', ''info'', ''keys'', ''remove'', ''replace'',
''size'', and ''values''), or on a variable containing a dictionary
value (''append'', ''incr'', ''lappend'', ''set'', and ''unset'').

Proposed subcommands:

 dict create:	Make a dictionary.

 > '''dict create''' ?''key1 value1 key2 value2 ...''?

 > This will create a new dictionary from the given keys and values
   and return it as the result.  The command will take an even number
   of arbitrary strings (or other objects, naturally) and will use the
   first, third, fifth, etc. as keys and the second, fourth, sixth,
   etc. as values.  From the point of view of string representations,
   this command will behave the same as the '''list''' command with an
   even number of arguments.  There is no restriction on the possible
   representations of keys or values.  It is legal to call this
   command with no arguments at all, which creates an empty
   dictionary.

 dict get:	Get value for given key.

 > '''dict get''' ''dictionaryValue'' ?''key ...''?

 > Given a dictionary value (first argument) and a key (second
   argument), this will retrieve the value for that key.  Where
   several keys are supplied, the behaviour of the command shall be as
   if the result of '''dict get''' ''dictVal key'' was passed as the first
   argument to '''dict get'' with the remaining arguments as second
   (and possibly subsequent) arguments.  This facilitates lookups in
   nested dictionaries.  For example, the following two commands are
   equivalent:

|	dict get $dict foo bar spong
|	dict get [dict get [dict get $dict foo] bar] spong

 > If no keys are provided, dict would return a list containing pairs
   of elements in a manner similar to '''array get'''.  That is, the
   first element of each pair would be the key and the second element
   would be the value for that key.

 > It is an error to attempt to retrieve a value for a key that is not
   present in the dictionary.

 dict replace:	Create a new dictionary that is a copy of an old one
		except with some values different or some extra
		key/value pairs added.

 > '''dict replace''' ''dictionaryValue'' ?''key value ...''?

 > This is very much the analogue of '''lreplace''', taking a dictionary
   value as its first argument and then a list of key/value pairs.
   The result of the command is a new dictionary value that is a copy
   of the supplied dictionary other than that whenever a key is one of
   those supplied to this command, the returned dictionary will map
   that key to the associated value.  It is legal for this command to
   be called with no key/value pairs, but illegal for this command to
   be called with a key but no value.

 dict remove:	Create a new dictionary that is a copy of an old one
		except without the key/value mappings whose keys are
		listed.

 > '''dict remove''' ''dictionaryValue'' ?''key key ...''?

 > This operation does what '''dict replace''' can't do; removes keys
   and values.  The result of the command is a new dictionary value
   that does not contain mappings for any of the keys listed; it is
   not an error if either there are no keys listed, or if any of the
   listed keys does not exist in the supplied dictionary.

 dict set:	Set value for given key in a dictionary in a variable.

 > '''dict set''' ''dictionaryVar key'' ?''key ...''? ''value''

 > This operation takes the name of a variable containing a dictionary
   value and places an updated dictionary value in that variable
   containing a mapping from the given key to the given value.  In a
   manner analogous to '''lset''', where multiple keys are present, they
   do indexing into nested dictionaries.

 dict unset:	Remove association for given key in a dictionary in a
		variable.

 > '''dict unset''' ''dictionaryVar key'' ?''key ...''?

 > This operation takes the name of a variable containing a dictionary
   value and places an updated dictionary value in that variable that
   does not contain a mapping for the given key.  Where multiple keys
   are present, this describes a path through nested dictionaries to
   the mapping to remove.  At least one key must be specified.

 dict keys:	List all keys (with optional criteria matching) in
		dictionary.

 > '''dict keys''' ''dictionaryValue'' ?''globPattern''?

 > Return a list of all keys in the given dictionary value.  If a
   pattern is supplied, only those keys that match it (according to
   the rules of '''string match''') will be returned.  The returned keys
   will be in an arbitrary implementation-specific order.

 dict values:	List all values (with optional criteria matching) in
		the dictionary.

 > '''dict values''' ''dictionaryValue'' ?''globPattern''?

 > Return a list of all values in the given dictionary value.  If a
   pattern is supplied, only those values that match it (according to
   the rules of '''string match''') will be returned.  The returned keys
   will be in an arbitrary implementation-specific order, though where
   no pattern is supplied the ''i''th key returned by '''dict keys'''
   will be the key for the ''i''th value returned by '''dict values'''
   applied to the same dictionary value.

 dict for:	Iterate across all key/value mappings in the
		dictionary.

 > '''dict for''' {''keyVar valueVar''} ''dictionaryValue body''

 > This takes three arguments, the first a pair of variable names (for
   the key and value respectively of each mapping in the dictionary),
   the second the dictionary value to iterate across, and the third a
   script to be evaluated for each mapping with the key and value
   variables set appropriately (in the manner of '''foreach'''.)  The
   result of the command is an empty string.  If any evaluation of the
   body generates a ''TCL_BREAK'' result, no further pairs from the
   dictionary will be iterated over and the '''dict for''' command will
   terminate successfully immediately.  If any evaluation of the body
   generates a ''TCL_CONTINUE'' result, this shall be treated exactly
   like a normal ''TCL_OK'' result.

 dict filter:	Create a new dictionary from an old one containing just
		a selection of key/value pairs.

 > '''dict filter''' ''dictionaryValue'' '''key''' ''globPattern''

 > '''dict filter''' ''dictionaryValue'' '''value''' ''globPattern''

 > '''dict filter''' ''dictionaryValue'' '''script''' {''keyVar valueVar''} ''script''

 > This takes a dictionary value and returns a new dictionary that
   contains just those key/value pairs that match the specified rule.
   Three rules are outlined above.  The '''key''' rule only matches those
   key/value pairs whose keys match the given glob-style pattern.  The
   '''value''' rule only matches those key/value pairs whose values match
   the given glob-style pattern.  The '''script''' rule tests for matching
   by assigning the key to the ''keyVar'' and the value to the
   ''valueVar'', and then evaluating the given script which should
   return a boolean value (with the key/value pair only being included
   in the result of the '''dict filter''' when a true value is returned.)

 dict append:	Append a string to the value for a particular key in
		the dictionary.

 > '''dict append''' ''dictionaryVar key'' ?''string ...''?

 > This appends the given string (or strings) to the value that the
   given key maps to in the dictionary value contained in the given
   variable, writing the resulting dictionary value back to that
   variable.  Non-existent keys are treated as if they map to an empty
   string.

 dict incr:	Increment the value for a particular key in the
		dictionary.

 > '''dict incr''' ''dictionaryVar key'' ?''increment''?

 > This adds the given increment value (an integer that defaults to 1
   if not specified) to the value that the given key maps to in the
   dictionary value contained in the given variable, writing the
   resulting dictionary value back to that variable.  Non-existent
   keys are treated as if they map to 0.  It is an error to increment
   a value for an existing key if that value is not an integer.

 dict lappend:	Append an item to the list-value for a particular key
		in the dictionary.

 > '''dict lappend''' ''dictionaryVar key'' ?''item ...''?

 > This appends the given items to the list value that the given key
   maps to in the dictionary value contained in the given variable,
   writing the resulting dictionary value back to that variable.
   Non-existent keys are treated as if they map to an empty list, and
   it is legal for there to be no items to append to the list.  It is
   an error for the value that the key maps to to not be representable
   as a list.

 dict exists:	Test whether a mapping exists for a key.

 > '''dict exists''' ''dictionaryValue key'' ?''key ...''?

 > This returns a boolean value indicating whether the given key (or
   path of keys through a set of nested dictionaries) exists in the
   given dictionary value.  This returns a true value exactly when
   '''dict get''' on that path will succeed.

 dict size:	Get the number of key/value mappings in a dictionary.

 > '''dict size''' ''dictionaryValue''

 > This returns the size of the dictionary, which will be exactly half
   the value that '''llength''' ''dictionaryValue'' would return.  It is an
   error to apply this command to a non-dictionary value.

 dict info:	Get implementation-specific information about the
		dictionary value.

 > '''dict info''' ''dictionaryValue''

 > This returns information (intended for display to people) about the
   given dictionary though the format of this data is dependent on the
   implementation of the dictionary.  For dictionaries that are
   implemented by hash tables, it is expected that this will return
   the string produced by ''Tcl_HashStats()''.

~ Other Related Changes

There are a few other commands that change:

 * '''array set''' will take a dictionary instead of (or as well as) a
   list as its final argument.

 * '''array get''' will return a dictionary.

 * '''string map''' will take a dictionary instead of (or as well as) a
   list as its map argument.

Naturally, dictionary handling will form its own maintenance area.  [16] and [24] will be updated as necessary.

~ C API

There will be a new public structure and a few new public functions to
allow C-level access to dictionary values:

The new structure (called ''Tcl_DictSearch'') will be there to allow
for searches (i.e. traversals) of a dictionary.  This TIP does not
specify the fields of the structure; the declaration is just to allow
for allocation of these structures on the C stack.

Many public API functions are capable of generating error messages;
these generally indicate some type-conversion failure.  Sharing
constraint violations (where applicable) cause panics as they indicate
basic programming errors which should not be causable by scripts.  The
public API functions are:

 > Tcl_Obj *'''Tcl_NewDictObj'''(void);

 > Tcl_Obj *'''Tcl_DbNewDictObj'''(CONST char *''file'', int ''line'');

These functions (in non-debug and debug versions) create a new
dictionary object and return it.

 > int '''Tcl_DictObjPut'''(Tcl_Interp *''interp'', Tcl_Obj *''dictPtr'',
	Tcl_Obj *''keyPtr'', Tcl_Obj *''valuePtr'');

This function inserts a new key/value pair into a dictionary, or
updates a key/value pair already in the dictionary.  The dictionary
object must be unshared.  Note that both the key and value objects
will have their reference count increased.  The return value is a
normal TCL_OK/TCL_ERROR result, with the ''interp'' for error
reporting.

 > int '''Tcl_DictObjGet'''(Tcl_Interp *''interp'', Tcl_Obj *''dictPtr'',
	Tcl_Obj *''keyPtr'', Tcl_Obj **''valuePtrPtr'');

This function looks up the value for a key in a dictionary.  The
variable pointed to by the ''valuePtrPtr'' argument is updated to
contain a reference to the value, or a NULL if there is no mapping for
the key in the dictionary.  No reference counts are manipulated by
this function.  The return value is a normal TCL_OK/TCL_ERROR result,
with the ''interp'' for error reporting.

 > int '''Tcl_DictObjRemove'''(Tcl_Interp *''interp'', Tcl_Obj *''dictPtr'',
	Tcl_Obj *''keyPtr'');

This function removes the key/value pair with the given key from the
dictionary.  It is not an error if the key is not present in the
dictionary.  The dictionary must be unshared.  The return value is a
normal TCL_OK/TCL_ERROR result, with the ''interp'' for error
reporting.

 > int '''Tcl_DictObjSize'''(Tcl_Interp *''interp'', Tcl_Obj *''dictPtr'',
	int *''sizePtr'');

This function updates the integer variable pointed to by ''sizePtr''
with the number of key/value pairs in the dictionary.  The return
value is a normal TCL_OK/TCL_ERROR result, with the ''interp'' for
error reporting.

 > int '''Tcl_DictObjFirst'''(Tcl_Interp *''interp'', Tcl_Obj *''dictPtr'',
	Tcl_DictSearch *''searchPtr'',
	Tcl_Obj **''keyPtrPtr'', Tcl_Obj **''valuePtrPtr'', int *''donePtr'');

This function starts a search of (i.e. iteration over) the given
dictionary, using the structure pointed to by ''searchPtr'' as
context.  The return value is a normal TCL_OK/TCL_ERROR result, with
the ''interp'' for error reporting.  Three variables are updated to
indicate what was found; ''keyPtrPtr'' is used for reporting the key
of a key/value pair and ''valuePtrPtr'' is used for reporting the
corresponding value.  Finally, ''donePtr'' is used for indicating
whether the search has found all the values; if the variable it points
to is set to 1 there are no key/value pairs in the dictionary
(i.e. the variables pointed to by ''keyPtrPtr'' and ''valuePtrPtr''
were not updated), but if the variable is set to 0, a key/value pair
was found and ''Tcl_DictObjNext()'' should be called to discover
whether that was the last value or if there are further ones in the
dictionary.  Note that if this function indicates that the search is
not done but the calling code wishes to extract no further values from
the dictionary, ''Tcl_DictObjDone()'' ''must'' be called to release
the internal locks on the representation of the value.

 > void '''Tcl_DictObjNext'''(Tcl_DictSearch *''searchPtr'',
	Tcl_Obj **''keyPtrPtr'', Tcl_Obj **''valuePtrPtr'', int *''donePtr'');

This function gets the next key/value pair from the search of a
dictionary, using the search referenced by ''searchPtr''.  The meaning
of the ''keyPtrPtr'', ''valuePtrPtr'' and ''donePtr'' variables is
much the same as in ''Tcl_DictObjFirst()'', along with the restriction
that if the function indicates that the search is not done but the
calling code wishes to extract no further values from the dictionary,
''Tcl_DictObjDone()'' ''must'' be called to release the internal locks
on the representation of the value.

 > void '''Tcl_DictObjDone'''(Tcl_DictSearch *''searchPtr'');

This function terminates a search of a dictionary before all the
values in the dictionary have been iterated over, releasing the
internal locks on the dictionary representation.

 > int '''Tcl_DictObjPutKeyList'''(Tcl_Interp *''interp'', Tcl_Obj *''dictPtr'',
	int ''keyc'', Tcl_Obj *CONST *''keyv'', Tcl_Obj *''valuePtr'');

This function is a variant on ''Tcl_DictObjPut()'' that takes a list
of keys so as to work with nested dictionaries.

 > int '''Tcl_DictObjRemoveKeyList'''(Tcl_Interp *''interp'', Tcl_Obj *''dictPtr'',
	int ''keyc'', Tcl_Obj *CONST *''keyv'');

This function is a variant on ''Tcl_DictObjRemove()'' that takes a
list of keys so as to work with nested dictionaries.

~ Examples

Counting the number of unique words in a file and the number of times
each word occurs:

|set f [open someFile.txt]
|set contents [read $f]
|close $f
|foreach word [regexp -all -inline {\w+} $contents] {
|   dict incr count $word
|}

|puts "There are [dict size $count] unique words."
|foreach word [lsort -dictionary [dict keys $count]] {
|   puts "${word}: [dict get $count $word] occurrences"
|}

A localisable '''string toupper''' implementation:


|set capital [dict create C [dict create]]
|foreach c {abcdefghijklmnopqrstuvwxyz} {
|   dict set capital C $c [string toupper $c]
|}

|dict set capital en [dict get $capital C]
|# ... and so on for other supported languages ...
|set upperCase [string map [dict get $capital $env(LANG)] $string

~ Copyright

This document has been placed in the public domain.

----

~ Appendices

''These appendices are not formally part of the proposal and exist
merely to help understanding.''

~ ~ Implementation Notes

Implement using hash tables (of course.)  Need efficient ways to
convert to/from lists, perhaps making lists know what's going on
underneath the covers?

~ ~ Future Directions

Alternate implementations of mappings, like trees or disk-backed
databases?

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|



|














|
|

|



|



|


|

|
|



|











|
|





|

|
|
|

|


|
|
|

|
|
|
|





|



|


|







|

|
|

|
|
|



|
|


|










|

|












|

|







|




|





|







|


|


|
|


|


|


|
|

|
|





|

|
|


|

|
|

|
|




|

|

|



|

|
|
|
|
|
|




|

|








|

|
|








|











|

|
|

|



|


|





|

|



|

|



|


|

|


|

|




|
|





|



|

|

|


|
|





|


|
|


|


|
|

|
|




|


|
|

|

|


|
|
|

|
|
|
|
|
|
|


|
|
|



|


|
|


|
|
|


|


|





|
|

|


|
|

|


|




|
|
|
|
|
<
>
|
|
|
<
|
|
>

|
|
|
<
>
|
|
|

|





|

|
|

|

|



|



>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440

441
442
443
444

445
446
447
448
449
450
451

452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478

# TIP 111: Dictionary Values and Manipulators

	Author:         Donal K. Fellows <[email protected]>
	Author:         David S. Cargo <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        05-Oct-2002
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes adding a standard value format \(and supporting
commands\) to Tcl that implements a value-to-value mapping, just as
Tcl's list values can be regarded as implementing a number-to-value
mapping.

# Rationale

What is a dictionary?  It is a translation from arbitrary values to
arbitrary values, often also known as an associative map.  Many
computer languages, especially higher-level ones, have them as part of
the language or the standard library.  It would be nice to have them
in Tcl too.

Now, I realise that Tcl already contains arrays which provide
dictionary functionality, but they are not quite the same thing.
Tcl's arrays are collections of variables indexable by name, and not
collections of values.  This has some far-reaching implications; it is
possible to set traces on individual elements of the array, but it is
not possible to pass the array by value.  However, one of the main
concerns is the sheer cost of arrays in terms of memory space; aside
from the hash table used as the core of the implementation \(and the
representations of the keys and values, of course\) there is a
substantial overhead for each array to support traces on the array as
a whole, plus a similar overhead _per element_ that stems from the
fact that elements are variables in their own right.  By contrast, a
dictionary value should be a lot more frugal.

# Value Syntax and Semantics

Naturally, it is desirable for dictionary values to have
human-readable forms that are similar to those that currently exist.
I propose using _key value key value ..._ form with list-style
quoting for keys and values that contain characters that are
significant to Tcl, which should be immediately familiar to users of
the **array get** and **array set** commands.  No special
interpretation will be placed on the amount of whitespace separating
keys and values, just as with lists \(indeed, any list with an even
number of elements can be regarded as a dictionary.\)  For example, the
following value represents a mapping from selected languages to a
possible program to invoke to compile them:

		C gcc C++ g++ FORTRAN f77 Java javac

Empty dictionaries are those that contain no mappings from keys to
values.  Any representation of an empty list will also be a
representation of an empty dictionary.  There is no upper bound on the
number of items that a dictionary may hold.

It should be specially noted that dictionary values have copy-on-write
semantics just like lists.  This means that if I hand a dictionary
value into a procedure as an argument, and that procedure updates the
variable containing that value, the value as seen by the caller will
not have changed.  This is in complete contrast with arrays which
cannot \(currently\) be passed by value other than through using **array
get** to convert the array to a list form and **array set** to convert
back again.

This specification does not state what order the keys and values are
listed in.  That depends on the implementation.

# Command Syntax and Semantics

I propose that all operations that work with dictionary values \(where
not done through adaptations of existing commands\) will go through the
**dict** command.  The alternatives are "array" which is already in
use, "dictionary" which is rather long for what I believe will be a
fairly commonly used command, "alist" \(association list\) which is
probably too easy to confuse with existing commands, and "map" which
is probably better reserved for future use as something for applying
an operation to a list \(or other collection of values\), "hash" \(which
is perhaps too common\), and "table" \(which is used for this type of
data structure in the Icon programming language\).

Most subcommands operate on either a dictionary value \(_exists_,
_for_, _get_, _info_, _keys_, _remove_, _replace_,
_size_, and _values_\), or on a variable containing a dictionary
value \(_append_, _incr_, _lappend_, _set_, and _unset_\).

Proposed subcommands:

 dict create:	Make a dictionary.

 > **dict create** ?_key1 value1 key2 value2 ..._?

 > This will create a new dictionary from the given keys and values
   and return it as the result.  The command will take an even number
   of arbitrary strings \(or other objects, naturally\) and will use the
   first, third, fifth, etc. as keys and the second, fourth, sixth,
   etc. as values.  From the point of view of string representations,
   this command will behave the same as the **list** command with an
   even number of arguments.  There is no restriction on the possible
   representations of keys or values.  It is legal to call this
   command with no arguments at all, which creates an empty
   dictionary.

 dict get:	Get value for given key.

 > **dict get** _dictionaryValue_ ?_key ..._?

 > Given a dictionary value \(first argument\) and a key \(second
   argument\), this will retrieve the value for that key.  Where
   several keys are supplied, the behaviour of the command shall be as
   if the result of **dict get** _dictVal key_ was passed as the first
   argument to **dict get_ with the remaining arguments as second
   \(and possibly subsequent\) arguments.  This facilitates lookups in
   nested dictionaries.  For example, the following two commands are
   equivalent:

		dict get $dict foo bar spong
		dict get [dict get [dict get $dict foo] bar] spong

 > If no keys are provided, dict would return a list containing pairs
   of elements in a manner similar to **array get**.  That is, the
   first element of each pair would be the key and the second element
   would be the value for that key.

 > It is an error to attempt to retrieve a value for a key that is not
   present in the dictionary.

 dict replace:	Create a new dictionary that is a copy of an old one
		except with some values different or some extra
		key/value pairs added.

 > **dict replace** _dictionaryValue_ ?_key value ..._?

 > This is very much the analogue of **lreplace**, taking a dictionary
   value as its first argument and then a list of key/value pairs.
   The result of the command is a new dictionary value that is a copy
   of the supplied dictionary other than that whenever a key is one of
   those supplied to this command, the returned dictionary will map
   that key to the associated value.  It is legal for this command to
   be called with no key/value pairs, but illegal for this command to
   be called with a key but no value.

 dict remove:	Create a new dictionary that is a copy of an old one
		except without the key/value mappings whose keys are
		listed.

 > **dict remove** _dictionaryValue_ ?_key key ..._?

 > This operation does what **dict replace** can't do; removes keys
   and values.  The result of the command is a new dictionary value
   that does not contain mappings for any of the keys listed; it is
   not an error if either there are no keys listed, or if any of the
   listed keys does not exist in the supplied dictionary.

 dict set:	Set value for given key in a dictionary in a variable.

 > **dict set** _dictionaryVar key_ ?_key ..._? _value_

 > This operation takes the name of a variable containing a dictionary
   value and places an updated dictionary value in that variable
   containing a mapping from the given key to the given value.  In a
   manner analogous to **lset**, where multiple keys are present, they
   do indexing into nested dictionaries.

 dict unset:	Remove association for given key in a dictionary in a
		variable.

 > **dict unset** _dictionaryVar key_ ?_key ..._?

 > This operation takes the name of a variable containing a dictionary
   value and places an updated dictionary value in that variable that
   does not contain a mapping for the given key.  Where multiple keys
   are present, this describes a path through nested dictionaries to
   the mapping to remove.  At least one key must be specified.

 dict keys:	List all keys \(with optional criteria matching\) in
		dictionary.

 > **dict keys** _dictionaryValue_ ?_globPattern_?

 > Return a list of all keys in the given dictionary value.  If a
   pattern is supplied, only those keys that match it \(according to
   the rules of **string match**\) will be returned.  The returned keys
   will be in an arbitrary implementation-specific order.

 dict values:	List all values \(with optional criteria matching\) in
		the dictionary.

 > **dict values** _dictionaryValue_ ?_globPattern_?

 > Return a list of all values in the given dictionary value.  If a
   pattern is supplied, only those values that match it \(according to
   the rules of **string match**\) will be returned.  The returned keys
   will be in an arbitrary implementation-specific order, though where
   no pattern is supplied the _i_th key returned by **dict keys**
   will be the key for the _i_th value returned by **dict values**
   applied to the same dictionary value.

 dict for:	Iterate across all key/value mappings in the
		dictionary.

 > **dict for** \{_keyVar valueVar_\} _dictionaryValue body_

 > This takes three arguments, the first a pair of variable names \(for
   the key and value respectively of each mapping in the dictionary\),
   the second the dictionary value to iterate across, and the third a
   script to be evaluated for each mapping with the key and value
   variables set appropriately \(in the manner of **foreach**.\)  The
   result of the command is an empty string.  If any evaluation of the
   body generates a _TCL\_BREAK_ result, no further pairs from the
   dictionary will be iterated over and the **dict for** command will
   terminate successfully immediately.  If any evaluation of the body
   generates a _TCL\_CONTINUE_ result, this shall be treated exactly
   like a normal _TCL\_OK_ result.

 dict filter:	Create a new dictionary from an old one containing just
		a selection of key/value pairs.

 > **dict filter** _dictionaryValue_ **key** _globPattern_

 > **dict filter** _dictionaryValue_ **value** _globPattern_

 > **dict filter** _dictionaryValue_ **script** \{_keyVar valueVar_\} _script_

 > This takes a dictionary value and returns a new dictionary that
   contains just those key/value pairs that match the specified rule.
   Three rules are outlined above.  The **key** rule only matches those
   key/value pairs whose keys match the given glob-style pattern.  The
   **value** rule only matches those key/value pairs whose values match
   the given glob-style pattern.  The **script** rule tests for matching
   by assigning the key to the _keyVar_ and the value to the
   _valueVar_, and then evaluating the given script which should
   return a boolean value \(with the key/value pair only being included
   in the result of the **dict filter** when a true value is returned.\)

 dict append:	Append a string to the value for a particular key in
		the dictionary.

 > **dict append** _dictionaryVar key_ ?_string ..._?

 > This appends the given string \(or strings\) to the value that the
   given key maps to in the dictionary value contained in the given
   variable, writing the resulting dictionary value back to that
   variable.  Non-existent keys are treated as if they map to an empty
   string.

 dict incr:	Increment the value for a particular key in the
		dictionary.

 > **dict incr** _dictionaryVar key_ ?_increment_?

 > This adds the given increment value \(an integer that defaults to 1
   if not specified\) to the value that the given key maps to in the
   dictionary value contained in the given variable, writing the
   resulting dictionary value back to that variable.  Non-existent
   keys are treated as if they map to 0.  It is an error to increment
   a value for an existing key if that value is not an integer.

 dict lappend:	Append an item to the list-value for a particular key
		in the dictionary.

 > **dict lappend** _dictionaryVar key_ ?_item ..._?

 > This appends the given items to the list value that the given key
   maps to in the dictionary value contained in the given variable,
   writing the resulting dictionary value back to that variable.
   Non-existent keys are treated as if they map to an empty list, and
   it is legal for there to be no items to append to the list.  It is
   an error for the value that the key maps to to not be representable
   as a list.

 dict exists:	Test whether a mapping exists for a key.

 > **dict exists** _dictionaryValue key_ ?_key ..._?

 > This returns a boolean value indicating whether the given key \(or
   path of keys through a set of nested dictionaries\) exists in the
   given dictionary value.  This returns a true value exactly when
   **dict get** on that path will succeed.

 dict size:	Get the number of key/value mappings in a dictionary.

 > **dict size** _dictionaryValue_

 > This returns the size of the dictionary, which will be exactly half
   the value that **llength** _dictionaryValue_ would return.  It is an
   error to apply this command to a non-dictionary value.

 dict info:	Get implementation-specific information about the
		dictionary value.

 > **dict info** _dictionaryValue_

 > This returns information \(intended for display to people\) about the
   given dictionary though the format of this data is dependent on the
   implementation of the dictionary.  For dictionaries that are
   implemented by hash tables, it is expected that this will return
   the string produced by _Tcl\_HashStats\(\)_.

# Other Related Changes

There are a few other commands that change:

 * **array set** will take a dictionary instead of \(or as well as\) a
   list as its final argument.

 * **array get** will return a dictionary.

 * **string map** will take a dictionary instead of \(or as well as\) a
   list as its map argument.

Naturally, dictionary handling will form its own maintenance area.  [[16]](16.md) and [[24]](24.md) will be updated as necessary.

# C API

There will be a new public structure and a few new public functions to
allow C-level access to dictionary values:

The new structure \(called _Tcl\_DictSearch_\) will be there to allow
for searches \(i.e. traversals\) of a dictionary.  This TIP does not
specify the fields of the structure; the declaration is just to allow
for allocation of these structures on the C stack.

Many public API functions are capable of generating error messages;
these generally indicate some type-conversion failure.  Sharing
constraint violations \(where applicable\) cause panics as they indicate
basic programming errors which should not be causable by scripts.  The
public API functions are:

 > Tcl\_Obj \***Tcl\_NewDictObj**\(void\);

 > Tcl\_Obj \***Tcl\_DbNewDictObj**\(CONST char \*_file_, int _line_\);

These functions \(in non-debug and debug versions\) create a new
dictionary object and return it.

 > int **Tcl\_DictObjPut**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_dictPtr_,
	Tcl\_Obj \*_keyPtr_, Tcl\_Obj \*_valuePtr_\);

This function inserts a new key/value pair into a dictionary, or
updates a key/value pair already in the dictionary.  The dictionary
object must be unshared.  Note that both the key and value objects
will have their reference count increased.  The return value is a
normal TCL\_OK/TCL\_ERROR result, with the _interp_ for error
reporting.

 > int **Tcl\_DictObjGet**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_dictPtr_,
	Tcl\_Obj \*_keyPtr_, Tcl\_Obj \*\*_valuePtrPtr_\);

This function looks up the value for a key in a dictionary.  The
variable pointed to by the _valuePtrPtr_ argument is updated to
contain a reference to the value, or a NULL if there is no mapping for
the key in the dictionary.  No reference counts are manipulated by
this function.  The return value is a normal TCL\_OK/TCL\_ERROR result,
with the _interp_ for error reporting.

 > int **Tcl\_DictObjRemove**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_dictPtr_,
	Tcl\_Obj \*_keyPtr_\);

This function removes the key/value pair with the given key from the
dictionary.  It is not an error if the key is not present in the
dictionary.  The dictionary must be unshared.  The return value is a
normal TCL\_OK/TCL\_ERROR result, with the _interp_ for error
reporting.

 > int **Tcl\_DictObjSize**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_dictPtr_,
	int \*_sizePtr_\);

This function updates the integer variable pointed to by _sizePtr_
with the number of key/value pairs in the dictionary.  The return
value is a normal TCL\_OK/TCL\_ERROR result, with the _interp_ for
error reporting.

 > int **Tcl\_DictObjFirst**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_dictPtr_,
	Tcl\_DictSearch \*_searchPtr_,
	Tcl\_Obj \*\*_keyPtrPtr_, Tcl\_Obj \*\*_valuePtrPtr_, int \*_donePtr_\);

This function starts a search of \(i.e. iteration over\) the given
dictionary, using the structure pointed to by _searchPtr_ as
context.  The return value is a normal TCL\_OK/TCL\_ERROR result, with
the _interp_ for error reporting.  Three variables are updated to
indicate what was found; _keyPtrPtr_ is used for reporting the key
of a key/value pair and _valuePtrPtr_ is used for reporting the
corresponding value.  Finally, _donePtr_ is used for indicating
whether the search has found all the values; if the variable it points
to is set to 1 there are no key/value pairs in the dictionary
\(i.e. the variables pointed to by _keyPtrPtr_ and _valuePtrPtr_
were not updated\), but if the variable is set to 0, a key/value pair
was found and _Tcl\_DictObjNext\(\)_ should be called to discover
whether that was the last value or if there are further ones in the
dictionary.  Note that if this function indicates that the search is
not done but the calling code wishes to extract no further values from
the dictionary, _Tcl\_DictObjDone\(\)_ _must_ be called to release
the internal locks on the representation of the value.

 > void **Tcl\_DictObjNext**\(Tcl\_DictSearch \*_searchPtr_,
	Tcl\_Obj \*\*_keyPtrPtr_, Tcl\_Obj \*\*_valuePtrPtr_, int \*_donePtr_\);

This function gets the next key/value pair from the search of a
dictionary, using the search referenced by _searchPtr_.  The meaning
of the _keyPtrPtr_, _valuePtrPtr_ and _donePtr_ variables is
much the same as in _Tcl\_DictObjFirst\(\)_, along with the restriction
that if the function indicates that the search is not done but the
calling code wishes to extract no further values from the dictionary,
_Tcl\_DictObjDone\(\)_ _must_ be called to release the internal locks
on the representation of the value.

 > void **Tcl\_DictObjDone**\(Tcl\_DictSearch \*_searchPtr_\);

This function terminates a search of a dictionary before all the
values in the dictionary have been iterated over, releasing the
internal locks on the dictionary representation.

 > int **Tcl\_DictObjPutKeyList**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_dictPtr_,
	int _keyc_, Tcl\_Obj \*CONST \*_keyv_, Tcl\_Obj \*_valuePtr_\);

This function is a variant on _Tcl\_DictObjPut\(\)_ that takes a list
of keys so as to work with nested dictionaries.

 > int **Tcl\_DictObjRemoveKeyList**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_dictPtr_,
	int _keyc_, Tcl\_Obj \*CONST \*_keyv_\);

This function is a variant on _Tcl\_DictObjRemove\(\)_ that takes a
list of keys so as to work with nested dictionaries.

# Examples

Counting the number of unique words in a file and the number of times
each word occurs:

	set f [open someFile.txt]
	set contents [read $f]
	close $f
	foreach word [regexp -all -inline {\w+} $contents] {
	   dict incr count $word

	}
	puts "There are [dict size $count] unique words."
	foreach word [lsort -dictionary [dict keys $count]] {
	   puts "${word}: [dict get $count $word] occurrences"

	}

A localisable **string toupper** implementation:

	set capital [dict create C [dict create]]
	foreach c {abcdefghijklmnopqrstuvwxyz} {
	   dict set capital C $c [string toupper $c]

	}
	dict set capital en [dict get $capital C]
	# ... and so on for other supported languages ...
	set upperCase [string map [dict get $capital $env(LANG)] $string

# Copyright

This document has been placed in the public domain.

----

# Appendices

_These appendices are not formally part of the proposal and exist
merely to help understanding._

# ~ Implementation Notes

Implement using hash tables \(of course.\)  Need efficient ways to
convert to/from lists, perhaps making lists know what's going on
underneath the covers?

# ~ Future Directions

Alternate implementations of mappings, like trees or disk-backed
databases?

Name change from tip/112.tip to tip/112.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

181
182
183
184
185
186
187
188
189
190



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

212
213
214
215
216
217
218
219
220

221
222
223

224
225
226
227
228
229

230
231
232
233
234
235
236
237
238
239
240
241

242
243
244
245
246
247
248
249
250
251
252

253
254
255
256
257
258
259
260

261
262
263

264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285

TIP:            112
Title:          Ensembles are Namespaces are Commands
Version:        $Revision: 2.28 $
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        10-Oct-2002
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes unifying the concept of ensembles (from [[Incr
Tcl]]) with namespaces and commands.  It also adds control of command
rewriting to allow for more efficient support for object systems like
Snit.

~ Rationale

Tcl's subcommand-style command collections (e.g. ''array'', ''info'',
''string'', ''interp'', etc.) are a very intuitive and popular way of
structuring collections of related commands.  However, it is quite
awkward to write Tcl code that behaves that way.  Users of [[Incr
Tcl]] have access to ensembles which provide that, but it would be a
very useful feature for many other uses too.

At the same time, it is becoming clear that many applications want to
commonly refer to commands inside other namespaces directly (instead
of through the [[namespace import]] mechanism) but the syntax for
doing this is verbose and not as elegant as it might be.

I believe that the same solution can address these two problems in one
go, and make the language stronger and more usable for it.

Furthermore, by giving the programmer control over the mapping from
the ensemble subcommands to their implementing commands, we can build
a simple class system on the cheap since we can, in effect, import
commands from elsewhere into the ensemble.  By extending the mapping
so that it allows the specification of not just the implementing
command, but also some leading arguments to that command (similar to
what you can do with the [[interp alias]] mechanism) this becomes a
very powerful mechanism indeed.

Finally, a sophisticated extra capability is the addition of an unknown
subcommand callback to allow the creator of the ensemble to specify a
customized strategy for handling subcommands that are not recognized by
the ensemble machinery.  This allows an ensemble to be dynamically
updated to include those subcommands that the user asks for, which is
a potential route for doing things like using an ensemble as a wrapper
round a Tk widget.

~ Proposed Change

I propose to add a new subcommand to the [[namespace]] command,
''ensemble'', that creates and manipulates the ensemble command for a
namespace.  Each namespace may have any number of ensemble commands
associated with it, with the default name of an ensemble command
being the fully-qualified name of the namespace itself, though it will
be legal to rename ensemble commands (anyone wanting to track such
events should use the [[trace]] command.)  Tcl will not create an
ensemble command for any namespace by default.

The [[namespace ensemble]] command will have the following subcommands:

 create: For creating a new ensemble for the ''current'' namespace. The
   command takes a list of option value pairs (as defined below) to
   set the ensemble up with.  As stated above, the default command name
   is exactly the name of the namespace, but any other name may be
   supplied (via the -command option); if it does not start with a
   namespace separator, the name will be taken as being relative to
   the current namespace.  If another command with the same name exists,
   it is deleted as part of the creation of the ensemble.

 configure: For reading and writing the configuration of a particular
   ensemble.  The command takes an argument specifying the name of the
   ensemble to configure, and then works with either no extra arguments
   (when it retrieves the entire ensemble configuration), one extra
   argument (the name of the option to retrieve), or a list of option
   value pairs to configure the ensemble with.  This command returns an error if applied to anything that is not an ensemble.

 exists: This subcommand (which takes a single argument) tests whether
   a command (with the given name) exists and is an ensemble.  This command only returns an error if the wrong number of arguments are supplied.

The options available for creation and configuring are:

 -subcommands: This option (if non-empty) specifies a list of ensemble
   subcommands that the ensemble supports.  It does not need to be
   sorted.  Each command is mapped according to the dictionary in the
   ''-map'' option (if a non-empty map is present and the command has
   a mapping) or to the correspondingly named command (which is not
   required to exist at the time this is specified) in the context
   namespace.

 -map: This option (if non-empty) specifies a dictionary that maps
   from ensemble subcommand names to lists of arguments to substitute
   into the ensemble invokation in place of the ensemble command name
   and the subcommand name.  See the ''-subcommands'' option for the meaning
   of this option when that option is also non-empty.  If this option is
   empty and the ''-subcommands'' option is empty too, the namespace will use
   the exported commands of the namespace as its command set, dynamically
   determining them (subject to cacheing) every time the ensemble is
   ''invoked''.  Note that the words in the dictionary values that give
   the commands to map to (as opposed to any arguments to them) are
   always resolved (if not absolute) relative to the namespace which is
   running [[namespace ensemble create]] or [[namespace ensemble
   configure]].

 -prefixes: This boolean option (which is on by default) controls whether
   unambiguous prefixes of ensemble commands are recognized as if they
   were the fully specified ensemble command names.

 -unknown: This provides (when non-empty) a partial command to handle
   the case where an ensemble subcommand is not recognized and would
   otherwise generate an error.  When empty (the default) an error (in
   the style of ''Tcl_GetIndexFromObj'') is generated whenever the
   ensemble is unable to determine how to implement a particular
   subcommand.

 > See ''Unknown Handler Behaviour'' below for details of how the
   ensemble interacts with its unknown handler.

Ensemble creation takes an extra option value pair:

 -command: This option allows you to override what the name of the
   ensemble to create is.

Ensemble configuring allows the querying of an extra read-only option:

 -namespace: This ''read-only'' option allows the retrieval of the name
   of the namespace that the ensemble was created in.

Given an ensemble command created by the above mechanism, calling the
command will first of all match the subcommand to its implementing
command (or command/argument list, as derived from the dictionary) in
a manner that will be recognizably similar to that enforced by
''Tcl_GetIndexFromObj()'' (unless the ''-unknown'' option override this
behaviour.)  For details of how the ensemble determines what its subcommands are, please see the ''-subcommands'' and ''-map'' options above.
Then the ensemble command will rewrite the command and arguments so
that the ensemble command and subcommand are replaced by the
implementing command and any specified arguments, with the resulting
word list being fed to ''Tcl_EvalObjv()'' for execution.  Note that
this does not increase the stack depth in terms of [[uplevel]], and
that the implementing command may itself be an ensemble command.

Note that if the namespace for an ensemble is deleted, the ensemble will
also be deleted though there is no lifetime constraint in the other
direction (i.e. using [[rename $theEnsemble {}]] will not cause the
namespace to vanish.)  Obviously, any ensemble which has the global
namespace backing it up will have the same natural lifespan as the
hosting Tcl interpreter.

~ Unknown Handler Behaviour

If an unknown handler is specified for an ensemble, that handler is called when the ensemble command would otherwise return an error due to it being unable to decide which subcommand to invoke.  The exact conditions under which that occurs are controlled by the ''-subcommands'', ''-map'' and ''-prefixes'' options as described above.

To execute the unknown handler, the ensemble mechanism takes the specified -unknown option and appends each argument of the attempted ensemble command invocation (including the ensemble command itself, expressed as a fully qualified name). It invokes the resulting command in the scope of the attempted call. If the execution of the unknown handler terminates normally, the ensemble engine reparses the subcommand (as described below) and tries to dispatch it again, which is ideal for when the ensemble's configuration has been updated by the unknown subcommand handler.  Any other kind of termination of the unknown handler is treated as an error.

The result of the unknown handler is expected to be a list (it is an error if it is not).  If the list is an empty list, the ensemble command attempts to look up the original subcommand again and, if it is not found this time, an error will be generated just as if the -unknown handler was not there (i.e. for any particular invokation of an ensemble, its unknown handler will be called at most once.)  This makes it easy for the unknown handler to update the ensemble or its backing namespace so as to provide an implementation of the desired subcommand and reparse.

When the result is a non-empty list, the words of that list are used to replace the ensemble command and subcommand, just as if they had been looked up in the -map.  It is up to the unknown handler to supply all namespace qualifiers if the implementing subcommand is not in the namespace of the caller of the ensemble command.  Also note that when ensemble commands are chained (e.g. if you make one of the commands that implement an ensemble subcommand into an ensemble, in a manner similar to the text widget's ''tag'' and ''mark'' subcommands) then the rewrite happens in the context of the caller of the outermost ensemble.  That is to say that ensembles do not in themselves place any namespace contexts on the Tcl call stack.

Where an empty -unknown handler is given (the default), the ensemble command will generate an error message based on the list of commands that the ensemble has defined (formatted similarly to the error message from ''Tcl_GetIndexFromObj()'').  This is the error that will be thrown when the subcommand is still not recognized during reparsing. It is also an error for an -unknown handler to delete its namespace.

~ Examples

|namespace eval carrot {
|   namespace export foo bar potato
|   namespace ensemble create     ;# Creates command ::carrot
|
|   proc foo {} {puts 1}          ;# Exported
|   proc bar {} {puts 2}          ;# Exported
|   proc boo {} {puts 3}          ;# Not exported
|
|   namespace eval turnip {       ;# Not exported
|      namespace export alpha
|      proc alpha {} {puts 4}     ;# Exported
|      proc beta {} {puts 5}      ;# Not exported
|      namespace ensemble create
|   }

|
|   namespace eval potato {       ;# Exported
|      proc north {x} {puts 6,$x} ;# Not exported
|      proc south {x} {puts 7,$x} ;# Not exported
|      # Notice we resolve names locally, and Tcl metachars are not special
|      namespace ensemble create -map {
|         north {north [$meta[$chars}
|      }
|   }
|}



|
|
|carrot foo                       ;# Prints 1
|carrot bar                       ;# Prints 2
|carrot b                         ;# Also prints 2 ("boo" not exported)
|carrot ?                         ;# ERROR: Alternatives "bar", "foo" and "potato"
|carrot potato                    ;# ERROR: Missing argument
|carrot potato ?                  ;# ERROR: Try "north" instead
|carrot potato north              ;# Prints 6,[$meta[$chars
|carrot turnip alpha              ;# ERROR: "turnip" not known
|carrot::turnip alpha             ;# Prints 4
|carrot::turnip::beta             ;# Prints 5
|
|rename ::carrot::potato ::spud
|spud north                       ;# Prints 6,[$meta[$chars
|spud south                       ;# ERROR: "south" not known
|carrot potato north              ;# ERROR: No ::carrot::potato command
|# Reconfigure spud; notice we get different name resolution now!
|namespace ensemble configure spud -map {
|   north {puts NORTH} south {puts SOUTH}
|}

|spud north                       ;# Prints NORTH
|spud south                       ;# Prints SOUTH
|namespace delete carrot
|spud north                       ;# ERROR: spud command already deleted
|
|
|namespace eval A {
|   proc a args {puts A::a=>$args}
|}

|namespace eval B {
|   proc b args {puts B::b=>$args}
|}

|# Create an ensemble in the global namespace
|namespace ensemble create -command C -map {
|   eg1 {::A::a foo bar}
|   eg2 {::B::b 1 2 3}
|   eg3 ::string
|}

|C eg1 spong                      ;# Prints A::a=>foo bar spong
|C eg2 evil code {[exit]}         ;# Prints B::b=>1 2 3 evil code [exit]
|C eg3 length qwertyuiop          ;# Returns 10
|
|
|# An example demonstrating the use of -unknown to do delegation
|# This uses an ensemble to add a subcommand to a frame
|package require Tk
|rename [frame .f] _impl.f
|namespace ensemble create -command .f -unknown {delegate _impl.f} -map {
|   flash {flashFrame _impl.f}
|}

|# General delegation framework handler
|proc delegate {target ensemble subcmd args} {
|   # Read the current map
|   set map [namespace ensemble configure $ensemble -map]
|   # Update it to include the new subcommand
|   dict set map $subcmd [list $target $subcmd]
|   # Install back into the ensemble
|   namespace ensemble configure $ensemble -map $map
|   # Result is empty string, so we reparse
|   return {}
|}

|# Our new subcommand implementation
|proc flashFrame w {
|   set bg [$w cget -background]
|   foreach colour {black white black white black white} {
|      $w configure -background $colour
|      update idletasks
|      after 150
|   }

|   $w configure -background $bg
|}


~ Consequences

Many commands in both Tcl and Tk would benefit from leveraging this,
and it would enable straight-forward implementations of things like
[65] in pure Tcl code.  It would also make doing things like partial
exposure of ensemble-like commands in safe interpreters much easier.

~ Sample Implementation

http://sf.net/tracker/?func=detail&aid=786509&group_id=10894&atid=310894

~ Copyright

This document has been placed in the public domain.

~ Acknowledgements

Thanks very much to Joe English, Don Porter and Kevin Kenny for their
suggestions in the development of this TIP.  Without them, it would have
been a far worse suggestion.  And thanks to Will Duquette for writing a
piece of software (Snit) that would benefit immensely from pushing the
ensemble stuff as hard as possible and then a bit.  :^)

<
|
<
|
|
|
|
|
|
|
>

|

|
|



|

|
|

|
|



|
|










|
|










|

|
|



|
|


|

|
|


|







|
|


|
|



|


|
|
|


|


|

|

|
|
|
|
|
|

|



|

|
|



|









|




|

|
|



|
|




|
|



|

|

|

|

|

|

|

|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
<
<
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
<
>
|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
<
|
>
|



|


|

|

|



|




|
|
>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

179
180
181
182
183
184
185
186



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209

210
211
212
213
214
215
216
217
218

219
220
221

222
223
224
225
226
227

228
229
230
231
232
233
234
235
236
237
238
239

240
241
242
243
244
245
246
247
248
249
250

251
252
253
254
255
256
257
258

259
260

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285

# TIP 112: Ensembles are Namespaces are Commands

	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        10-Oct-2002
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes unifying the concept of ensembles \(from [Incr
Tcl]\) with namespaces and commands.  It also adds control of command
rewriting to allow for more efficient support for object systems like
Snit.

# Rationale

Tcl's subcommand-style command collections \(e.g. _array_, _info_,
_string_, _interp_, etc.\) are a very intuitive and popular way of
structuring collections of related commands.  However, it is quite
awkward to write Tcl code that behaves that way.  Users of [Incr
Tcl] have access to ensembles which provide that, but it would be a
very useful feature for many other uses too.

At the same time, it is becoming clear that many applications want to
commonly refer to commands inside other namespaces directly \(instead
of through the [namespace import] mechanism\) but the syntax for
doing this is verbose and not as elegant as it might be.

I believe that the same solution can address these two problems in one
go, and make the language stronger and more usable for it.

Furthermore, by giving the programmer control over the mapping from
the ensemble subcommands to their implementing commands, we can build
a simple class system on the cheap since we can, in effect, import
commands from elsewhere into the ensemble.  By extending the mapping
so that it allows the specification of not just the implementing
command, but also some leading arguments to that command \(similar to
what you can do with the [interp alias] mechanism\) this becomes a
very powerful mechanism indeed.

Finally, a sophisticated extra capability is the addition of an unknown
subcommand callback to allow the creator of the ensemble to specify a
customized strategy for handling subcommands that are not recognized by
the ensemble machinery.  This allows an ensemble to be dynamically
updated to include those subcommands that the user asks for, which is
a potential route for doing things like using an ensemble as a wrapper
round a Tk widget.

# Proposed Change

I propose to add a new subcommand to the [namespace] command,
_ensemble_, that creates and manipulates the ensemble command for a
namespace.  Each namespace may have any number of ensemble commands
associated with it, with the default name of an ensemble command
being the fully-qualified name of the namespace itself, though it will
be legal to rename ensemble commands \(anyone wanting to track such
events should use the [trace] command.\)  Tcl will not create an
ensemble command for any namespace by default.

The [namespace ensemble] command will have the following subcommands:

 create: For creating a new ensemble for the _current_ namespace. The
   command takes a list of option value pairs \(as defined below\) to
   set the ensemble up with.  As stated above, the default command name
   is exactly the name of the namespace, but any other name may be
   supplied \(via the -command option\); if it does not start with a
   namespace separator, the name will be taken as being relative to
   the current namespace.  If another command with the same name exists,
   it is deleted as part of the creation of the ensemble.

 configure: For reading and writing the configuration of a particular
   ensemble.  The command takes an argument specifying the name of the
   ensemble to configure, and then works with either no extra arguments
   \(when it retrieves the entire ensemble configuration\), one extra
   argument \(the name of the option to retrieve\), or a list of option
   value pairs to configure the ensemble with.  This command returns an error if applied to anything that is not an ensemble.

 exists: This subcommand \(which takes a single argument\) tests whether
   a command \(with the given name\) exists and is an ensemble.  This command only returns an error if the wrong number of arguments are supplied.

The options available for creation and configuring are:

 -subcommands: This option \(if non-empty\) specifies a list of ensemble
   subcommands that the ensemble supports.  It does not need to be
   sorted.  Each command is mapped according to the dictionary in the
   _-map_ option \(if a non-empty map is present and the command has
   a mapping\) or to the correspondingly named command \(which is not
   required to exist at the time this is specified\) in the context
   namespace.

 -map: This option \(if non-empty\) specifies a dictionary that maps
   from ensemble subcommand names to lists of arguments to substitute
   into the ensemble invokation in place of the ensemble command name
   and the subcommand name.  See the _-subcommands_ option for the meaning
   of this option when that option is also non-empty.  If this option is
   empty and the _-subcommands_ option is empty too, the namespace will use
   the exported commands of the namespace as its command set, dynamically
   determining them \(subject to cacheing\) every time the ensemble is
   _invoked_.  Note that the words in the dictionary values that give
   the commands to map to \(as opposed to any arguments to them\) are
   always resolved \(if not absolute\) relative to the namespace which is
   running [namespace ensemble create] or [namespace ensemble
   configure].

 -prefixes: This boolean option \(which is on by default\) controls whether
   unambiguous prefixes of ensemble commands are recognized as if they
   were the fully specified ensemble command names.

 -unknown: This provides \(when non-empty\) a partial command to handle
   the case where an ensemble subcommand is not recognized and would
   otherwise generate an error.  When empty \(the default\) an error \(in
   the style of _Tcl\_GetIndexFromObj_\) is generated whenever the
   ensemble is unable to determine how to implement a particular
   subcommand.

 > See _Unknown Handler Behaviour_ below for details of how the
   ensemble interacts with its unknown handler.

Ensemble creation takes an extra option value pair:

 -command: This option allows you to override what the name of the
   ensemble to create is.

Ensemble configuring allows the querying of an extra read-only option:

 -namespace: This _read-only_ option allows the retrieval of the name
   of the namespace that the ensemble was created in.

Given an ensemble command created by the above mechanism, calling the
command will first of all match the subcommand to its implementing
command \(or command/argument list, as derived from the dictionary\) in
a manner that will be recognizably similar to that enforced by
_Tcl\_GetIndexFromObj\(\)_ \(unless the _-unknown_ option override this
behaviour.\)  For details of how the ensemble determines what its subcommands are, please see the _-subcommands_ and _-map_ options above.
Then the ensemble command will rewrite the command and arguments so
that the ensemble command and subcommand are replaced by the
implementing command and any specified arguments, with the resulting
word list being fed to _Tcl\_EvalObjv\(\)_ for execution.  Note that
this does not increase the stack depth in terms of [uplevel], and
that the implementing command may itself be an ensemble command.

Note that if the namespace for an ensemble is deleted, the ensemble will
also be deleted though there is no lifetime constraint in the other
direction \(i.e. using [rename $theEnsemble {}] will not cause the
namespace to vanish.\)  Obviously, any ensemble which has the global
namespace backing it up will have the same natural lifespan as the
hosting Tcl interpreter.

# Unknown Handler Behaviour

If an unknown handler is specified for an ensemble, that handler is called when the ensemble command would otherwise return an error due to it being unable to decide which subcommand to invoke.  The exact conditions under which that occurs are controlled by the _-subcommands_, _-map_ and _-prefixes_ options as described above.

To execute the unknown handler, the ensemble mechanism takes the specified -unknown option and appends each argument of the attempted ensemble command invocation \(including the ensemble command itself, expressed as a fully qualified name\). It invokes the resulting command in the scope of the attempted call. If the execution of the unknown handler terminates normally, the ensemble engine reparses the subcommand \(as described below\) and tries to dispatch it again, which is ideal for when the ensemble's configuration has been updated by the unknown subcommand handler.  Any other kind of termination of the unknown handler is treated as an error.

The result of the unknown handler is expected to be a list \(it is an error if it is not\).  If the list is an empty list, the ensemble command attempts to look up the original subcommand again and, if it is not found this time, an error will be generated just as if the -unknown handler was not there \(i.e. for any particular invokation of an ensemble, its unknown handler will be called at most once.\)  This makes it easy for the unknown handler to update the ensemble or its backing namespace so as to provide an implementation of the desired subcommand and reparse.

When the result is a non-empty list, the words of that list are used to replace the ensemble command and subcommand, just as if they had been looked up in the -map.  It is up to the unknown handler to supply all namespace qualifiers if the implementing subcommand is not in the namespace of the caller of the ensemble command.  Also note that when ensemble commands are chained \(e.g. if you make one of the commands that implement an ensemble subcommand into an ensemble, in a manner similar to the text widget's _tag_ and _mark_ subcommands\) then the rewrite happens in the context of the caller of the outermost ensemble.  That is to say that ensembles do not in themselves place any namespace contexts on the Tcl call stack.

Where an empty -unknown handler is given \(the default\), the ensemble command will generate an error message based on the list of commands that the ensemble has defined \(formatted similarly to the error message from _Tcl\_GetIndexFromObj\(\)_\).  This is the error that will be thrown when the subcommand is still not recognized during reparsing. It is also an error for an -unknown handler to delete its namespace.

# Examples

	namespace eval carrot {
	   namespace export foo bar potato
	   namespace ensemble create     ;# Creates command ::carrot
	
	   proc foo {} {puts 1}          ;# Exported
	   proc bar {} {puts 2}          ;# Exported
	   proc boo {} {puts 3}          ;# Not exported
	
	   namespace eval turnip {       ;# Not exported
	      namespace export alpha
	      proc alpha {} {puts 4}     ;# Exported
	      proc beta {} {puts 5}      ;# Not exported
	      namespace ensemble create

	   }
	
	   namespace eval potato {       ;# Exported
	      proc north {x} {puts 6,$x} ;# Not exported
	      proc south {x} {puts 7,$x} ;# Not exported
	      # Notice we resolve names locally, and Tcl metachars are not special
	      namespace ensemble create -map {
	         north {north [$meta[$chars}



	      }
	   }
	}
	
	
	carrot foo                       ;# Prints 1
	carrot bar                       ;# Prints 2
	carrot b                         ;# Also prints 2 ("boo" not exported)
	carrot ?                         ;# ERROR: Alternatives "bar", "foo" and "potato"
	carrot potato                    ;# ERROR: Missing argument
	carrot potato ?                  ;# ERROR: Try "north" instead
	carrot potato north              ;# Prints 6,[$meta[$chars
	carrot turnip alpha              ;# ERROR: "turnip" not known
	carrot::turnip alpha             ;# Prints 4
	carrot::turnip::beta             ;# Prints 5
	
	rename ::carrot::potato ::spud
	spud north                       ;# Prints 6,[$meta[$chars
	spud south                       ;# ERROR: "south" not known
	carrot potato north              ;# ERROR: No ::carrot::potato command
	# Reconfigure spud; notice we get different name resolution now!
	namespace ensemble configure spud -map {
	   north {puts NORTH} south {puts SOUTH}

	}
	spud north                       ;# Prints NORTH
	spud south                       ;# Prints SOUTH
	namespace delete carrot
	spud north                       ;# ERROR: spud command already deleted
	
	
	namespace eval A {
	   proc a args {puts A::a=>$args}

	}
	namespace eval B {
	   proc b args {puts B::b=>$args}

	}
	# Create an ensemble in the global namespace
	namespace ensemble create -command C -map {
	   eg1 {::A::a foo bar}
	   eg2 {::B::b 1 2 3}
	   eg3 ::string

	}
	C eg1 spong                      ;# Prints A::a=>foo bar spong
	C eg2 evil code {[exit]}         ;# Prints B::b=>1 2 3 evil code [exit]
	C eg3 length qwertyuiop          ;# Returns 10
	
	
	# An example demonstrating the use of -unknown to do delegation
	# This uses an ensemble to add a subcommand to a frame
	package require Tk
	rename [frame .f] _impl.f
	namespace ensemble create -command .f -unknown {delegate _impl.f} -map {
	   flash {flashFrame _impl.f}

	}
	# General delegation framework handler
	proc delegate {target ensemble subcmd args} {
	   # Read the current map
	   set map [namespace ensemble configure $ensemble -map]
	   # Update it to include the new subcommand
	   dict set map $subcmd [list $target $subcmd]
	   # Install back into the ensemble
	   namespace ensemble configure $ensemble -map $map
	   # Result is empty string, so we reparse
	   return {}

	}
	# Our new subcommand implementation
	proc flashFrame w {
	   set bg [$w cget -background]
	   foreach colour {black white black white black white} {
	      $w configure -background $colour
	      update idletasks
	      after 150

	   }
	   $w configure -background $bg

	}

# Consequences

Many commands in both Tcl and Tk would benefit from leveraging this,
and it would enable straight-forward implementations of things like
[[65]](65.md) in pure Tcl code.  It would also make doing things like partial
exposure of ensemble-like commands in safe interpreters much easier.

# Sample Implementation

<http://sf.net/tracker/?func=detail&aid=786509&group\_id=10894&atid=310894>

# Copyright

This document has been placed in the public domain.

# Acknowledgements

Thanks very much to Joe English, Don Porter and Kevin Kenny for their
suggestions in the development of this TIP.  Without them, it would have
been a far worse suggestion.  And thanks to Will Duquette for writing a
piece of software \(Snit\) that would benefit immensely from pushing the
ensemble stuff as hard as possible and then a bit.  :^\)

Name change from tip/113.tip to tip/113.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

TIP:            113
Title:          Multi-Line Searches in the Text Widget
Version:        $Revision: 1.13 $
Author:         Vince Darley <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        11-Oct-2002
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes enhancing the implementation of the ''$textwidget
search'' subcommand to allow matching of both exact strings and regexp
patterns which span multiple lines, and to allow reporting on all matches.

~ Proposal

If the string/pattern given to the ''search'' subcommand contains
sub-strings/patterns which match newlines, then it will be possible
for that command to return a match which spans multiple lines.  Where
a match could occur both within a single line and across multiple
lines, the first such match will be found, and the length of the match
will follow the usual regexp rules, as documented in the regexp man
page.  Since the text widget is inherently a line-based container of text, regexp searches will implicitly use the regexp ''-line'' functionality so that ''^'', ''$'' matching beginning and end of any line, and ''.'', ''[^'' will not match a newline (but see the ''-nolinestop'' flag to turn off the latter behaviour).

This can be implemented very efficiently, given
the ''TCL_REG_CANMATCH'' flag supported by the regexp library, with no
impact at all on the speed of matching single lines.

In addition, two new options to the ''search'' subcommand are available:

If the new ''-all'' option is given to the ''search'' subcommand, then all matches within the given range will be reported. This means the return result of the command will be a list of indices, and, if a ''-count var'' option was given, ''var'' will be set to a list of match-index-lengths.

If the new ''-nolinestop'' option is given then regexp searches will allow ''.'' and ''[^'' sequences to match newline characters (which is normally not the case).  This is equivalent to ''not'' providing the ''-linestop'' flag to Tcl's ''regexp'' command.

The text widget man page will be updated to reflect the new ''-all'' and ''-nolinestop'' options, and to remove the "single line" caveat.

~ Reference implementation

This is available from:

http://sourceforge.net/tracker/?func=detail&aid=621901&group_id=12997&atid=312997

The patch includes objectification of the entire Text widget, so the multi-line search changes are not obvious to isolate.  In fact the changes required are < 100 lines of code (given that the rest has been objectified, that is).  Of course one nice side-effect of objectification is that regexp objects used in searches are actually cached, which they previously couldn't be.

Note: this patch has to workaround a crashing bug in Tcl's unicode string manipulation.  It would be best if that bug was fixed before applying this patch.

~ Issues

On the implementation side, it might be interesting to abstract the search interface away from the text widget, so that it could in principle be applied to any line-based textual source.

As in the single-line matching implementation in Tcl 8.x, the lack of support for backwards matching in Tcl's regexp library means that backwards matching can only be implemented as repeated forward matches, with a commensurate performance penalty (the solution to which is outside the scope of this tip).

Tk has a curious misfeature that ''$text search -regexp "\n" $pos'' will always fail to match anything. This behaviour will change as a result of this TIP (it will match the first newline after ''$pos''), and any code which somehow depended on that peculiarity will therefore break.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|


|

|





|


|


|

|

|

|

|



|

|



|



|

|

|


>

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

# TIP 113: Multi-Line Searches in the Text Widget

	Author:         Vince Darley <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        11-Oct-2002
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes enhancing the implementation of the _$textwidget
search_ subcommand to allow matching of both exact strings and regexp
patterns which span multiple lines, and to allow reporting on all matches.

# Proposal

If the string/pattern given to the _search_ subcommand contains
sub-strings/patterns which match newlines, then it will be possible
for that command to return a match which spans multiple lines.  Where
a match could occur both within a single line and across multiple
lines, the first such match will be found, and the length of the match
will follow the usual regexp rules, as documented in the regexp man
page.  Since the text widget is inherently a line-based container of text, regexp searches will implicitly use the regexp _-line_ functionality so that _^_, _$_ matching beginning and end of any line, and _._, _[^_ will not match a newline \(but see the _-nolinestop_ flag to turn off the latter behaviour\).

This can be implemented very efficiently, given
the _TCL\_REG\_CANMATCH_ flag supported by the regexp library, with no
impact at all on the speed of matching single lines.

In addition, two new options to the _search_ subcommand are available:

If the new _-all_ option is given to the _search_ subcommand, then all matches within the given range will be reported. This means the return result of the command will be a list of indices, and, if a _-count var_ option was given, _var_ will be set to a list of match-index-lengths.

If the new _-nolinestop_ option is given then regexp searches will allow _._ and _[^_ sequences to match newline characters \(which is normally not the case\).  This is equivalent to _not_ providing the _-linestop_ flag to Tcl's _regexp_ command.

The text widget man page will be updated to reflect the new _-all_ and _-nolinestop_ options, and to remove the "single line" caveat.

# Reference implementation

This is available from:

<http://sourceforge.net/tracker/?func=detail&aid=621901&group\_id=12997&atid=312997>

The patch includes objectification of the entire Text widget, so the multi-line search changes are not obvious to isolate.  In fact the changes required are < 100 lines of code \(given that the rest has been objectified, that is\).  Of course one nice side-effect of objectification is that regexp objects used in searches are actually cached, which they previously couldn't be.

Note: this patch has to workaround a crashing bug in Tcl's unicode string manipulation.  It would be best if that bug was fixed before applying this patch.

# Issues

On the implementation side, it might be interesting to abstract the search interface away from the text widget, so that it could in principle be applied to any line-based textual source.

As in the single-line matching implementation in Tcl 8.x, the lack of support for backwards matching in Tcl's regexp library means that backwards matching can only be implemented as repeated forward matches, with a commensurate performance penalty \(the solution to which is outside the scope of this tip\).

Tk has a curious misfeature that _$text search -regexp "\\n" $pos_ will always fail to match anything. This behaviour will change as a result of this TIP \(it will match the first newline after _$pos_\), and any code which somehow depended on that peculiarity will therefore break.

# Copyright

This document has been placed in the public domain.

Name change from tip/114.tip to tip/114.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

161
162
163
164
165
166
167
168
169
170
171
172
173

174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206

TIP:            114
Title:          Eliminate Octal Parsing of Leading Zero Integer Strings
Author:         Don Porter <[email protected]>
Created:        16-Oct-2007
Type:           Project
State:          Draft
Vote:           Done
Version:        $Revision: 2.3 $
Tcl-Version:    9.0
Post-History:   
Keywords:       octal


~Abstract

This TIP proposes elimination of Tcl's practice of using octal
notation to interpret a string with a leading zero when an
integer value is expected.

~History and Rationale

There are several places in the syntax of several Tcl commands
where an integer value may be accepted.  Routines such as
'''Tcl_GetInt()''' perform the task of parsing an integer value
from the string value in these places.  Ultimately, these routines
have been built on C standard library functions such as
'''strtol()'''.  Due to this implementation choice, Tcl integer
parsing has inherited features from '''strtol()''' including
the feature that a leading zero in a string has been taken
as a signal that the string is an integer value in octal format.

Several programmers and programs have hit this feature by
surprise, resulting in nasty bugs such as:

| % proc m date {
|      lassign [split $date -] y m d
|      return [string index _JFMAMJJASOND $m]
|   }

| % m 2007-02-14
| F

| % m 2007-12-25
| D

| % m 2007-09-26
| bad index "09": must be integer?[+-]integer? or end?[+-]integer? (looks like invalid octal number)

There are very few places in Tcl scripts where this feature
is actually useful.  Octal format for integers simply isn't
encountered all that often in most programming tasks tackled by
Tcl scripts.  The main counterexample is the use of octal format
integers to describe filesystem permissions on unix systems.
The Tcl commands that operate on filesystem permission values
are '''open''' and '''file attributes''', and it is a simple matter
to directly code them to recognize octal format, rather that have
then rely on octal parsing as a general integer value recognition
feature.  On the HEAD, these commands have already been so revised.
With those few cases accounted for, it's been observed that
removing this feature of Tcl integer parsing "will likely fix
more scripts than it breaks."

The opportunity to make this change in Tcl 8.5 arises because
we've already replaced our old parsing routines based on
'''strtol()'''  with our own number parser [249].

~ Proposal

Revise all integer parsing in Tcl by making modifications to
the '''TclParseNumber()''' routine.  With reference to the
state machine graph in [249], we change the exit edges of
state ''integer[[1]]''.  Characters '''0''' - '''7''' and
characters '''8''' - '''9''' should now lead to state ''integer[[4]]'',
so that they continue decimal parsing, and not octal parsing.
The states ''integer[[2]]'' and ''error[[5]]'' will now be
accessible only if the character '''o''' or '''O''' is seen
while in state ''integer[[1]]'' and there will no longer be
any exit from those states when the characters '''.''' or '''e'''
or '''E''' are observed.

This change to '''TclParseNumber()''' is achieved with a
'''#define KILL_OCTAL''' in the file ''tclStrToD.c''.

~ Compatibility

This change is an incompatibility.  It's long
been believed that such a change should not happen until Tcl 9
because of this, but over time the consensus belief has developed
that far fewer programs and programmers will be harmed by the
incompatibility than will be helped by removing the misfeature.

That said, the incompatibility is serious.  The same string in
the same place in a script can now have a completely different
meaning.  Before the change:

| % lindex {a b c d e f g h i j k} 010
| i


After the change:

| % lindex {a b c d e f g h i j k} 010
| k


This is not the usual situation where new feature causes scripts
that were an error to become non-errors -- a compatible change.

This is also not a situation where a change causes legal scripts
to become errors.  Such a change would break scripts, but would
at least leave behind scripts that raise noisy errors alerting
about the breakage.

This is the most serious kind of incompatibility, where we replace
a working script with another working script that does something
completely different.  An illustration of the problem from Tcl's
own test suite highlights the danger.  Some of Tcl's tests in
'''io.test''' depend on the umask value, so that value is captured:

| set umaskValue [exec /bin/sh -c umask]

Note that the shell command '''umask''' returns a mask value as
an integer in octal format.  The test suite has relied on Tcl's
built-in ability to recognize this format, and the expected
result of test '''io-40.3''' has been computed:

| format %04o [expr {0666 & ~$umaskValue}]

After the proposed change, ''$umaskValue'' is treated as a decimal
number, and the wrong expected result is computed.  (This test
has already been updated on the HEAD to avoid such problems.)

It is not difficult to imagine more serious problems in scripts
that make use of the result returned by the shell command '''umask'''
where a file might be created or modified with completely unintended
permissions as a result of the proposed change.  Such scripts
might easily raise security concerns.

Even in the light of the judgment that such (hopefully rare) compatibility
issues are acceptable in exchange for the benefits of purging the
misfeature, we really ought to consider seriously how we can alert
those migrating to Tcl 8.5 to this possibility and to the need to
examine their scripts for this issue.

Besides the impact on Tcl commands, this change may also cause
incompatibilities in extensions, to the extent their commands
rely on Tcl's integer parsing to support octal notation.

~ Rejected Alternatives

Motivated largely by the serious incompatibilities lurking here,
a few people have suggested that some means be provided to toggle
Tcl's integer parsing behavior between two modes, one which
recognizes octal and one which does not.  This idea appears inspired
in part by the '''::tcl_precision''' variable, which has long
exercised control over Tcl's floating point number formatting.

While the motivation may be well-intended, this proposal is basically
unworkable, and can't really help anybody.  The point of the proposed
change is to make simple code work as simple coders expect it to.
Our original example proc can already be corrected like so:

| proc m date {
|    scan $date %d-%d-%d y m d
|    return [string index _JFMAMJJASOND $m]
| }


The point of this proposal is to make the original code just work.
It doesn't help to offer this complexity as a solution:

| % proc m date {
|      set mode [tcl::unsupported::octal]
|      tcl::unsupported::octal off
|      lassign [split $date -] y m d
|      set result [string index _JFMAMJJASOND $m]
|      tcl::unsupported::octal $mode
|      return $result
|   }


No one would choose that over just fixing the code
to use '''scan''', in which case this proposal won't be needed.
Also, this kind of management of a shared mode setting cannot
(easily and cheaply) be avoided, because at the point we need
to control the Tcl number parser, the most specific context
we have is the thread, so the mode has to be set thread-wide.

Likewise, the (hopefully rare) set of scripts that would actually
want to turn octal parsing back on are not going to announce themselves.
In order to know that 

| tcl::unsupported::octal on

needs to be added to a script to make it function correctly,
some kind of audit has to reach that conclusion, and once that
conclusion is reached and the issues are understood, it's just
as easy to insert '''scan %o''' in the proper places as it would
be to insert the '''tcl::unsupported::octal''' stopgap.

In short, any coder finding themselves in a position to consider
using a '''tcl::unsupported::octal''' tool, would quickly decide
not to use it in favor of just fixing their code.  Thus users
of this feature are mythical, and it will not be implemented.

~ Note

This TIP has been ''explicitly'' rejected as a feature for Tcl 8.5.
Consensus was that the type of breakage it inherently induces is not
acceptable in a minor version change.

~Copyright

This document is placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|





|



|


|
|






|
|
|
<
>
|
<
>
|
<
>
|
|







|









|

|


|
|
|
|

|
|
|
|
|

|
|

|











|
<
>



|
<
>













|

|

|


|

|

|
|
|


|




|









|





|







|
|
|
<
>




|
|
|
|
|
|
|
<
|
>

|

|



|



|




|
|


|



|

|



|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

159
160
161
162
163
164
165
166
167
168
169
170

171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206

# TIP 114: Eliminate Octal Parsing of Leading Zero Integer Strings
	Author:         Don Porter <[email protected]>
	Created:        16-Oct-2007
	Type:           Project
	State:          Draft
	Vote:           Done

	Tcl-Version:    9.0
	Post-History:   
	Keywords:       octal
-----

# Abstract

This TIP proposes elimination of Tcl's practice of using octal
notation to interpret a string with a leading zero when an
integer value is expected.

# History and Rationale

There are several places in the syntax of several Tcl commands
where an integer value may be accepted.  Routines such as
**Tcl\_GetInt\(\)** perform the task of parsing an integer value
from the string value in these places.  Ultimately, these routines
have been built on C standard library functions such as
**strtol\(\)**.  Due to this implementation choice, Tcl integer
parsing has inherited features from **strtol\(\)** including
the feature that a leading zero in a string has been taken
as a signal that the string is an integer value in octal format.

Several programmers and programs have hit this feature by
surprise, resulting in nasty bugs such as:

	 % proc m date {
	      lassign [split $date -] y m d
	      return [string index _JFMAMJJASOND $m]

	   }
	 % m 2007-02-14

	 F
	 % m 2007-12-25

	 D
	 % m 2007-09-26
	 bad index "09": must be integer?[+-]integer? or end?[+-]integer? (looks like invalid octal number)

There are very few places in Tcl scripts where this feature
is actually useful.  Octal format for integers simply isn't
encountered all that often in most programming tasks tackled by
Tcl scripts.  The main counterexample is the use of octal format
integers to describe filesystem permissions on unix systems.
The Tcl commands that operate on filesystem permission values
are **open** and **file attributes**, and it is a simple matter
to directly code them to recognize octal format, rather that have
then rely on octal parsing as a general integer value recognition
feature.  On the HEAD, these commands have already been so revised.
With those few cases accounted for, it's been observed that
removing this feature of Tcl integer parsing "will likely fix
more scripts than it breaks."

The opportunity to make this change in Tcl 8.5 arises because
we've already replaced our old parsing routines based on
**strtol\(\)**  with our own number parser [[249]](249.md).

# Proposal

Revise all integer parsing in Tcl by making modifications to
the **TclParseNumber\(\)** routine.  With reference to the
state machine graph in [[249]](249.md), we change the exit edges of
state _integer[[1]](1.md)_.  Characters **0** - **7** and
characters **8** - **9** should now lead to state _integer[[4]](4.md)_,
so that they continue decimal parsing, and not octal parsing.
The states _integer[[2]](2.md)_ and _error[[5]](5.md)_ will now be
accessible only if the character **o** or **O** is seen
while in state _integer[[1]](1.md)_ and there will no longer be
any exit from those states when the characters **.** or **e**
or **E** are observed.

This change to **TclParseNumber\(\)** is achieved with a
**\#define KILL\_OCTAL** in the file _tclStrToD.c_.

# Compatibility

This change is an incompatibility.  It's long
been believed that such a change should not happen until Tcl 9
because of this, but over time the consensus belief has developed
that far fewer programs and programmers will be harmed by the
incompatibility than will be helped by removing the misfeature.

That said, the incompatibility is serious.  The same string in
the same place in a script can now have a completely different
meaning.  Before the change:

	 % lindex {a b c d e f g h i j k} 010

	 i

After the change:

	 % lindex {a b c d e f g h i j k} 010

	 k

This is not the usual situation where new feature causes scripts
that were an error to become non-errors -- a compatible change.

This is also not a situation where a change causes legal scripts
to become errors.  Such a change would break scripts, but would
at least leave behind scripts that raise noisy errors alerting
about the breakage.

This is the most serious kind of incompatibility, where we replace
a working script with another working script that does something
completely different.  An illustration of the problem from Tcl's
own test suite highlights the danger.  Some of Tcl's tests in
**io.test** depend on the umask value, so that value is captured:

	 set umaskValue [exec /bin/sh -c umask]

Note that the shell command **umask** returns a mask value as
an integer in octal format.  The test suite has relied on Tcl's
built-in ability to recognize this format, and the expected
result of test **io-40.3** has been computed:

	 format %04o [expr {0666 & ~$umaskValue}]

After the proposed change, _$umaskValue_ is treated as a decimal
number, and the wrong expected result is computed.  \(This test
has already been updated on the HEAD to avoid such problems.\)

It is not difficult to imagine more serious problems in scripts
that make use of the result returned by the shell command **umask**
where a file might be created or modified with completely unintended
permissions as a result of the proposed change.  Such scripts
might easily raise security concerns.

Even in the light of the judgment that such \(hopefully rare\) compatibility
issues are acceptable in exchange for the benefits of purging the
misfeature, we really ought to consider seriously how we can alert
those migrating to Tcl 8.5 to this possibility and to the need to
examine their scripts for this issue.

Besides the impact on Tcl commands, this change may also cause
incompatibilities in extensions, to the extent their commands
rely on Tcl's integer parsing to support octal notation.

# Rejected Alternatives

Motivated largely by the serious incompatibilities lurking here,
a few people have suggested that some means be provided to toggle
Tcl's integer parsing behavior between two modes, one which
recognizes octal and one which does not.  This idea appears inspired
in part by the **::tcl\_precision** variable, which has long
exercised control over Tcl's floating point number formatting.

While the motivation may be well-intended, this proposal is basically
unworkable, and can't really help anybody.  The point of the proposed
change is to make simple code work as simple coders expect it to.
Our original example proc can already be corrected like so:

	 proc m date {
	    scan $date %d-%d-%d y m d
	    return [string index _JFMAMJJASOND $m]

	 }

The point of this proposal is to make the original code just work.
It doesn't help to offer this complexity as a solution:

	 % proc m date {
	      set mode [tcl::unsupported::octal]
	      tcl::unsupported::octal off
	      lassign [split $date -] y m d
	      set result [string index _JFMAMJJASOND $m]
	      tcl::unsupported::octal $mode
	      return $result

	   }

No one would choose that over just fixing the code
to use **scan**, in which case this proposal won't be needed.
Also, this kind of management of a shared mode setting cannot
\(easily and cheaply\) be avoided, because at the point we need
to control the Tcl number parser, the most specific context
we have is the thread, so the mode has to be set thread-wide.

Likewise, the \(hopefully rare\) set of scripts that would actually
want to turn octal parsing back on are not going to announce themselves.
In order to know that 

	 tcl::unsupported::octal on

needs to be added to a script to make it function correctly,
some kind of audit has to reach that conclusion, and once that
conclusion is reached and the issues are understood, it's just
as easy to insert **scan %o** in the proper places as it would
be to insert the **tcl::unsupported::octal** stopgap.

In short, any coder finding themselves in a position to consider
using a **tcl::unsupported::octal** tool, would quickly decide
not to use it in favor of just fixing their code.  Thus users
of this feature are mythical, and it will not be implemented.

# Note

This TIP has been _explicitly_ rejected as a feature for Tcl 8.5.
Consensus was that the type of breakage it inherently induces is not
acceptable in a minor version change.

# Copyright

This document is placed in the public domain.

Name change from tip/115.tip to tip/115.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

TIP:            115
Title:          Making Tcl Truly 64-Bit Ready
Version:        $Revision: 1.3 $
Author:         Donal K. Fellows <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        23-Oct-2002
Post-History:   
Tcl-Version:    9.0


~ Abstract

This TIP proposes changes to Tcl to make it operate more effectively
on 64-bit systems.

~ Rationale

It is a fact of life that 64-bit platforms are becoming more common.
While once the assumption that virtually everything was a 32-bit
machine (where not smaller) was valid, this is no longer the case.
Particularly on modern supercomputers (though increasingly in
workstations and high-end desktop systems too), the amount of memory
that the machine contains is exceeding 2GB, and the need to address
very large amounts of memory is certainly there in scientific and
engineering applications.  And where they lead, consumer systems will
probably follow too.

At the moment, Tcl is ill-prepared for this.  In particular, the type
used for expressing sizes of entities in Tcl (whether strings, lists
or undifferentiated blocks of memory) is ''int'' (and cannot be made
into an ''unsigned int'' in most of those places where it is not
already an unsigned value) but on the majority of 64-bit platforms
this is still a 32-bit type, which is a major restriction.  However,
on the vast majority of those platforms ''long'' is a 64-bit type, and
so a suitable replacement.  (The exceptions to this are the Alpha - but
that is unusual in that both ''int'' and ''long'' are 64-bit types
there, meaning that the platform will be unaffected by such an
alteration - and Win64, which has a 32-bit ''long'' but 64-bit
pointers.)

Luckily, standards like POSIX have already been dealing with this
problem before us, and the types ''size_t'' (which is unsigned) and
''ssize_t'' (which is signed) exist for the sorts of uses we're
interested in (i.e. they are both the same size as each other, and
''size_t'' is large enough to describe the size of any allocatable
memory chunk.)

~ Details of Changes

The key changes will be to change the lengths of the following types
from ''int'' to ''ssize_t'' in all appropriate places, and ''unsigned
int'' to ''size_t'' likewise (mainly in memory allocation routines.)

 * ''Tcl_Obj'' - the ''length'' member.  (Potentially the ''refCount''
   member needs updating as well, but that's less critical.)

 * ''Tcl_SavedResult'' - the ''appendAvl'' and ''appendUsed'' members.

 * ''Tcl_DString'' - the ''length'' and ''spaceAvl'' members.

 * ''Tcl_Token'' - the ''size'' and ''numComponents'' members.

 * ''Tcl_Parse'' - the ''commentSize'', ''commandSize'', numWords'',
   ''numTokens'' and ''tokensAvailable'' members.

 * ''CompiledLocal'' - the ''nameLength'' member.

 * ''Interp'' - the ''appendAvl'', ''appendUsed'' and ''termOffset''
   members.

 * ''List'' - the ''maxElemCount'' and ''elemCount'' members.

 * ''ByteArray'' - the ''used'' and ''allocated'' members.

 * ''SortElement'' - the ''count'' member.

 * ''SortInfo'' - the ''index'' member.

 * ''CopyState'' - the ''toRead'' and ''total'' members.

 * ''GetsState'' - the ''rawRead'', ''bytesWrote'', ''charsWrote'' and
   ''totalChars'' members.

 * ''ParseInfo'' - the ''size'' member.

 * ''String'' - the ''numChars'' member (see also the ''TestString''
   structure.)

Changes to the bytecode-related structures might be worthwhile doing
too, though there are more backward-compatibility issues there.

These changes will force many of the types used in the public API to
change as well.  Notable highlights:

 * ''Tcl_Alloc'' will now take an ''size_t''.

 * ''Tcl_GetByteArrayFromObj'' will now take a pointer to a ''ssize_t''.

 * ''Tcl_GetStringFromObj'' will now take a pointer to a ''ssize_t''.

 * ''Tcl_ListObjLength'' will now take a pointer to a ''ssize_t''.

 * ''Tcl_GetUnicodeFromObj'' will now take a pointer to a ''ssize_t''.

In the internal API, the following notable change will happen:

 * ''TclGetIntForIndex'' will now take a pointer to a ''ssize_t''.

There are probably other similar API changes required.

~ What This TIP Does Not Do

This TIP does not rearrange structure orderings.  Although this would
be very useful for some common structures (notably ''Tcl_Obj'') if the
common arithmetic types were smaller than the word size, it turns out
that the changes in types required to deal with larger entities will
make these rearrangements largely unnecessary and/or pointless.
(Inefficiency in statically-allocated structures won't matter as the
number of instances will remain comparatively small, even in very
large programs.)  Once the changes are applied, there is typically at
most a single ''int'' field per structure, usually holding either a
reference count, a set of flags, or a Tcl result code.

It should also be noted that all structures are always going to be
correctly aligned internally as we never use C's bitfield support, so
structure alignment is purely an issue of efficiency, and not of correct
access to the fields.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|




|



|
|
|






|
|
|
|

|
|
|

|
|


|
|
|
|
|

|


|
|

|
|

|

|

|

|
|

|

|


|

|

|

|

|

|
|

|

|
|







|

|

|

|

|



|



|


|



|

|
|







|


>

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

# TIP 115: Making Tcl Truly 64-Bit Ready

	Author:         Donal K. Fellows <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        23-Oct-2002
	Post-History:   
	Tcl-Version:    9.0
-----

# Abstract

This TIP proposes changes to Tcl to make it operate more effectively
on 64-bit systems.

# Rationale

It is a fact of life that 64-bit platforms are becoming more common.
While once the assumption that virtually everything was a 32-bit
machine \(where not smaller\) was valid, this is no longer the case.
Particularly on modern supercomputers \(though increasingly in
workstations and high-end desktop systems too\), the amount of memory
that the machine contains is exceeding 2GB, and the need to address
very large amounts of memory is certainly there in scientific and
engineering applications.  And where they lead, consumer systems will
probably follow too.

At the moment, Tcl is ill-prepared for this.  In particular, the type
used for expressing sizes of entities in Tcl \(whether strings, lists
or undifferentiated blocks of memory\) is _int_ \(and cannot be made
into an _unsigned int_ in most of those places where it is not
already an unsigned value\) but on the majority of 64-bit platforms
this is still a 32-bit type, which is a major restriction.  However,
on the vast majority of those platforms _long_ is a 64-bit type, and
so a suitable replacement.  \(The exceptions to this are the Alpha - but
that is unusual in that both _int_ and _long_ are 64-bit types
there, meaning that the platform will be unaffected by such an
alteration - and Win64, which has a 32-bit _long_ but 64-bit
pointers.\)

Luckily, standards like POSIX have already been dealing with this
problem before us, and the types _size\_t_ \(which is unsigned\) and
_ssize\_t_ \(which is signed\) exist for the sorts of uses we're
interested in \(i.e. they are both the same size as each other, and
_size\_t_ is large enough to describe the size of any allocatable
memory chunk.\)

# Details of Changes

The key changes will be to change the lengths of the following types
from _int_ to _ssize\_t_ in all appropriate places, and _unsigned
int_ to _size\_t_ likewise \(mainly in memory allocation routines.\)

 * _Tcl\_Obj_ - the _length_ member.  \(Potentially the _refCount_
   member needs updating as well, but that's less critical.\)

 * _Tcl\_SavedResult_ - the _appendAvl_ and _appendUsed_ members.

 * _Tcl\_DString_ - the _length_ and _spaceAvl_ members.

 * _Tcl\_Token_ - the _size_ and _numComponents_ members.

 * _Tcl\_Parse_ - the _commentSize_, _commandSize_, numWords_,
   _numTokens_ and _tokensAvailable_ members.

 * _CompiledLocal_ - the _nameLength_ member.

 * _Interp_ - the _appendAvl_, _appendUsed_ and _termOffset_
   members.

 * _List_ - the _maxElemCount_ and _elemCount_ members.

 * _ByteArray_ - the _used_ and _allocated_ members.

 * _SortElement_ - the _count_ member.

 * _SortInfo_ - the _index_ member.

 * _CopyState_ - the _toRead_ and _total_ members.

 * _GetsState_ - the _rawRead_, _bytesWrote_, _charsWrote_ and
   _totalChars_ members.

 * _ParseInfo_ - the _size_ member.

 * _String_ - the _numChars_ member \(see also the _TestString_
   structure.\)

Changes to the bytecode-related structures might be worthwhile doing
too, though there are more backward-compatibility issues there.

These changes will force many of the types used in the public API to
change as well.  Notable highlights:

 * _Tcl\_Alloc_ will now take an _size\_t_.

 * _Tcl\_GetByteArrayFromObj_ will now take a pointer to a _ssize\_t_.

 * _Tcl\_GetStringFromObj_ will now take a pointer to a _ssize\_t_.

 * _Tcl\_ListObjLength_ will now take a pointer to a _ssize\_t_.

 * _Tcl\_GetUnicodeFromObj_ will now take a pointer to a _ssize\_t_.

In the internal API, the following notable change will happen:

 * _TclGetIntForIndex_ will now take a pointer to a _ssize\_t_.

There are probably other similar API changes required.

# What This TIP Does Not Do

This TIP does not rearrange structure orderings.  Although this would
be very useful for some common structures \(notably _Tcl\_Obj_\) if the
common arithmetic types were smaller than the word size, it turns out
that the changes in types required to deal with larger entities will
make these rearrangements largely unnecessary and/or pointless.
\(Inefficiency in statically-allocated structures won't matter as the
number of instances will remain comparatively small, even in very
large programs.\)  Once the changes are applied, there is typically at
most a single _int_ field per structure, usually holding either a
reference count, a set of flags, or a Tcl result code.

It should also be noted that all structures are always going to be
correctly aligned internally as we never use C's bitfield support, so
structure alignment is purely an issue of efficiency, and not of correct
access to the fields.

# Copyright

This document has been placed in the public domain.

Name change from tip/116.tip to tip/116.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

TIP:            116
Title:          More Safety for Large Images
Version:        $Revision: 1.6 $
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        28-Oct-2002
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP alters the C API for Tk's images so that failures to allocate
sufficient memory for a large image can be handled more gracefully
than a straight ''panic()''.

~ Rationale

Tk's image mechanism is nice and flexible, but it can run into
problems with a large image.  If we consider a square image that is
2000 pixels on each side (such sizes of images are becoming more
common with the increasing popularity and sophistication of digital
photography), we find it requires about 16MB of memory to load (4
million pixels, four bytes per pixel) but obviously just because an
application fails to load that image (or something even larger), it
doesn't mean that the best course of action is a ''panic()''-induced
crash.  Instead, a graceful failure back to the Tcl interpreter would
allow for scripts to find a way to report this low-memory situation in
a way that users can understand.

The problem with this is that for many of the routes through the Tk
image API, there is no way to report a memory allocation failure;
currently, the only failure mode is total.  This TIP changes this.

~ Proposed Changes

I propose making the following functions that currently return
''void'' return ''int'' instead and that they should additionally take
a standard ''Tcl_Interp *interp'' argument to allow an error message
describing the failure (currently only due to insufficient memory) to
be added to the current interpreter.  It will not be an error for the
''interp'' argument to be ''NULL'', though it will be up to the caller
to guess why the failure happened.

 * ''Tk_PhotoExpand'' will become:

|int
|Tk_PhotoExpand(Tcl_Interp *interp, Tk_PhotoHandle handle,
|               int width, int height)

 * ''Tk_PhotoPutBlock'' will become:

|int
|Tk_PhotoPutBlock(Tcl_Interp *interp, Tk_PhotoHandle handle,
|                 Tk_PhotoImageBlock *blockPtr,
|                 int x, int y, int width, int height, int compRule)

 * ''Tk_PhotoPutZoomedBlock'' will become:

|int
|Tk_PhotoPutZoomedBlock(Tcl_Interp *interp, Tk_PhotoHandle handle,
|                       Tk_PhotoImageBlock *blockPtr,
|                       int x, int y, int width, int height,
|                       int zoomX, int zoomY, int subsampleX, int subsampleY,
|                       int compRule)

 * ''Tk_PhotoSetSize'' will become:

|int
|Tk_PhotoSetSize(Tcl_Interp *interp, Tk_PhotoHandle handle,
|                int width, int height)

Also note that as a consequence of this, some image-related Tk
commands will also gain additional error return situations.  Since
these all trigger abnormal process termination (and potentially a
core-dump too) at the moment, this change in behaviour is believed to
be wholly beneficial.

~ Backward Compatibility

This TIP also proposes a backward compatibility interface, so that
extensions need not be heavily modified to work with new versions of
Tk.  This is done by leaving backwardly-compatible functions in the
old locations in Tk's stub table and adding a ''#define'' to allow
selection of the old API with the standard names.  I propose doing this
when the symbol ''USE_PANIC_ON_PHOTO_ALLOC_FAILURE'' is defined; like
this, extension authors can switch from compiling with Tk 8.4 to using
later versions by adding just one flag to their makefile (or other build
script/environment.)

Note that this interacts with the backward-compatability interface
defined in [98]; if that is enabled, the back-compat interface defined
here is enabled as well.

~ Sample Implementation

http://sf.net/tracker/?func=detail&aid=646382&group_id=12997&atid=312997

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|



|

|



|

|
|
|
|








|


|
|
|

|


|

|
|
|

|

|
|
|
|

|

|
|
|
|
|
|

|

|
|
|



|
|


|




|

|

|
|


|


|

|

|


>

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

# TIP 116: More Safety for Large Images

	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        28-Oct-2002
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP alters the C API for Tk's images so that failures to allocate
sufficient memory for a large image can be handled more gracefully
than a straight _panic\(\)_.

# Rationale

Tk's image mechanism is nice and flexible, but it can run into
problems with a large image.  If we consider a square image that is
2000 pixels on each side \(such sizes of images are becoming more
common with the increasing popularity and sophistication of digital
photography\), we find it requires about 16MB of memory to load \(4
million pixels, four bytes per pixel\) but obviously just because an
application fails to load that image \(or something even larger\), it
doesn't mean that the best course of action is a _panic\(\)_-induced
crash.  Instead, a graceful failure back to the Tcl interpreter would
allow for scripts to find a way to report this low-memory situation in
a way that users can understand.

The problem with this is that for many of the routes through the Tk
image API, there is no way to report a memory allocation failure;
currently, the only failure mode is total.  This TIP changes this.

# Proposed Changes

I propose making the following functions that currently return
_void_ return _int_ instead and that they should additionally take
a standard _Tcl\_Interp \*interp_ argument to allow an error message
describing the failure \(currently only due to insufficient memory\) to
be added to the current interpreter.  It will not be an error for the
_interp_ argument to be _NULL_, though it will be up to the caller
to guess why the failure happened.

 * _Tk\_PhotoExpand_ will become:

		int
		Tk_PhotoExpand(Tcl_Interp *interp, Tk_PhotoHandle handle,
		               int width, int height)

 * _Tk\_PhotoPutBlock_ will become:

		int
		Tk_PhotoPutBlock(Tcl_Interp *interp, Tk_PhotoHandle handle,
		                 Tk_PhotoImageBlock *blockPtr,
		                 int x, int y, int width, int height, int compRule)

 * _Tk\_PhotoPutZoomedBlock_ will become:

		int
		Tk_PhotoPutZoomedBlock(Tcl_Interp *interp, Tk_PhotoHandle handle,
		                       Tk_PhotoImageBlock *blockPtr,
		                       int x, int y, int width, int height,
		                       int zoomX, int zoomY, int subsampleX, int subsampleY,
		                       int compRule)

 * _Tk\_PhotoSetSize_ will become:

		int
		Tk_PhotoSetSize(Tcl_Interp *interp, Tk_PhotoHandle handle,
		                int width, int height)

Also note that as a consequence of this, some image-related Tk
commands will also gain additional error return situations.  Since
these all trigger abnormal process termination \(and potentially a
core-dump too\) at the moment, this change in behaviour is believed to
be wholly beneficial.

# Backward Compatibility

This TIP also proposes a backward compatibility interface, so that
extensions need not be heavily modified to work with new versions of
Tk.  This is done by leaving backwardly-compatible functions in the
old locations in Tk's stub table and adding a _\#define_ to allow
selection of the old API with the standard names.  I propose doing this
when the symbol _USE\_PANIC\_ON\_PHOTO\_ALLOC\_FAILURE_ is defined; like
this, extension authors can switch from compiling with Tk 8.4 to using
later versions by adding just one flag to their makefile \(or other build
script/environment.\)

Note that this interacts with the backward-compatability interface
defined in [[98]](98.md); if that is enabled, the back-compat interface defined
here is enabled as well.

# Sample Implementation

<http://sf.net/tracker/?func=detail&aid=646382&group\_id=12997&atid=312997>

# Copyright

This document has been placed in the public domain.

Name change from tip/117.tip to tip/117.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

TIP:            117
Title:          Object Type Introspection
Version:        $Revision: 1.9 $
Author:         Peter Spjuth <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        01-Nov-2002
Post-History:   
Tcl-Version:    8.5
Obsoleted-By:	214


~ Abstract

This TIP proposes to add a command to give information
on the current internal representation of an object.

~ Rationale

When trying to understand the internals of objects and when trying to
track down shimmering problems it is very helpful to be able to see
what type an object currently has.

~ Specification

A new package called "Debug" is created as part of the core.

A new command, ''objtype'', is added to the Debug package.
The command has the syntax:

 > '''Debug::objtype''' ?''value''?

If no value is submitted, a list of all currently registered object
types are returned.

If a value is submitted, it returns a list where the first element
is the name of value's object type, or "none" if there is no
internal representation.  The second element is a boolean stating
if the object has a valid string representation.

Examples:

|% Debug::objtype
|boolean index double end-offset wideInt list cmdName bytecode
|nsName procbody bytearray int {array search} string
|% set apa hejsan
|hejsan
|% Debug::objtype $apa
|none 1
|% string length $apa
|6

|% Debug::objtype $apa
|string 1
|% regexp $apa hoppsan
|0

|% Debug::objtype $apa
|regexp 1
|% Debug::objtype [expr 1+1]
|int 0

~ Discussion

The first proposal was to add this as a subcommand to info.  This
was considered bad since this should be a pure debug command
and should never be used in live code.  Thus the proposition
came up to create a Debug package and put it in there to emphasise
its debug nature.  The Debug package can also be extended in the
future with other utilities.

~ Reference Implementation

|static int
|ObjTypeCmd(dummy, interp, objc, objv)
|    ClientData dummy;		/* Not used. */
|    Tcl_Interp *interp;	/* Current interpreter. */
|    int objc;			/* Number of arguments. */
|    Tcl_Obj *CONST objv[];	/* Argument objects. */
|{

|    Tcl_Obj *listPtr;
|
|    if ((objc != 2) && (objc != 3)) {
|        Tcl_WrongNumArgs(interp, 2, objv, "?value?");
|        return TCL_ERROR;
|    }

|
|    listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
|
|    if (objc == 2) {
|        Tcl_AppendAllObjTypes(interp, listPtr);
|    } else {
|        Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(
|                (objv[2]->typePtr != NULL) ? objv[2]->typePtr->name : "none", -1));
|        Tcl_ListObjAppendElement(interp, listPtr,
|                Tcl_NewBooleanObj(objv[2]->bytes != NULL));
|    }

|    Tcl_SetObjResult(interp, listPtr);
|    return TCL_OK;
|}


~ Future possibilities

For further object introspection the command can easily be 
extended by options.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|





|



|


|











|
|
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|

|








|

|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
<
>
|
|
<
|
>
|




|


>

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

# TIP 117: Object Type Introspection

	Author:         Peter Spjuth <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        01-Nov-2002
	Post-History:   
	Tcl-Version:    8.5
	Obsoleted-By:	214
-----

# Abstract

This TIP proposes to add a command to give information
on the current internal representation of an object.

# Rationale

When trying to understand the internals of objects and when trying to
track down shimmering problems it is very helpful to be able to see
what type an object currently has.

# Specification

A new package called "Debug" is created as part of the core.

A new command, _objtype_, is added to the Debug package.
The command has the syntax:

 > **Debug::objtype** ?_value_?

If no value is submitted, a list of all currently registered object
types are returned.

If a value is submitted, it returns a list where the first element
is the name of value's object type, or "none" if there is no
internal representation.  The second element is a boolean stating
if the object has a valid string representation.

Examples:

	% Debug::objtype
	boolean index double end-offset wideInt list cmdName bytecode
	nsName procbody bytearray int {array search} string
	% set apa hejsan
	hejsan
	% Debug::objtype $apa
	none 1
	% string length $apa

	6
	% Debug::objtype $apa
	string 1
	% regexp $apa hoppsan

	0
	% Debug::objtype $apa
	regexp 1
	% Debug::objtype [expr 1+1]
	int 0

# Discussion

The first proposal was to add this as a subcommand to info.  This
was considered bad since this should be a pure debug command
and should never be used in live code.  Thus the proposition
came up to create a Debug package and put it in there to emphasise
its debug nature.  The Debug package can also be extended in the
future with other utilities.

# Reference Implementation

	static int
	ObjTypeCmd(dummy, interp, objc, objv)
	    ClientData dummy;		/* Not used. */
	    Tcl_Interp *interp;	/* Current interpreter. */
	    int objc;			/* Number of arguments. */
	    Tcl_Obj *CONST objv[];	/* Argument objects. */

	{
	    Tcl_Obj *listPtr;
	
	    if ((objc != 2) && (objc != 3)) {
	        Tcl_WrongNumArgs(interp, 2, objv, "?value?");
	        return TCL_ERROR;

	    }
	
	    listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
	
	    if (objc == 2) {
	        Tcl_AppendAllObjTypes(interp, listPtr);
	    } else {
	        Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(
	                (objv[2]->typePtr != NULL) ? objv[2]->typePtr->name : "none", -1));
	        Tcl_ListObjAppendElement(interp, listPtr,
	                Tcl_NewBooleanObj(objv[2]->bytes != NULL));

	    }
	    Tcl_SetObjResult(interp, listPtr);
	    return TCL_OK;

	}

# Future possibilities

For further object introspection the command can easily be 
extended by options.

# Copyright

This document has been placed in the public domain.

Name change from tip/118.tip to tip/118.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191

TIP:            118
Title:          Enhance [file attributes] and [file copy] on Mac OS X & BSD
Version:        $Revision: 1.7 $
Author:         Daniel A. Steffen <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        01-Nov-2002
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes a set of changes to ''[file attributes]'' and
''[file copy]'' to make them function better on MacOS X and other
BSD-Unix systems.

~ Summary of Proposed Changes

This TIP proposes five sets of changes to ''[file attributes]'' and
''[file copy]'':

 1. Add support for the Macintosh and Windows specific flag ''[file
    attributes -readonly]'' to Unixes that support the ''chflags()''
    API, to allow the ''user immutable'' flag to be accessed &
    modified from Tcl.

 2. Add support for the Macintosh specific flags ''[file attributes
    -readonly -creator -type -hidden]'' to Mac OS X via the POSIX
    level API ''getattrlist()''.

 3. Add a new flag ''[file attributes -rsrclength]'' to Mac OS X and
    Mac OS 9 that gives the length of the resource fork of a file; 0
    is the only value that this attribute can be set to, which strips
    the resource fork off a file.

 4. Change ''[file attributes]'' to return the list of attributes that
    can be retrieved without error for a given file, instead of
    aborting the whole command when any error occurs.

 5. Enhance ''[file copy]'' on Mac OS X (more precisely, the native
    file-system ''Tcl_FSCopyFile'') to copy finder attributes (i.e.
    ''-readonly -creator -type -hidden'') and resource forks
    transparently.

~ Rationale

There is currently no way to access and modify HFS file-system metadata
from Tcl on Mac OS X whereas Tcl on Mac OS 9 (or Classic) on the same
Macintosh has that capability.  Worse, ''[file copy]'' (and
potentially even ''[file rename]'' if it results in a copy) on Mac OS
X can be a destructive operation at present if it operates on a file
that has essential data in its resource fork or its HFS metadata.
This again in contrast to the same operations in Tcl on Mac OS 9 where
this information is preserved.  This TIP seeks to rectify these
asymmetries in order to better hide such file-system related platform
specificities from the scripter.

~ Details

Additional information & examples:

 1. Unix versions that support ''chflags()'' include BSD >= 4.4 and
    Darwin/Mac OS X (where ''user immutable'' is the flag
    corresponding to the file locked state on the HFS file-system,
    which is what ''[file attributes -readonly]'' controls on Mac OS
    9).

 2. The use of ''getattrlist()'' does not require linking with Carbon
    and thus allows access to HFS file-system metadata from Tcl on pure
    open-source Darwin systems (which is something no other scripting
    language can claim at present).

 3. The new attribute ''-rsrclength'' is useful to check whether a
    file has a resource fork and to calculate total file size on Mac
    OS 9 and X (note that ''[file size]'' returns the size of the data
    fork only).  Stripping a file's resource fork (by setting
    ''-rsrclength'' to 0) is a common operation on Mac OS when dealing
    with files that are destined for other platforms.  This is a
    feature that has been requested several times and given that it
    ties in well with the implementation of the other new attributes
    it comes at essentially no additional cost.

|% file attributes test
|-group admin -owner steffen -permissions 00644 -readonly 0 -creator Doug -type RSRC -hidden 0 -rsrclength 314
|% file attributes test -rsrclength 5
|setting nonzero rsrclength not supported
|% file attributes test -rsrclength 0
|% file attributes test
|-group admin -owner steffen -permissions 00644 -readonly 0 -creator Doug -type RSRC -hidden 0 -rsrclength 0

 4. On Mac OS X, trying to retrieve the new attributes ''-creator
    -type -rsrclength'' fails on non-regular files & directories (and
    on any file located on a non-HFS file-system that doesn't support
    ''getattrlist()'').  Returning only the list of attributes that
    are valid seems like much more sensible behaviour in this case
    than failing with an error and not returning anything.  In the
    case where no valid attributes can be retrieved at all, the error
    returned by the last attempt is passed upstream, to preserve
    existing error handling.  This proposed change in behaviour of
    ''[file attributes]'' seems necessary to allow the command to
    continue to work in a consistent way on all inputs and on all
    platforms; it should not impact existing code since for current
    attributes, failure to retrieve any one attribute is equivalent to
    failure to retrieve all attributes.

|% close [open test w]
|% file attributes test
|-group admin -owner steffen -permissions 00644 -readonly 0 -creator {} -type {} -hidden 0 -rsrclength 0
|% file delete test
|% file mkdir test
|% file attributes test
|-group admin -owner steffen -permissions 040755 -readonly 0 -hidden 0
|% file delete test

 5. Unlike the Finder and other HFS aware tools on Mac OS X, Tcl
    currently ignores HFS metadata and the resource fork, which will
    undoubtedly surprise scripters unpleasantly.  ''[file copy]''
    should hide such platform specificities and copy a file in the
    same way as the Finder:

|% file attributes test
|-group admin -owner steffen -permissions 00644 -readonly 0 -creator Doug -type RSRC -hidden 0 -rsrclength 314
|% file copy test test1
|% file attributes test1
|-group admin -owner steffen -permissions 00644 -readonly 0 -creator Doug -type RSRC -hidden 0 -rsrclength 314
|% file delete test1

~ Comments

Additional implementation details:

 * To support the new attributes ''-creator -type'', routines to
   convert from numerical OSTypes (''u_int32_t'') to the usual four
   character human readable format have been adapted from
   ''mac/tclMacResource.c''; the new versions accept/return strings of
   length 0-4 unlike the originals that only dealt with length 4.
   This is important because creator/type 0 (i.e. ''-creator {} -type
   {}'') is common on Mac OS X. The Mac OS 9 implementation of the
   OSType string representation code has been modified accordingly by
   adding support for strings of length 0-4 and missing
   ''UtfToExternal/ExternalToUtf'' conversions.

 * ''macRoman'' is the encoding used for the string representation of
   OSTypes, for consistency with Tcl on Mac OS 9 as well as with
   common Mac OS X tools such as Resorcerer & SuperGetInfo that all
   use ''macRoman'' to display creator/type codes; this encoding is
   probably what most people would expect.  It's unfortunate that this
   means that use of ''[file attributes]'' on Darwin/Mac OS X will
   cause the non-builtin ''macRoman'' encoding to load.  ASCII-only
   OSTypes will still work properly if ''macRoman'' is not available,
   fallback to ''latin1'' in that case could also be added if deemed
   necessary.  However, the Tk Aqua port already relies on
   ''macRoman'' being present so in the most common usage pattern
   ''macRoman'' should be present and loaded anyway.

 * The Mac OS 9 implementation of ''[file attributes -creator -type]''
   currently returns the bogus 'Fldr' type & creator for directories,
   this has been changed to return an error for consistency with the
   Mac OS X implementation.

 * Most of the implementation of the new Mac OS X specific features
   has been added added at the end of ''unix/tclUnixFCmd.c'', it might
   be cleaner to move this code to a separate file
   ''macosx/tclMacOSXFCmd.c'', but that would require several routines
   in both ''unix/tclUnixFCmd.c'' and ''mac/tclMacOSXFCmd.c'' to be
   made non-static.  It's unclear whether this is an acceptable change
   just for the sake of code separation/cleanliness.

~ Reference Implementation

SourceForge patch #626360
[[http://sourceforge.net/tracker/index.php?func=detail&aid=626360&group_id=10894&atid=310894]]
implements this TIP as a patch to the current HEAD.

The patch has been tested on the SF compile-farm on hosts:

 [Alpha] Linux 2.4 (Debian 3.0): where ''chflags()'' and
   ''getattrlist()'' are not available and no ill effects ensue
   (i.e. no new tests fail).

 [x86] FreeBSD (4.7-RC): where ''chflags()'' is available and ''[file
   attributes -readonly]'' can successfully be interrogated (but not
   set due to permission issues at SourceForge).  No new tests fail.

as well as on Mac OS 9, X 10.1.5 and X 10.2.1, where all the new
functionality is available and no new tests fail.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|


|

|
|

|
|
|


|
|
|

|




|



|
|
|


|


|
|
|







|



|
|

|
|

|

|
|

|

|
|
|





|
|
|
|
|
|
|

|
|

|





|





|
|
|
|
|
|
|
|



|



|
|
|
|
|
|

|



|
|

|

|
|


|

|


|

|
|
|
|

|
|

|





|

|
|



|

|
|




|
|
|

|
|
|




|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191

# TIP 118: Enhance [file attributes] and [file copy] on Mac OS X & BSD

	Author:         Daniel A. Steffen <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        01-Nov-2002
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes a set of changes to _[file attributes]_ and
_[file copy]_ to make them function better on MacOS X and other
BSD-Unix systems.

# Summary of Proposed Changes

This TIP proposes five sets of changes to _[file attributes]_ and
_[file copy]_:

 1. Add support for the Macintosh and Windows specific flag _[file
    attributes -readonly]_ to Unixes that support the _chflags\(\)_
    API, to allow the _user immutable_ flag to be accessed &
    modified from Tcl.

 2. Add support for the Macintosh specific flags _[file attributes
    -readonly -creator -type -hidden]_ to Mac OS X via the POSIX
    level API _getattrlist\(\)_.

 3. Add a new flag _[file attributes -rsrclength]_ to Mac OS X and
    Mac OS 9 that gives the length of the resource fork of a file; 0
    is the only value that this attribute can be set to, which strips
    the resource fork off a file.

 4. Change _[file attributes]_ to return the list of attributes that
    can be retrieved without error for a given file, instead of
    aborting the whole command when any error occurs.

 5. Enhance _[file copy]_ on Mac OS X \(more precisely, the native
    file-system _Tcl\_FSCopyFile_\) to copy finder attributes \(i.e.
    _-readonly -creator -type -hidden_\) and resource forks
    transparently.

# Rationale

There is currently no way to access and modify HFS file-system metadata
from Tcl on Mac OS X whereas Tcl on Mac OS 9 \(or Classic\) on the same
Macintosh has that capability.  Worse, _[file copy]_ \(and
potentially even _[file rename]_ if it results in a copy\) on Mac OS
X can be a destructive operation at present if it operates on a file
that has essential data in its resource fork or its HFS metadata.
This again in contrast to the same operations in Tcl on Mac OS 9 where
this information is preserved.  This TIP seeks to rectify these
asymmetries in order to better hide such file-system related platform
specificities from the scripter.

# Details

Additional information & examples:

 1. Unix versions that support _chflags\(\)_ include BSD >= 4.4 and
    Darwin/Mac OS X \(where _user immutable_ is the flag
    corresponding to the file locked state on the HFS file-system,
    which is what _[file attributes -readonly]_ controls on Mac OS
    9\).

 2. The use of _getattrlist\(\)_ does not require linking with Carbon
    and thus allows access to HFS file-system metadata from Tcl on pure
    open-source Darwin systems \(which is something no other scripting
    language can claim at present\).

 3. The new attribute _-rsrclength_ is useful to check whether a
    file has a resource fork and to calculate total file size on Mac
    OS 9 and X \(note that _[file size]_ returns the size of the data
    fork only\).  Stripping a file's resource fork \(by setting
    _-rsrclength_ to 0\) is a common operation on Mac OS when dealing
    with files that are destined for other platforms.  This is a
    feature that has been requested several times and given that it
    ties in well with the implementation of the other new attributes
    it comes at essentially no additional cost.

		% file attributes test
		-group admin -owner steffen -permissions 00644 -readonly 0 -creator Doug -type RSRC -hidden 0 -rsrclength 314
		% file attributes test -rsrclength 5
		setting nonzero rsrclength not supported
		% file attributes test -rsrclength 0
		% file attributes test
		-group admin -owner steffen -permissions 00644 -readonly 0 -creator Doug -type RSRC -hidden 0 -rsrclength 0

 4. On Mac OS X, trying to retrieve the new attributes _-creator
    -type -rsrclength_ fails on non-regular files & directories \(and
    on any file located on a non-HFS file-system that doesn't support
    _getattrlist\(\)_\).  Returning only the list of attributes that
    are valid seems like much more sensible behaviour in this case
    than failing with an error and not returning anything.  In the
    case where no valid attributes can be retrieved at all, the error
    returned by the last attempt is passed upstream, to preserve
    existing error handling.  This proposed change in behaviour of
    _[file attributes]_ seems necessary to allow the command to
    continue to work in a consistent way on all inputs and on all
    platforms; it should not impact existing code since for current
    attributes, failure to retrieve any one attribute is equivalent to
    failure to retrieve all attributes.

		% close [open test w]
		% file attributes test
		-group admin -owner steffen -permissions 00644 -readonly 0 -creator {} -type {} -hidden 0 -rsrclength 0
		% file delete test
		% file mkdir test
		% file attributes test
		-group admin -owner steffen -permissions 040755 -readonly 0 -hidden 0
		% file delete test

 5. Unlike the Finder and other HFS aware tools on Mac OS X, Tcl
    currently ignores HFS metadata and the resource fork, which will
    undoubtedly surprise scripters unpleasantly.  _[file copy]_
    should hide such platform specificities and copy a file in the
    same way as the Finder:

		% file attributes test
		-group admin -owner steffen -permissions 00644 -readonly 0 -creator Doug -type RSRC -hidden 0 -rsrclength 314
		% file copy test test1
		% file attributes test1
		-group admin -owner steffen -permissions 00644 -readonly 0 -creator Doug -type RSRC -hidden 0 -rsrclength 314
		% file delete test1

# Comments

Additional implementation details:

 * To support the new attributes _-creator -type_, routines to
   convert from numerical OSTypes \(_u\_int32\_t_\) to the usual four
   character human readable format have been adapted from
   _mac/tclMacResource.c_; the new versions accept/return strings of
   length 0-4 unlike the originals that only dealt with length 4.
   This is important because creator/type 0 \(i.e. _-creator \{\} -type
   \{\}_\) is common on Mac OS X. The Mac OS 9 implementation of the
   OSType string representation code has been modified accordingly by
   adding support for strings of length 0-4 and missing
   _UtfToExternal/ExternalToUtf_ conversions.

 * _macRoman_ is the encoding used for the string representation of
   OSTypes, for consistency with Tcl on Mac OS 9 as well as with
   common Mac OS X tools such as Resorcerer & SuperGetInfo that all
   use _macRoman_ to display creator/type codes; this encoding is
   probably what most people would expect.  It's unfortunate that this
   means that use of _[file attributes]_ on Darwin/Mac OS X will
   cause the non-builtin _macRoman_ encoding to load.  ASCII-only
   OSTypes will still work properly if _macRoman_ is not available,
   fallback to _latin1_ in that case could also be added if deemed
   necessary.  However, the Tk Aqua port already relies on
   _macRoman_ being present so in the most common usage pattern
   _macRoman_ should be present and loaded anyway.

 * The Mac OS 9 implementation of _[file attributes -creator -type]_
   currently returns the bogus 'Fldr' type & creator for directories,
   this has been changed to return an error for consistency with the
   Mac OS X implementation.

 * Most of the implementation of the new Mac OS X specific features
   has been added added at the end of _unix/tclUnixFCmd.c_, it might
   be cleaner to move this code to a separate file
   _macosx/tclMacOSXFCmd.c_, but that would require several routines
   in both _unix/tclUnixFCmd.c_ and _mac/tclMacOSXFCmd.c_ to be
   made non-static.  It's unclear whether this is an acceptable change
   just for the sake of code separation/cleanliness.

# Reference Implementation

SourceForge patch \#626360
<http://sourceforge.net/tracker/index.php?func=detail&aid=626360&group_id=10894&atid=310894> 
implements this TIP as a patch to the current HEAD.

The patch has been tested on the SF compile-farm on hosts:

 [Alpha] Linux 2.4 \(Debian 3.0\): where _chflags\(\)_ and
   _getattrlist\(\)_ are not available and no ill effects ensue
   \(i.e. no new tests fail\).

 [x86] FreeBSD \(4.7-RC\): where _chflags\(\)_ is available and _[file
   attributes -readonly]_ can successfully be interrogated \(but not
   set due to permission issues at SourceForge\).  No new tests fail.

as well as on Mac OS 9, X 10.1.5 and X 10.2.1, where all the new
functionality is available and no new tests fail.

# Copyright

This document has been placed in the public domain.

Name change from tip/119.tip to tip/119.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

TIP:            119
Title:          Angled Text on a Canvas
Version:        $Revision: 1.8 $
Author:         Simon Geard <[email protected]>
Author:		Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        18-Nov-2002
Post-History:   
Tcl-Version:    8.6


~ Abstract

The current text object on a canvas does not support the creation of
text strings at an arbitrary angle.  For some applications this is
limitation is sufficiently serious to disqualify Tk from use.  This
TIP removes this restriction.

~ Rationale

Using a Tk canvas to display e.g. an engineering drawing from a CAD
application is limited - such applications will output angled text and
there is simply no way of displaying such text on a canvas.

Another consideration is the competition.  Both Qt and Java canvas
objects support angled text on their canvas object - most new users
would I believe be surprised to discover that this functionality is not
supported.

Due to the internal architecture of Tk a side effect of this work
would be to enable buttons (and possibly other widgets) to have their
text written at an angle as well.  This TIP does not expose that
functionality.

~ Implementation

At the command level there would be an extra attribute, ''-angle'',
added to the canvas's text object:

|<canvas> create text <x> <y> -text <str> ?-angle <angle>? ...

where the angle is specified in degrees.  Manipulation of the angle
would be done in the usual way through the ''itemconfigure'' and
''itemcget'' subcommands:

|<canvas> itemconfigure <tag> -angle <angle>

Note that PostScript naturally supports rotation of text.

~ Reference Implementation

I have done an initial assessment of the amount of work required and
have and have created a patch to implement it in Tk 8.4.5 .  This
initial work was fairly straightforward but the internal housekeeping
work maintaining and interacting with an angled box will be more
substantial.  The patch (uploaded to SourceForge
[http://sf.net/tracker/?func=detail&aid=1611359&group_id=12997&atid=312997]) is
for X only.  It doesn't use any X extensions and should work for X11R3
and above.  I don't know how it would be done on non-X systems but
hopefully they'll (Win & MacOS at least) provide native tools to make
their implementation straightforward as well.

~~ Implementation Notes

The implementation was tricky to develop, because it was wholly different on
each rendering platform (X11 is two, depending on which font rendering engine
is used). This delayed implementation of this TIP for a whole release.

 Classic X11: Uses a general monochrome pixmap rotation engine.

 X11 + Xft: Generates rotated versions of the fonts by installing a rotation
   matrix, caching them in the subfont management engine.

 Win32: Generates rotated versions of the fonts using the built-in font
   rotation suport, caching them in the subfont management engine.

 MacOS X: Applies the rotation to the Current Transformation Matrix
   immediately before rendering.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|






|











|



|

|


|


|
|

|



|





|
|


|


|


|
|



|








|


>

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

# TIP 119: Angled Text on a Canvas

	Author:         Simon Geard <[email protected]>
	Author:		Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        18-Nov-2002
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

The current text object on a canvas does not support the creation of
text strings at an arbitrary angle.  For some applications this is
limitation is sufficiently serious to disqualify Tk from use.  This
TIP removes this restriction.

# Rationale

Using a Tk canvas to display e.g. an engineering drawing from a CAD
application is limited - such applications will output angled text and
there is simply no way of displaying such text on a canvas.

Another consideration is the competition.  Both Qt and Java canvas
objects support angled text on their canvas object - most new users
would I believe be surprised to discover that this functionality is not
supported.

Due to the internal architecture of Tk a side effect of this work
would be to enable buttons \(and possibly other widgets\) to have their
text written at an angle as well.  This TIP does not expose that
functionality.

# Implementation

At the command level there would be an extra attribute, _-angle_,
added to the canvas's text object:

	<canvas> create text <x> <y> -text <str> ?-angle <angle>? ...

where the angle is specified in degrees.  Manipulation of the angle
would be done in the usual way through the _itemconfigure_ and
_itemcget_ subcommands:

	<canvas> itemconfigure <tag> -angle <angle>

Note that PostScript naturally supports rotation of text.

# Reference Implementation

I have done an initial assessment of the amount of work required and
have and have created a patch to implement it in Tk 8.4.5 .  This
initial work was fairly straightforward but the internal housekeeping
work maintaining and interacting with an angled box will be more
substantial.  The patch \(uploaded to SourceForge
<http://sf.net/tracker/?func=detail&aid=1611359&group_id=12997&atid=312997> \) is
for X only.  It doesn't use any X extensions and should work for X11R3
and above.  I don't know how it would be done on non-X systems but
hopefully they'll \(Win & MacOS at least\) provide native tools to make
their implementation straightforward as well.

## Implementation Notes

The implementation was tricky to develop, because it was wholly different on
each rendering platform \(X11 is two, depending on which font rendering engine
is used\). This delayed implementation of this TIP for a whole release.

 Classic X11: Uses a general monochrome pixmap rotation engine.

 X11 \+ Xft: Generates rotated versions of the fonts by installing a rotation
   matrix, caching them in the subfont management engine.

 Win32: Generates rotated versions of the fonts using the built-in font
   rotation suport, caching them in the subfont management engine.

 MacOS X: Applies the rotation to the Current Transformation Matrix
   immediately before rendering.

# Copyright

This document has been placed in the public domain.

Name change from tip/12.tip to tip/12.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
TIP:            12
Title:          The "Batteries Included" Distribution
Version:        $Revision: 1.3 $
Author:         George A. Howlett <[email protected]>
Author:         Larry W. Virden <[email protected]>
State:          Draft
Type:           Informative
Vote:           Pending
Created:        15-Sep-2000
Post-History:   
Discussions-To: news:comp.lang.tcl


~ Abstract

This document describes a comprehensive Tcl/Tk distribution.  Its
primary purpose is to create a standard source tree that includes Tcl,
Tk, and extensions so that they can be built and installed in an
simple and easy manner.

~ Introduction

One of the most enduring complaints about Tcl/Tk is that it lacks
features, especially when compared to Perl, Python, or Java.  We
patiently explain that some particular feature is available in
extension "XYZ" only to hear how hard it is to build and install
extensions.

Frank Stajano ("The SMS server, or why I switched from Tcl to Python")
describes the problem succinctly.

 > "But if I had to put the finger on the single most important reason
   that has me now working in Python rather than in Tcl/[[incr Tcl]]
   it would not be a language issue but a library issue. I prefer
   Python because its standard library is a gold mine. Sure, for
   anything I want to do there's bound to be an extension available in
   the Tcl code repository on the FTP site. Now I just have to find
   it, fetch it, recompile the interpreter with it (Oh wait - this may
   mean getting and installing a C compiler for this system. Will the
   GNU one compile the windowing stuff properly or do I need to get
   VC++, or Borland?  Who wants to have some fun discovering where
   another IDE has hidden the useful compiler flags this week?), hope
   that it won't clash with other extensions I've had to install, hope
   that it will not require a different version of the interpreter
   from the one I am running, and so on. Python supports the same C
   extension mechanism as Tcl - but the practical difference is that
   the stuff I want is, most of the time, already included and shipped
   in the standard distribution of the language!"

<
|
<
|
|
|
|
|
|
|
|
>

|






|







|



|




|


|
|








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

# TIP 12: The "Batteries Included" Distribution

	Author:         George A. Howlett <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        15-Sep-2000
	Post-History:   
	Discussions-To: news:comp.lang.tcl
-----

# Abstract

This document describes a comprehensive Tcl/Tk distribution.  Its
primary purpose is to create a standard source tree that includes Tcl,
Tk, and extensions so that they can be built and installed in an
simple and easy manner.

# Introduction

One of the most enduring complaints about Tcl/Tk is that it lacks
features, especially when compared to Perl, Python, or Java.  We
patiently explain that some particular feature is available in
extension "XYZ" only to hear how hard it is to build and install
extensions.

Frank Stajano \("The SMS server, or why I switched from Tcl to Python"\)
describes the problem succinctly.

 > "But if I had to put the finger on the single most important reason
   that has me now working in Python rather than in Tcl/[incr Tcl]
   it would not be a language issue but a library issue. I prefer
   Python because its standard library is a gold mine. Sure, for
   anything I want to do there's bound to be an extension available in
   the Tcl code repository on the FTP site. Now I just have to find
   it, fetch it, recompile the interpreter with it \(Oh wait - this may
   mean getting and installing a C compiler for this system. Will the
   GNU one compile the windowing stuff properly or do I need to get
   VC\+\+, or Borland?  Who wants to have some fun discovering where
   another IDE has hidden the useful compiler flags this week?\), hope
   that it won't clash with other extensions I've had to install, hope
   that it will not require a different version of the interpreter
   from the one I am running, and so on. Python supports the same C
   extension mechanism as Tcl - but the practical difference is that
   the stuff I want is, most of the time, already included and shipped
   in the standard distribution of the language!"

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
that words "core" and "extension" disappear from our Tcl vocabularies.
We've lived their artifical distinctions that are useful only to core
developers and extension writers.  It's skewed our thinking about
relationship between Tcl and its parts.  After all, application
writers first care about whether a feature or capability is available,
not how it's structured under the hood.

~ The "Batteries Included" Distribution.

Let's start with a very modest example.  Let's imagine that the
"Batteries Included" distribution is nothing more than an archive file of
the source code for Tcl/Tk and several extensions.

|            Unix    Windows  Mac
|             ----    -------  ---
|  Tcl 8.3       x       x      x
|  Tk 8.3        x       x      x
|  [incr Tcl]    x       x      x
|  expect        x       ?
|  TclX          x
|  BLT           x       x
|  Trf           
|  Html widget
|  XML
|  ...lots more...

Tcl, Tk, and the packages are configured such that they can be built
and installed just from a top level directory (not individually).
Someone can download and try out all sorts of new features without
repeating the same "configure", "make", "make install" sequences.

With this simple tar file, the following benefits are automatically
generated:

  * It provides a simple way for users to try out extensions.  Users







|





|
|
|
|
|
|
|
|
|
|
|
|


|







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
that words "core" and "extension" disappear from our Tcl vocabularies.
We've lived their artifical distinctions that are useful only to core
developers and extension writers.  It's skewed our thinking about
relationship between Tcl and its parts.  After all, application
writers first care about whether a feature or capability is available,
not how it's structured under the hood.

# The "Batteries Included" Distribution.

Let's start with a very modest example.  Let's imagine that the
"Batteries Included" distribution is nothing more than an archive file of
the source code for Tcl/Tk and several extensions.

	            Unix    Windows  Mac
	             ----    -------  ---
	  Tcl 8.3       x       x      x
	  Tk 8.3        x       x      x
	  [incr Tcl]    x       x      x
	  expect        x       ?
	  TclX          x
	  BLT           x       x
	  Trf           
	  Html widget
	  XML
	  ...lots more...

Tcl, Tk, and the packages are configured such that they can be built
and installed just from a top level directory \(not individually\).
Someone can download and try out all sorts of new features without
repeating the same "configure", "make", "make install" sequences.

With this simple tar file, the following benefits are automatically
generated:

  * It provides a simple way for users to try out extensions.  Users
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
136
137
138
139
140
141
142
143
    features being universally available.  Your program can again be
    just a Tcl script, not an array of packages that everyone needs to
    download and install.

  * It's better for extension writers.  Configuration is simpler,
    since you know where all the sources and the compiler-specific
    information will reside.  You don't need to search for
    ''tclConfig.sh'' or ''tkConfig.sh'' files.

  * It's better for Tcl/Tk distribution builders.  This includes both
    the Linux distributors and company sysadmins that build Tcl/Tk.
    They don't have to fear installing extensions because of version
    dependencies.

  > Let's give Redhat and SuSE a good reason to move off of version
    8.0. One the big advantages of Linux over (let's say) Solaris is
    that each new Redhat or SuSE distribution comes with updated
    versions of utilities already built.

  * It's better for the core developers. Extension writers will
    willing the adopt changes in exchange for the wider distribution.
    The core team will in turn gain better understanding of the
    burdens of extension writers.

  * It's better for Tcl library writers.  With [incr Tcl], we now have
    a basis for a real, extensible Tcl-code library.  Library code
    rely on a full set of extensions being available.

~ Rationale

We want to create an open door procedure that makes it easy for
contributors to add new features and commands to Tcl and Tk.  By
creating a framework for extensions to be built and distributed, the
"Batteries Included" distribution will provide a path for great new
features to quickly become available to the Tcl community.








|






|
|












|







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
136
137
138
139
140
141
142
    features being universally available.  Your program can again be
    just a Tcl script, not an array of packages that everyone needs to
    download and install.

  * It's better for extension writers.  Configuration is simpler,
    since you know where all the sources and the compiler-specific
    information will reside.  You don't need to search for
    _tclConfig.sh_ or _tkConfig.sh_ files.

  * It's better for Tcl/Tk distribution builders.  This includes both
    the Linux distributors and company sysadmins that build Tcl/Tk.
    They don't have to fear installing extensions because of version
    dependencies.

	  > Let's give Redhat and SuSE a good reason to move off of version
    8.0. One the big advantages of Linux over \(let's say\) Solaris is
    that each new Redhat or SuSE distribution comes with updated
    versions of utilities already built.

  * It's better for the core developers. Extension writers will
    willing the adopt changes in exchange for the wider distribution.
    The core team will in turn gain better understanding of the
    burdens of extension writers.

  * It's better for Tcl library writers.  With [incr Tcl], we now have
    a basis for a real, extensible Tcl-code library.  Library code
    rely on a full set of extensions being available.

# Rationale

We want to create an open door procedure that makes it easy for
contributors to add new features and commands to Tcl and Tk.  By
creating a framework for extensions to be built and distributed, the
"Batteries Included" distribution will provide a path for great new
features to quickly become available to the Tcl community.

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294


If the "Batteries Included" distribution is to become successful, it
must be a cooperative effort between Tcl core developers, extension
writers, and the Tcl user community.  For example, we need the help of
extension writers to adopt the new configuration scheme and directory
structure.

~ Particulars

We can stage the project with small milestones while still focusing on
longer range goals.  For example, the first phase can be as simple as
creating a tar file.  It will start to address questions that were
raised by TEA.  For example, how do we manage documentation?

The biggest reason why this proposal will succeed is the incredible
talent in the Tcl community.  We can leverage the skills and
experiences of the foremost experts on the core, extensions, and
applications.

~ Tcl/Tk Version.

The distribution will be based on 8.3.2 (or 8.3.3 when it is
released).  While there's no assurance when 8.4 will be released and
in what state, we also want to place a premium on stable, robust
extensions, that have been thoroughly tested.  Most extensions will be
unlikely to have been tested against the 8.4 alphas.

~ Phase 1.

 * Identify extensions.  

 > What extensions should be included in the near term?  We need
   extension authors that are willing to work with us to build a
   directory framework, change configuration files, etc.  Extensions
   do not need to work on all platforms.  For example, there is a
   wealth of Windows-based extensions that should be included in 
   a Windows specific build.

 > What are the minimum requirements for extensions in the short term?
   Manual pages, html, tests, demos all would be nice.  We need to
   temper this with what's practical.  This is a learning process. We
   can adjust requirements in future phases.

 * Determine build and install directory structures.  

 > We need to make this work with more that one release installed.
   Don't suppose that there only one version will ever be used.

 * Setup CVS archives.

 * Create configuration files.  

 > This will require negotiation with extension writers.  We want
   their buy-in so they will maintain the changes.

 > There may be more than one form of configuration required.  One
   subtle but important issue is that extensions must be able to be
   configured without Tcl or Tk libraries already existing.  This is a
   "trusted" configure.  The extension must trust that the library
   will exist.  Right now, most extensions work from "untrusted"
   configurations.

 * Test builds on multiple platforms.  

 > For now, the Windows and Mac build files can be hand-generated.  It
   may be too hard to create a seamless build environment. We're not
   trying to satisfy every Windows/Mac developer here.  We can focus
   on creating pre-built binary distributions for these platforms.

 * Create self-installing executables for Windows and the Mac.  

 > If we want, we can provide Linux, Solaris, etc. binaries by
   reviving Michael McLennan's Tclish installer.

~ Phase 2.

 * Handle documentation issues.  

 > Generate platform specific doc with Richard Hipp's XML code.

 * Establish Tcl code library.

 * Identify more extensions.

 * Determine the release schedule for "batteries included" distribution.  

 > How often do you release a new version?  It must be more frequent
   than Tcl/Tk.  We can start by planning for quarterly releases and
   then adding more frequent releases if necessary.

 * Determine what core changes (if any) are needed for the distribution.

 * Start looking at network-based updates.

 * Start looking at selective builds.  Allow builders to compile/install 
   subsets of the distribution.

 * Push on Redhat, SuSE, etc. to pick up distribution.

~ Phase 3.

 * Network-based installs.

 * Selective installations/builds.

 * Include applications tree.

 * Identify more extensions.

The last phases are sketchy.  Feel free to add to this list, further
breaking down goals into subtasks.

~ Open Issues

 * Windows and MacIntosh sources.

 > Given the dearth of configuration tools for these platforms, it's
   likely that only binary installations will be available for the
   near term.

 * Documentation

 > Overlap in command and widget names can be neatly handled by
   namespaces.  Need to consider how to handle manual pages.

~ More Information

If anyone has interest to participate or would like to add comments to
the "Batteries Included" proposal, please send mail to George Howlett
<[email protected]>.

~ Copyright

This document has been placed in the public domain.

~ See Also

[4] by Brent Welch <[email protected]>.








|











|

|
|




|



|






|






|






|


|








|






|


|



|







|



|








|












|



|





|


|





|



|

|
>
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294

If the "Batteries Included" distribution is to become successful, it
must be a cooperative effort between Tcl core developers, extension
writers, and the Tcl user community.  For example, we need the help of
extension writers to adopt the new configuration scheme and directory
structure.

# Particulars

We can stage the project with small milestones while still focusing on
longer range goals.  For example, the first phase can be as simple as
creating a tar file.  It will start to address questions that were
raised by TEA.  For example, how do we manage documentation?

The biggest reason why this proposal will succeed is the incredible
talent in the Tcl community.  We can leverage the skills and
experiences of the foremost experts on the core, extensions, and
applications.

# Tcl/Tk Version.

The distribution will be based on 8.3.2 \(or 8.3.3 when it is
released\).  While there's no assurance when 8.4 will be released and
in what state, we also want to place a premium on stable, robust
extensions, that have been thoroughly tested.  Most extensions will be
unlikely to have been tested against the 8.4 alphas.

# Phase 1.

 * Identify extensions.  

	 > What extensions should be included in the near term?  We need
   extension authors that are willing to work with us to build a
   directory framework, change configuration files, etc.  Extensions
   do not need to work on all platforms.  For example, there is a
   wealth of Windows-based extensions that should be included in 
   a Windows specific build.

	 > What are the minimum requirements for extensions in the short term?
   Manual pages, html, tests, demos all would be nice.  We need to
   temper this with what's practical.  This is a learning process. We
   can adjust requirements in future phases.

 * Determine build and install directory structures.  

	 > We need to make this work with more that one release installed.
   Don't suppose that there only one version will ever be used.

 * Setup CVS archives.

 * Create configuration files.  

	 > This will require negotiation with extension writers.  We want
   their buy-in so they will maintain the changes.

	 > There may be more than one form of configuration required.  One
   subtle but important issue is that extensions must be able to be
   configured without Tcl or Tk libraries already existing.  This is a
   "trusted" configure.  The extension must trust that the library
   will exist.  Right now, most extensions work from "untrusted"
   configurations.

 * Test builds on multiple platforms.  

	 > For now, the Windows and Mac build files can be hand-generated.  It
   may be too hard to create a seamless build environment. We're not
   trying to satisfy every Windows/Mac developer here.  We can focus
   on creating pre-built binary distributions for these platforms.

 * Create self-installing executables for Windows and the Mac.  

	 > If we want, we can provide Linux, Solaris, etc. binaries by
   reviving Michael McLennan's Tclish installer.

# Phase 2.

 * Handle documentation issues.  

	 > Generate platform specific doc with Richard Hipp's XML code.

 * Establish Tcl code library.

 * Identify more extensions.

 * Determine the release schedule for "batteries included" distribution.  

	 > How often do you release a new version?  It must be more frequent
   than Tcl/Tk.  We can start by planning for quarterly releases and
   then adding more frequent releases if necessary.

 * Determine what core changes \(if any\) are needed for the distribution.

 * Start looking at network-based updates.

 * Start looking at selective builds.  Allow builders to compile/install 
   subsets of the distribution.

 * Push on Redhat, SuSE, etc. to pick up distribution.

# Phase 3.

 * Network-based installs.

 * Selective installations/builds.

 * Include applications tree.

 * Identify more extensions.

The last phases are sketchy.  Feel free to add to this list, further
breaking down goals into subtasks.

# Open Issues

 * Windows and MacIntosh sources.

	 > Given the dearth of configuration tools for these platforms, it's
   likely that only binary installations will be available for the
   near term.

 * Documentation

	 > Overlap in command and widget names can be neatly handled by
   namespaces.  Need to consider how to handle manual pages.

# More Information

If anyone has interest to participate or would like to add comments to
the "Batteries Included" proposal, please send mail to George Howlett
<[email protected]>.

# Copyright

This document has been placed in the public domain.

# See Also

[[4]](4.md) by Brent Welch <[email protected]>.

Name change from tip/120.tip to tip/120.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

TIP:            120
Title:          Restricted DDE Services
Version:        $Revision: 1.5 $
Author:         Pat Thoyts <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        04-Dec-2002
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP will enhance the DDE package for use with safe interpreters
and allow programmer control of the commands exposed by the DDE
service.

~ Rationale

By default the Tcl DDE service exposes all of the commands and
variables available in the interpreter to all DDE clients.  This is
not always desirable.  One solution might be to load the package into
a safe slave interpreter and use [[interp alias]] to expose the
required commands.  Unfortunately the package doesn't support loading
into safe interpreters.

~ Proposed Changes

Firstly, this TIP proposes a ''-handler'' option to the [[dde
servername]] sub-command.  The argument for this option should be the
name of a procedure that will authenticate and evaluate DDE requests.

Secondly, the DDE package should be enhanced to be capable of
providing a service within a safe interpreter.

~ New Option

The new syntax will be ''dde servername ?-handler command?
servername''.  To permit introspection we will accept ''dde servername
-handler'' which will return the handler name (if any).  If a
servername must be defined using an initial hyphen then the standard
'--' separator can be used.

The dde request is appended to the handler command (which may be a list)
and then evaluated in the global context. This ensures that all unsafe
elements will not be evaluated before the handler code has a chance to
examine them. So

| proc handler {request} {
|    if {[string match "info *" $request} {
|       uplevel #0 [lindex $request 0] [lrange $request 1 end]
|    } else
|       return -code error "permission denied"
|    }
| }



The above handler will permit [[info vars]] but will fail when trying
[[info vars ; bad_proc]] with info complaining about the wrong number
of parameters. Passing a single string means that we can handle
standard dde styles of requests, for instance 
'Open("c:\Program Files\prog.exe")' which would not usefully convert
into a list.

~ Safe DDE

The dde package should support loading within a safe interpreter but
with the following constraints.

 * The dde command should be hidden.  This means that the safe
   interpreter may not call the command but a master interpreter call
   this command within the context of the safe interpreter.

 * Remote execution requests should be handled ''only'' by a defined
   handler procedure.  The normal default is to evaluate a remote
   execution request in the global namespace.  I propose that when
   operating in a safe interpreter that the request be denied unless a
   handler is defined.  The programmer then has the ability to
   authenticate the request before it is evaluated.

 * Remote variable reads should be denied.  Rather that add in another
   handler - the XTYP_REQUEST service command should be denied for
   safe interpreters.  It is trivial to use [[dde eval Remote set
   $varname]] to read the value of a variable.

~ Reference Implementation

See the SourceForge Feature Request at
https://sourceforge.net/tracker/index.php?func=detail&aid=649859&group_id=10894&atid=310894

~ Example

| # Provide a handler that only allows the [info] command
| # Note: This runs in the master interp.
| proc restricted_handler {request} {
|    if {[string match "info *" $request} {
|       uplevel #0 [lindex $request 0] [lrange $request 1 end]
|    } else
|       return -code error "permission denied"
|    }
| }


|
| # Create a safe slave interpreter and expose as a DDE service.
| safe::interpCreate slave
| slave invokehidden load tcldde12d.dll Dde
| slave invokehidden dde servername -handler dde_cmd SafeSlave
| interp alias slave dde_cmd {} restricted_handler
|
| # If testing in tclsh...
| set ::_waiting 0 ; after 20000 {set ::_waiting 1} ; vwait ::_waiting

~ Consequences

There should be no change to current users of this package unless they
are using a server name beginning with a hyphen.  In this case they
will need to insert '--' before the server name.

~ Copyright

This document is hereby placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|





|




|



|

|
|





|

|
|
|



|




|
|
|
|
|
<
<
|
>
>
|
|


|


|








|







|
|
|

|


|

|

|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
|

|





|


>

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

# TIP 120: Restricted DDE Services

	Author:         Pat Thoyts <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        04-Dec-2002
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP will enhance the DDE package for use with safe interpreters
and allow programmer control of the commands exposed by the DDE
service.

# Rationale

By default the Tcl DDE service exposes all of the commands and
variables available in the interpreter to all DDE clients.  This is
not always desirable.  One solution might be to load the package into
a safe slave interpreter and use [interp alias] to expose the
required commands.  Unfortunately the package doesn't support loading
into safe interpreters.

# Proposed Changes

Firstly, this TIP proposes a _-handler_ option to the [dde
servername] sub-command.  The argument for this option should be the
name of a procedure that will authenticate and evaluate DDE requests.

Secondly, the DDE package should be enhanced to be capable of
providing a service within a safe interpreter.

# New Option

The new syntax will be _dde servername ?-handler command?
servername_.  To permit introspection we will accept _dde servername
-handler_ which will return the handler name \(if any\).  If a
servername must be defined using an initial hyphen then the standard
'--' separator can be used.

The dde request is appended to the handler command \(which may be a list\)
and then evaluated in the global context. This ensures that all unsafe
elements will not be evaluated before the handler code has a chance to
examine them. So

	 proc handler {request} {
	    if {[string match "info *" $request} {
	       uplevel #0 [lindex $request 0] [lrange $request 1 end]
	    } else
	       return -code error "permission denied"


	    }
	 }

The above handler will permit [info vars] but will fail when trying
[info vars ; bad_proc] with info complaining about the wrong number
of parameters. Passing a single string means that we can handle
standard dde styles of requests, for instance 
'Open\("c:\\Program Files\\prog.exe"\)' which would not usefully convert
into a list.

# Safe DDE

The dde package should support loading within a safe interpreter but
with the following constraints.

 * The dde command should be hidden.  This means that the safe
   interpreter may not call the command but a master interpreter call
   this command within the context of the safe interpreter.

 * Remote execution requests should be handled _only_ by a defined
   handler procedure.  The normal default is to evaluate a remote
   execution request in the global namespace.  I propose that when
   operating in a safe interpreter that the request be denied unless a
   handler is defined.  The programmer then has the ability to
   authenticate the request before it is evaluated.

 * Remote variable reads should be denied.  Rather that add in another
   handler - the XTYP\_REQUEST service command should be denied for
   safe interpreters.  It is trivial to use [dde eval Remote set
   $varname] to read the value of a variable.

# Reference Implementation

See the SourceForge Feature Request at
<https://sourceforge.net/tracker/index.php?func=detail&aid=649859&group\_id=10894&atid=310894>

# Example

	 # Provide a handler that only allows the [info] command
	 # Note: This runs in the master interp.
	 proc restricted_handler {request} {
	    if {[string match "info *" $request} {
	       uplevel #0 [lindex $request 0] [lrange $request 1 end]
	    } else
	       return -code error "permission denied"


	    }
	 }
	
	 # Create a safe slave interpreter and expose as a DDE service.
	 safe::interpCreate slave
	 slave invokehidden load tcldde12d.dll Dde
	 slave invokehidden dde servername -handler dde_cmd SafeSlave
	 interp alias slave dde_cmd {} restricted_handler
	
	 # If testing in tclsh...
	 set ::_waiting 0 ; after 20000 {set ::_waiting 1} ; vwait ::_waiting

# Consequences

There should be no change to current users of this package unless they
are using a server name beginning with a hyphen.  In this case they
will need to insert '--' before the server name.

# Copyright

This document is hereby placed in the public domain.

Name change from tip/121.tip to tip/121.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
136
137

TIP:            121
Title:          Controlled Application Shutdown via Tcl_Exit
Version:        $Revision: 1.8 $
Author:         Joe Mistachkin <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        05-Dec-2002
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP will allow all applications to perform a controlled shutdown
(or do nothing) in the event that ''Tcl_Exit()'' is called.

~ Rationale

For most applications written in C that use Tcl, calling the runtime
''exit()'' function is normally a reasonable way to shutdown the
application.  Unfortunately, this is not always the case.
Applications written in other languages (and very complex C
applications) may have very specific application shutdown
requirements.  This is especially true in multi-threaded
environments.  The problem is further compounded by extensions that
use ''Tcl_Exit''.

~ Versus Exit Handlers

There are distinct advantages to using this method instead of using
normal exit handlers in some cases.  The normal exit handler cannot
defer (or in an emergency, prevent) the application shutdown because
''Tcl_Finalize()'' has already been called.  From the perspective of
the exit handler, we have no way of knowing what other exit handlers
have been called and/or their subsystems destroyed. In addition, even
if it could somehow cause ''Tcl_Finalize()'' to defer the application
shutdown, some or all of the other exit handlers may have already
been executed, which would leave the application in an inconsistent
state.  This relatively simple change allows the programmer to get
control very early during the application shutdown process.

~ Proposed Changes

First, this TIP proposes a new Tcl API function called
''Tcl_SetExitProc()'' or something similar.  This function
accepts a ''Tcl_ExitProc'' pointer and returns a ''Tcl_ExitProc''
pointer.  The return value is the old exit proc pointer.

Second, the ''Tcl_Exit()'' Tcl API function would be modified to
allow for the handler to be called.

Third, the documentation for ''Tcl_Exit()'' would be updated to
include ''Tcl_SetExitProc()'' and a warning that any custom exit proc
should NOT return.

~ Tcl_SetExitProc

|Tcl_ExitProc *
|Tcl_SetExitProc(proc)
|    Tcl_ExitProc *proc; /* new exit handler for app or NULL */
|{

|    Tcl_ExitProc *prevExitProc; /* return prev exit handler to caller */
|
|    Tcl_MutexLock(&exitMutex);
|    prevExitProc = appExitPtr; /* get old app exit ptr */
|    appExitPtr = proc; /* set new app exit ptr */
|    Tcl_MutexUnlock(&exitMutex);
|
|    return prevExitProc;
|}


~ Tcl_Exit

|void
|Tcl_Exit(status)
|    int status;			/* Exit status for application;  typically
|				 * 0 for normal return, 1 for error return. */
|{

|    Tcl_ExitProc *currentAppExitPtr;
|
|    Tcl_MutexLock(&exitMutex);
|    currentAppExitPtr = appExitPtr;
|    Tcl_MutexUnlock(&exitMutex);
|
|    if (currentAppExitPtr) {
|      /***********************************************************/
|      /* WARNING: This code SHOULD NOT return, as there is code  */
|      /*          that depends on Tcl_Exit never returning.      */
|      /***********************************************************/
|      currentAppExitPtr((ClientData) status);
|    } else {
|      Tcl_Finalize();
|      TclpExit(status);
|    }

|
|    Tcl_Panic ("exitProc returned!");
|}


~ Example

|void MyAppExitProc(ClientData clientData)
|{

|  /* #1. Perform application specific shutdown code...    */
|  /* #2. Wait for other threads to gracefully shutdown... */
|
|  exit(0);
|
|  return; /* We should never get here. */
|}

|
|
| ... sometime during application initialization ...
|
| /* from this point on MyAppExitProc will handle Tcl_Exit requests */
| Tcl_SetExitProc(MyAppExitProc);
|
| ... optionally, sometime later ...
|
| /* from this point on the old (default) handling will be used */
| Tcl_SetExitProc(NULL);

~ Reference Implementation

A patch that implements everything suggested in this TIP is available
at the URL:

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

~ Consequences

There is no change for current users of the ''Tcl_Exit()'' function,
including the [[exit]] command, if ''Tcl_SetExitProc()'' is never
called explicitly by the application.

~ Copyright

This document is hereby placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|

|


|

|
|


|

|



|
|


|





|


|
|


|


|
|


|

|
|
|
<
>
|
|
|
|
|
|
|
|
<
|
>
|

|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
<
|
>
|

|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|

|




|

|

|
|


|


>

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
136
137

# TIP 121: Controlled Application Shutdown via Tcl_Exit

	Author:         Joe Mistachkin <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        05-Dec-2002
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP will allow all applications to perform a controlled shutdown
\(or do nothing\) in the event that _Tcl\_Exit\(\)_ is called.

# Rationale

For most applications written in C that use Tcl, calling the runtime
_exit\(\)_ function is normally a reasonable way to shutdown the
application.  Unfortunately, this is not always the case.
Applications written in other languages \(and very complex C
applications\) may have very specific application shutdown
requirements.  This is especially true in multi-threaded
environments.  The problem is further compounded by extensions that
use _Tcl\_Exit_.

# Versus Exit Handlers

There are distinct advantages to using this method instead of using
normal exit handlers in some cases.  The normal exit handler cannot
defer \(or in an emergency, prevent\) the application shutdown because
_Tcl\_Finalize\(\)_ has already been called.  From the perspective of
the exit handler, we have no way of knowing what other exit handlers
have been called and/or their subsystems destroyed. In addition, even
if it could somehow cause _Tcl\_Finalize\(\)_ to defer the application
shutdown, some or all of the other exit handlers may have already
been executed, which would leave the application in an inconsistent
state.  This relatively simple change allows the programmer to get
control very early during the application shutdown process.

# Proposed Changes

First, this TIP proposes a new Tcl API function called
_Tcl\_SetExitProc\(\)_ or something similar.  This function
accepts a _Tcl\_ExitProc_ pointer and returns a _Tcl\_ExitProc_
pointer.  The return value is the old exit proc pointer.

Second, the _Tcl\_Exit\(\)_ Tcl API function would be modified to
allow for the handler to be called.

Third, the documentation for _Tcl\_Exit\(\)_ would be updated to
include _Tcl\_SetExitProc\(\)_ and a warning that any custom exit proc
should NOT return.

# Tcl\_SetExitProc

	Tcl_ExitProc *
	Tcl_SetExitProc(proc)
	    Tcl_ExitProc *proc; /* new exit handler for app or NULL */

	{
	    Tcl_ExitProc *prevExitProc; /* return prev exit handler to caller */
	
	    Tcl_MutexLock(&exitMutex);
	    prevExitProc = appExitPtr; /* get old app exit ptr */
	    appExitPtr = proc; /* set new app exit ptr */
	    Tcl_MutexUnlock(&exitMutex);
	
	    return prevExitProc;

	}

# Tcl\_Exit

	void
	Tcl_Exit(status)
	    int status;			/* Exit status for application;  typically
					 * 0 for normal return, 1 for error return. */

	{
	    Tcl_ExitProc *currentAppExitPtr;
	
	    Tcl_MutexLock(&exitMutex);
	    currentAppExitPtr = appExitPtr;
	    Tcl_MutexUnlock(&exitMutex);
	
	    if (currentAppExitPtr) {
	      /***********************************************************/
	      /* WARNING: This code SHOULD NOT return, as there is code  */
	      /*          that depends on Tcl_Exit never returning.      */
	      /***********************************************************/
	      currentAppExitPtr((ClientData) status);
	    } else {
	      Tcl_Finalize();
	      TclpExit(status);

	    }
	
	    Tcl_Panic ("exitProc returned!");

	}

# Example

	void MyAppExitProc(ClientData clientData)

	{
	  /* #1. Perform application specific shutdown code...    */
	  /* #2. Wait for other threads to gracefully shutdown... */
	
	  exit(0);
	
	  return; /* We should never get here. */

	}
	
	
	 ... sometime during application initialization ...
	
	 /* from this point on MyAppExitProc will handle Tcl_Exit requests */
	 Tcl_SetExitProc(MyAppExitProc);
	
	 ... optionally, sometime later ...
	
	 /* from this point on the old (default) handling will be used */
	 Tcl_SetExitProc(NULL);

# Reference Implementation

A patch that implements everything suggested in this TIP is available
at the URL:

<http://sourceforge.net/tracker/index.php?func=detail&aid=649313&group\_id=10894&atid=310894>

# Consequences

There is no change for current users of the _Tcl\_Exit\(\)_ function,
including the [exit] command, if _Tcl\_SetExitProc\(\)_ is never
called explicitly by the application.

# Copyright

This document is hereby placed in the public domain.

Name change from tip/122.tip to tip/122.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

TIP:            122
Title:          Use tcl_{non,}wordchars Throughout Tcl/Tk
Version:        $Revision: 1.9 $
Author:         Martin Weber <[email protected]>
Author:         Vince Darley <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        12-Dec-2002
Post-History:   
Tcl-Version:    8.6


~ Abstract

This TIP shall bring flexible management of word and non-word chars to
Tcl, to be used throughout the Tcl realm in e.g. [[regexp]]'s \w \W,
Tk's [[textwidget]], [[string]] wordstart/wordend etc.

~Specification

Assignment to ''tcl_{non,}wordchars'' shall influence any place in Tcl
which decides whether something is a word character or not, including
detection of word boundaries in e.g. regular expressions, Tk's text
widget and so on.

For this there shall be no hard-coding of lists of values which are
word and non-word characters, and neither shall the language rely on
the language of implementation (i.e. C's ''is*()'' functions), as this
disallows dynamic changing of ''tcl_{non,}wordchars''.

Rather shall the value(s) of ''tcl_{non,}wordchars'' be used to
determine whether a given character is part of a word or not.

~Rationale

Currently in Tcl there are different hard-coded ways to decide whether
a certain character is a word character or a non word character.
Different hard-coded ways also imply that changes on one side might
not get over to the other side, so there soon are different hard-coded
ways which yield different hard-coded results.  As a inference of it
being hard-coded, this also means that there is no way to change or
fix that potentially broken behavior.  Having Tcl lookup the values of
those variables at runtime allows for the needed flexibility, both
when dealing with nonstandard demands and nonstandard character sets.

As an example of the breakage, you can assign a regular expression
to tcl_{,non}wordchars, and the double click binding in the textwidget
will regard that pattern when marking a "whole word". When you try
to ask the text widget to deliver the data under a certain coordinate
with the indices 'wortstart' and 'wordend', the value of
tcl_{non,}wordchars is not used though.

There may be a problem with the performance of the lookup, but on the
other hand are C's ''is*()'' functions also implemented via a table
lookup.  An installation of a caching static character table could
guarantee the needed performance.

~Example of current word confusion

Tk's text widget uses "word" in several ways:

1. selection by word (double-click + drag),

2. movement by word ('insert wordstart'),

3. regexp searching with \m\M wordmatching.

4. line breaks when wrapping (-wrap word)

It is not at all clear from reading Tcl or Tk's documentation what the
behaviour of the above options will be.  It turns out that:

1. after a convoluted call-chain, ends up calling
tcl_wordBreakAfter/Before which use tcl_wordchars and tcl_nonwordchars (which actually are defined differently on Windows vs Unix/MacOS!!).

2. uses 'isalnum(char)' or '_' to define a word (hard-coded in Tk's
tkTextIndex.c) (in Tk8.5a0 this has been fixed to use ''Tcl_UniCharIsWordChar'')

3. uses Tcl's regexp engine's definition of a word (this ought to be the same as that used in (2)).

4. Anything separated by white-space from something else, used with '-wrap word' to define line-wrapping in text widgets (and canvases).

It is quite likely that most of the above are different under some
circumstances or some platforms/locales, and certainly if the
user/developer wants to create a text widget with a different word
definition, they basically can't in any consistent way.

~Implementation

None yet.

~Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|
|

|

|






|
|

|


|












|



|


|



|



|

|

|

|





|

|
|

|

|






|



|


>

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

# TIP 122: Use tcl_{non,}wordchars Throughout Tcl/Tk

	Author:         Martin Weber <[email protected]>
	Author:         Vince Darley <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        12-Dec-2002
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

This TIP shall bring flexible management of word and non-word chars to
Tcl, to be used throughout the Tcl realm in e.g. [regexp]'s \\w \\W,
Tk's [textwidget], [string] wordstart/wordend etc.

# Specification

Assignment to _tcl\_\{non,\}wordchars_ shall influence any place in Tcl
which decides whether something is a word character or not, including
detection of word boundaries in e.g. regular expressions, Tk's text
widget and so on.

For this there shall be no hard-coding of lists of values which are
word and non-word characters, and neither shall the language rely on
the language of implementation \(i.e. C's _is\*\(\)_ functions\), as this
disallows dynamic changing of _tcl\_\{non,\}wordchars_.

Rather shall the value\(s\) of _tcl\_\{non,\}wordchars_ be used to
determine whether a given character is part of a word or not.

# Rationale

Currently in Tcl there are different hard-coded ways to decide whether
a certain character is a word character or a non word character.
Different hard-coded ways also imply that changes on one side might
not get over to the other side, so there soon are different hard-coded
ways which yield different hard-coded results.  As a inference of it
being hard-coded, this also means that there is no way to change or
fix that potentially broken behavior.  Having Tcl lookup the values of
those variables at runtime allows for the needed flexibility, both
when dealing with nonstandard demands and nonstandard character sets.

As an example of the breakage, you can assign a regular expression
to tcl\_\{,non\}wordchars, and the double click binding in the textwidget
will regard that pattern when marking a "whole word". When you try
to ask the text widget to deliver the data under a certain coordinate
with the indices 'wortstart' and 'wordend', the value of
tcl\_\{non,\}wordchars is not used though.

There may be a problem with the performance of the lookup, but on the
other hand are C's _is\*\(\)_ functions also implemented via a table
lookup.  An installation of a caching static character table could
guarantee the needed performance.

# Example of current word confusion

Tk's text widget uses "word" in several ways:

1. selection by word \(double-click \+ drag\),

2. movement by word \('insert wordstart'\),

3. regexp searching with \\m\\M wordmatching.

4. line breaks when wrapping \(-wrap word\)

It is not at all clear from reading Tcl or Tk's documentation what the
behaviour of the above options will be.  It turns out that:

1. after a convoluted call-chain, ends up calling
tcl\_wordBreakAfter/Before which use tcl\_wordchars and tcl\_nonwordchars \(which actually are defined differently on Windows vs Unix/MacOS!!\).

2. uses 'isalnum\(char\)' or '\_' to define a word \(hard-coded in Tk's
tkTextIndex.c\) \(in Tk8.5a0 this has been fixed to use _Tcl\_UniCharIsWordChar_\)

3. uses Tcl's regexp engine's definition of a word \(this ought to be the same as that used in \(2\)\).

4. Anything separated by white-space from something else, used with '-wrap word' to define line-wrapping in text widgets \(and canvases\).

It is quite likely that most of the above are different under some
circumstances or some platforms/locales, and certainly if the
user/developer wants to create a text widget with a different word
definition, they basically can't in any consistent way.

# Implementation

None yet.

# Copyright

This document is placed in the public domain.

Name change from tip/123.tip to tip/123.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

TIP:            123
Title:          Adding an Exponentiation Operator to the [expr] Command
Version:        $Revision: 1.6 $
Author:         Arjen Markus <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        16-Dec-2002
Post-History:   
Keywords:       mathematics,evaluation
Tcl-Version:    8.5


~ Abstract

This TIP proposes to add a new operator to the operators recognised by
the [[expr]] command: the exponentiation operator.  This operator will
enhance the functionality of the current ''pow()'' function by
returning a result that depends on the type of its operands.  It will
also make complicated formulae more readable.

~ Introduction

Currently Tcl's [[expr]] command uses the exponentiation function
''pow()'' to calculate such expressions as "2 to the power 10".  The
drawback of this is twofold:

 * Expressions using several exponentiations become difficult to read.
   For instance, a third-degree polynomial looks like:

| 2.0*pow($x,3) - 1.2*pow($x,2) + 3.0*$x + 4.0

 > or:

| 2.0*$x*$x*$x - 1.2*$x*$x + 3.0*$x + 4.0

 * The result of raising an integer to an integer power is a
   double: 2 to the power 10 is 1024.0, not 1024.

Other languages, like for instance FORTRAN, use an operator instead of
a function.  Two operators are commonly found: ** and ^.  As the
latter already has a meaning within the [[expr]] command, we propose
to add the "**" operator instead.  The above example would become:

| 2.0*$x**3 - 1.2*$x**2 + 3.0*$x + 4.0

~ Mathematical Details

The implementation of the exponentiation operator will have the
following properties (below we refer to the expression ''$x**$y''):

If ''x'' and ''y'' are both integers (ordinary or wide):

 * The result is of the same type as the widest operand

 * An error is raised if the operation makes no mathematical sense,
   ''0**(-1)'' for instance.

 * If ''x'' has the value 0, then:

 > * if ''y > 0'', the result is 0

 > * if ''y < 0'', the result is an error

 > * if ''y == 0'', the result is 1

 * If ''x'' has the value 1, then the result is always 1

 * If ''y'' has the value 0, the result is always 1

 * If ''x'' has a negative value lower than -1 and ''y < 0'', the
   result is 0

 * If ''x'' has the value -1, then depending on whether ''y'' is even
   or odd, the result is 1 or -1 (respectively.)

 * For all other combinations, the value is "''x'' raised to the power
   ''y''"

 * When evaluating this, no attention is paid to overflow, even though
   the result might fit into a wide integer (though of course the
   result will be a wide integer if either operand was wide.)  This is
   in accordance with the type model used in other [[expr]] operators.

If either ''x'' or ''y'' is a double, the C function ''pow()'' is used
to compute the result.

The following expressions are parsed and evaluated in accordance with
all other operators:

| $x ** $y ** $z ==> ($x ** $y ) ** $z
| $x ** -1       ==> ($x ** (-1))

The precedence of the exponentiation operator is thus ''higher'' than
the multiplication, division and remainder operations and lower than
the unary operations, in accordance with common definitions.

~ Sample Implementation

http://sf.net/tracker/?func=detail&aid=655176&group_id=10894&atid=310894

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|


|
|



|

|
|





|

|

|





|
|
|

|

|


|

|




|

|

|

|

|

|

|

|


|
|

|
|


|
|
|

|





|
|

|



|

|

|


>

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

# TIP 123: Adding an Exponentiation Operator to the [expr] Command

	Author:         Arjen Markus <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        16-Dec-2002
	Post-History:   
	Keywords:       mathematics,evaluation
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to add a new operator to the operators recognised by
the [expr] command: the exponentiation operator.  This operator will
enhance the functionality of the current _pow\(\)_ function by
returning a result that depends on the type of its operands.  It will
also make complicated formulae more readable.

# Introduction

Currently Tcl's [expr] command uses the exponentiation function
_pow\(\)_ to calculate such expressions as "2 to the power 10".  The
drawback of this is twofold:

 * Expressions using several exponentiations become difficult to read.
   For instance, a third-degree polynomial looks like:

		 2.0*pow($x,3) - 1.2*pow($x,2) + 3.0*$x + 4.0

	 > or:

		 2.0*$x*$x*$x - 1.2*$x*$x + 3.0*$x + 4.0

 * The result of raising an integer to an integer power is a
   double: 2 to the power 10 is 1024.0, not 1024.

Other languages, like for instance FORTRAN, use an operator instead of
a function.  Two operators are commonly found: \*\* and ^.  As the
latter already has a meaning within the [expr] command, we propose
to add the "\*\*" operator instead.  The above example would become:

	 2.0*$x**3 - 1.2*$x**2 + 3.0*$x + 4.0

# Mathematical Details

The implementation of the exponentiation operator will have the
following properties \(below we refer to the expression _$x\*\*$y_\):

If _x_ and _y_ are both integers \(ordinary or wide\):

 * The result is of the same type as the widest operand

 * An error is raised if the operation makes no mathematical sense,
   _0\*\*\(-1\)_ for instance.

 * If _x_ has the value 0, then:

	 > \* if _y > 0_, the result is 0

	 > \* if _y < 0_, the result is an error

	 > \* if _y == 0_, the result is 1

 * If _x_ has the value 1, then the result is always 1

 * If _y_ has the value 0, the result is always 1

 * If _x_ has a negative value lower than -1 and _y < 0_, the
   result is 0

 * If _x_ has the value -1, then depending on whether _y_ is even
   or odd, the result is 1 or -1 \(respectively.\)

 * For all other combinations, the value is "_x_ raised to the power
   _y_"

 * When evaluating this, no attention is paid to overflow, even though
   the result might fit into a wide integer \(though of course the
   result will be a wide integer if either operand was wide.\)  This is
   in accordance with the type model used in other [expr] operators.

If either _x_ or _y_ is a double, the C function _pow\(\)_ is used
to compute the result.

The following expressions are parsed and evaluated in accordance with
all other operators:

	 $x ** $y ** $z ==> ($x ** $y ) ** $z
	 $x ** -1       ==> ($x ** (-1))

The precedence of the exponentiation operator is thus _higher_ than
the multiplication, division and remainder operations and lower than
the unary operations, in accordance with common definitions.

# Sample Implementation

<http://sf.net/tracker/?func=detail&aid=655176&group\_id=10894&atid=310894>

# Copyright

This document is placed in the public domain.

Name change from tip/124.tip to tip/124.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

TIP:            124
Title:          High-Resolution Absolute Time Values From [clock]
Version:        $Revision: 1.13 $
Author:         Mark Harrison <[email protected]>
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        20-Dec-2002
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes altering the '''clock clicks''' command to add
a '''-microseconds''' option, and to tie it to an absolute reference.

~ Rationale

The '''clock clicks''' command is a useful feature for analyzing and
tuning performance in Tcl programs.  Since the timer is relative,
however, it is difficult to correlate times between two programs or
with timestamps stored in a log file.

~ Proposed change

This TIP proposes two changes to '''clock clicks''' to make it more
useful in situations where absolute times are needed:

   1. Change '''clock clicks -milliseconds''' to return a wide integer,
      representing the number of milliseconds since the Posix epoch.

   1. Add a '''clock clicks -microseconds''' that likewise returns
      a wide integer, representing the number of microseconds since
      the Posix epoch.

~ Compatibility with existing code

Now that Tcl supports 64-bit integers transparently, compatibility
with existing code is unlikely to cause trouble.  In practice, the
only uses of '''clock clicks''' that the authors have seen all simply
compute the difference between two successive values.  Since the
difference will continue to fit in 32 bits if it did so before,
such code will simply continue to work.

The change from a relative standard to an absolute one is
likewise transparent.  One fact that supports this claim is that
such a change was made in '''clock clicks -milliseconds''' on Windows
in support of [7], and no Windows users reported trouble as
a result.

Code that attempts to use '''clock clicks'' as an absolute standard
by correlating its values with those returned from '''clock seconds'''
(as in http://wiki.tcl.tk/1035) will also continue to work without
without change, although the improvements to '''clock clicks''' will
certainly provide a better way to do it.

~ Reference Implementation

The original reference implementation at

http://sf.net/tracker/?func=detail&atid=310894&aid=656997&group_id=10894

presents an interface that has since been superseded. The
reference implementation will be updated at such time as this
TIP is approved.

~ Copyright

This document has been placed in the public domain.

~ Comments

Gerald Lester also points out (in the Tcl'ers Chat) that we ought
to make [clock seconds] return a wide value at the same time as
we implement the rest of these changes, in order to address the
Y2038 problem.  Alas, the problem goes deeper; the ''gettimeofday()''
call (and Tcl's mirroring of it in the ''Tcl_GetTime'' interface) is
not Y2038-ready. The necessary upgrades to return a 64-bit value
for [clock seconds] are outside the scope of this TIP.

Several people have informally asked whether 64 bits are enough
to hold the microsecond counter.  Since 2**64 microseconds is
roughly half a million years, the authors are confident that
the answer is, "yes."

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|

|

|




|

|


|


|



|



|






|
|


|
|
|
|


|



|





|



|

|


|
|




|


>

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

# TIP 124: High-Resolution Absolute Time Values From [clock]

	Author:         Mark Harrison <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        20-Dec-2002
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes altering the **clock clicks** command to add
a **-microseconds** option, and to tie it to an absolute reference.

# Rationale

The **clock clicks** command is a useful feature for analyzing and
tuning performance in Tcl programs.  Since the timer is relative,
however, it is difficult to correlate times between two programs or
with timestamps stored in a log file.

# Proposed change

This TIP proposes two changes to **clock clicks** to make it more
useful in situations where absolute times are needed:

   1. Change **clock clicks -milliseconds** to return a wide integer,
      representing the number of milliseconds since the Posix epoch.

   1. Add a **clock clicks -microseconds** that likewise returns
      a wide integer, representing the number of microseconds since
      the Posix epoch.

# Compatibility with existing code

Now that Tcl supports 64-bit integers transparently, compatibility
with existing code is unlikely to cause trouble.  In practice, the
only uses of **clock clicks** that the authors have seen all simply
compute the difference between two successive values.  Since the
difference will continue to fit in 32 bits if it did so before,
such code will simply continue to work.

The change from a relative standard to an absolute one is
likewise transparent.  One fact that supports this claim is that
such a change was made in **clock clicks -milliseconds** on Windows
in support of [[7]](7.md), and no Windows users reported trouble as
a result.

Code that attempts to use **clock clicks_ as an absolute standard
by correlating its values with those returned from **clock seconds**
\(as in <http://wiki.tcl.tk/1035\)> will also continue to work without
without change, although the improvements to **clock clicks** will
certainly provide a better way to do it.

# Reference Implementation

The original reference implementation at

<http://sf.net/tracker/?func=detail&atid=310894&aid=656997&group\_id=10894>

presents an interface that has since been superseded. The
reference implementation will be updated at such time as this
TIP is approved.

# Copyright

This document has been placed in the public domain.

# Comments

Gerald Lester also points out \(in the Tcl'ers Chat\) that we ought
to make [clock seconds] return a wide value at the same time as
we implement the rest of these changes, in order to address the
Y2038 problem.  Alas, the problem goes deeper; the _gettimeofday\(\)_
call \(and Tcl's mirroring of it in the _Tcl\_GetTime_ interface\) is
not Y2038-ready. The necessary upgrades to return a 64-bit value
for [clock seconds] are outside the scope of this TIP.

Several people have informally asked whether 64 bits are enough
to hold the microsecond counter.  Since 2\*\*64 microseconds is
roughly half a million years, the authors are confident that
the answer is, "yes."

Name change from tip/125.tip to tip/125.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
136
137
138
139
140
141
142
143
144
145
146
147

TIP:            125
Title:          Converting between Frame and Toplevel Windows
Version:        $Revision: 1.10 $
Author:         Brian Griffin <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         Sacha Sch�r <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        20-Jan-2003
Post-History:   
Keywords:       reparent,Tk
Tcl-Version:    8.5


~ Abstract

This TIP modifies the '''wm''' command to act as a geometry manager for
Frames, allowing them to become Toplevel windows.

~ Rationale

One of the usability features introduced recently in many windowing systems,
is the ability to "tear out" or "insert" sub-frames and panes within an
application. The most common form of this is the ability to tear off a
toolbar, making it an independent window. This feature gives the end user the
ability to configure the application in ways that best suit them and improve
their overall productivity.

Currently there is no mechanism with Tk to move a widget subtree to a new
toplevel parent without reconstructing the hierarchy from scratch. The basic
command will give the Tk programmer the ability to implement megawidgets that
support tear-off toolbars, notebooks, etc., since the children widgets of the
frame will follow along, unchanged.

An alternative approach has been taken from the orignal '''wm toplevel'''
proposal as described here:

In Tk, Toplevel windows are basically a special form of a Frame which are
managed by the window manager. The proposal is to add the commands '''wm
manage''' and '''wm forget''' which will take an arbitrary Frame and allow it
to be managed by the window manager, making it a Toplevel window.

There are three configure options of Toplevel that are not present on a frame,
'''-menu''', '''-screen''', and '''-use'''. The options '''-screen''' and
'''-use''' can only be specified when a Toplevel is created and cannot be
modified later. The '''-menu''' option can be modified after widget creation
and should be available on a frame so that when the frame is managed as a
Toplevel, the menu can be present, therefore, this option has been added to
the Frame widget. When a frame is not managed as a toplevel, the '''-menu'''
option is ignored.

Note: because of special conditions of Toplevel, it is necessary to restrict
them to only be managed by the window manager; they cannot be converted to
frames and therefore, '''wm forget''' is not allowed on a Toplevel widget.

~ Reference Implementation

TkToolkit patch #998125 implements the '''wm manage''' and '''wm forget'''
commands on Unix and Windows. A partial MacOSX implementation is also
provided. This implementation only works for buttons and menubuttons. For the
remaining Tk widgets to be present in a '''wm manage''''d frame, the widgets
need to recognize and implement the TK_URBAN_RENEWAL flag.

The original '''wm toplevel''' implementation can be obtained
[ftp://ftp.model.com/pub/tcl/reframe], with patch files as well as Linux and
Win32 builds of 8.3.4 and 8.4.1 available.

The ''demo.tcl'' file illustrates the basic function.

~ Known Issues

The reference implementation works on Windows and Linux. A Mac implementation
has been partially implemented. Because of the Mac architecture, it is
necessary to reconstruct widgets in order to remap their window hierarchy.
The reference implementation includes a widget flag, TK_URBAN_RENEWAL which is
used to trigger this reconstruction.

Because of assumptions and restrictions, Toplevels can only be managed by the
window manager and cannot become frames and be managed by any other geometry
manager. This restriction is enforced which means the '''-use''' and
'''-screen''' options do not present any problem or complication with this
proposal.

The toplevel '''-menu''' option has been added to frames. This allows the
setting of menus on a frame so that when the frame is managed as a toplevel,
the menus will appear, otherwise the option is ignored.

~ Alternatives

An alternative to extending the '''wm''' command is to make this feature
either a method or a configure option of the Toplevel and Frame widget.

''A.'' [[''w'' '''detach''']] to convert a Frame into a Toplevel, and [[''w''
attach''']] to convert a Toplevel into a Frame.

''B.'' [[''w'' '''configure -toplevel 1''']] to convert a Frame into a
Toplevel, and [[''w'' '''configure -toplevel 0''']] to convert a Toplevel into
a Frame.

These different approaches (wm, method, config) depend on how the feature is
viewed. One view is that the of changing the nature or class (Toplevel, Frame)
of the widget. An alternative view is that of changing "who" manages the
widget (wm, place, grid, pack).

I suppose another alternative is to follow the precedent of the geometry
managers:

 * '''wm''' ''w'' ?'''-transient''' ''parent''? ?'''-overrideredirect'''
   ''boolean''? ...

 * '''wm forget''' ''w''

~ Comments

''From Sacha Sch�r <[email protected]>:''

The way the TIP and its alternatives are proposed, a frame can be made into a
toplevel and vice versa. However, it is not possible, to move a frame from one
toplevel to another. This is of importance even for the most common motivation
for this TIP, the possibility to implement a tear-off behaviour. If a frame is
going to be teared out of a toplevel window, it might be desirable that it
becomes part of another toplevel window, together with some extra decoration.

I see, that with this more general behaviour, the path name becomes a problem.
Therefore I propose the alternative approach, of making the '''-container'''
and '''-use''' options dynamically configurable as already discussed in the
past

''From Brian:''

The problem is that we can't reparent widgets without changing their Tk widget
pathname. Doing this introduces all kinds of sticky problems.

In practice, the decoration is in the form of Menus, Toolbars, and Footers.
All of these things can (must) be created and managed as part of the
dock/undock process. The way to do this is to create these things the first
time a window is undocked, then just "hide" them when redocking the window;
they still exist, but are just not mapped anywhere, until the next time the
window is undocked.

The bottom line is that the '''wm manage''' command does not do ''everything''
you need when performing an undock operation; it is only a small piece of the
pie, but a very critical one.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|


|














|



|
|



|
|
|


|




|

|

|


|
|

|



|

|




|




|
|


|



|

|


|
|

|
|


|
|

|




|
|

|

|

|









|
|


|





|





|



|


>

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
136
137
138
139
140
141
142
143
144
145
146
147

# TIP 125: Converting between Frame and Toplevel Windows

	Author:         Brian Griffin <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         Sacha Schär <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        20-Jan-2003
	Post-History:   
	Keywords:       reparent,Tk
	Tcl-Version:    8.5
-----

# Abstract

This TIP modifies the **wm** command to act as a geometry manager for
Frames, allowing them to become Toplevel windows.

# Rationale

One of the usability features introduced recently in many windowing systems,
is the ability to "tear out" or "insert" sub-frames and panes within an
application. The most common form of this is the ability to tear off a
toolbar, making it an independent window. This feature gives the end user the
ability to configure the application in ways that best suit them and improve
their overall productivity.

Currently there is no mechanism with Tk to move a widget subtree to a new
toplevel parent without reconstructing the hierarchy from scratch. The basic
command will give the Tk programmer the ability to implement megawidgets that
support tear-off toolbars, notebooks, etc., since the children widgets of the
frame will follow along, unchanged.

An alternative approach has been taken from the orignal **wm toplevel**
proposal as described here:

In Tk, Toplevel windows are basically a special form of a Frame which are
managed by the window manager. The proposal is to add the commands **wm
manage** and **wm forget** which will take an arbitrary Frame and allow it
to be managed by the window manager, making it a Toplevel window.

There are three configure options of Toplevel that are not present on a frame,
**-menu**, **-screen**, and **-use**. The options **-screen** and
**-use** can only be specified when a Toplevel is created and cannot be
modified later. The **-menu** option can be modified after widget creation
and should be available on a frame so that when the frame is managed as a
Toplevel, the menu can be present, therefore, this option has been added to
the Frame widget. When a frame is not managed as a toplevel, the **-menu**
option is ignored.

Note: because of special conditions of Toplevel, it is necessary to restrict
them to only be managed by the window manager; they cannot be converted to
frames and therefore, **wm forget** is not allowed on a Toplevel widget.

# Reference Implementation

TkToolkit patch \#998125 implements the **wm manage** and **wm forget**
commands on Unix and Windows. A partial MacOSX implementation is also
provided. This implementation only works for buttons and menubuttons. For the
remaining Tk widgets to be present in a **wm manage**'d frame, the widgets
need to recognize and implement the TK\_URBAN\_RENEWAL flag.

The original **wm toplevel** implementation can be obtained
[ftp://ftp.model.com/pub/tcl/reframe], with patch files as well as Linux and
Win32 builds of 8.3.4 and 8.4.1 available.

The _demo.tcl_ file illustrates the basic function.

# Known Issues

The reference implementation works on Windows and Linux. A Mac implementation
has been partially implemented. Because of the Mac architecture, it is
necessary to reconstruct widgets in order to remap their window hierarchy.
The reference implementation includes a widget flag, TK\_URBAN\_RENEWAL which is
used to trigger this reconstruction.

Because of assumptions and restrictions, Toplevels can only be managed by the
window manager and cannot become frames and be managed by any other geometry
manager. This restriction is enforced which means the **-use** and
**-screen** options do not present any problem or complication with this
proposal.

The toplevel **-menu** option has been added to frames. This allows the
setting of menus on a frame so that when the frame is managed as a toplevel,
the menus will appear, otherwise the option is ignored.

# Alternatives

An alternative to extending the **wm** command is to make this feature
either a method or a configure option of the Toplevel and Frame widget.

_A._ [_w_ **detach**] to convert a Frame into a Toplevel, and [_w_
attach**] to convert a Toplevel into a Frame.

_B._ [_w_ **configure -toplevel 1**] to convert a Frame into a
Toplevel, and [_w_ **configure -toplevel 0**] to convert a Toplevel into
a Frame.

These different approaches \(wm, method, config\) depend on how the feature is
viewed. One view is that the of changing the nature or class \(Toplevel, Frame\)
of the widget. An alternative view is that of changing "who" manages the
widget \(wm, place, grid, pack\).

I suppose another alternative is to follow the precedent of the geometry
managers:

 * **wm** _w_ ?**-transient** _parent_? ?**-overrideredirect**
   _boolean_? ...

 * **wm forget** _w_

# Comments

_From Sacha Schär <[email protected]>:_

The way the TIP and its alternatives are proposed, a frame can be made into a
toplevel and vice versa. However, it is not possible, to move a frame from one
toplevel to another. This is of importance even for the most common motivation
for this TIP, the possibility to implement a tear-off behaviour. If a frame is
going to be teared out of a toplevel window, it might be desirable that it
becomes part of another toplevel window, together with some extra decoration.

I see, that with this more general behaviour, the path name becomes a problem.
Therefore I propose the alternative approach, of making the **-container**
and **-use** options dynamically configurable as already discussed in the
past

_From Brian:_

The problem is that we can't reparent widgets without changing their Tk widget
pathname. Doing this introduces all kinds of sticky problems.

In practice, the decoration is in the form of Menus, Toolbars, and Footers.
All of these things can \(must\) be created and managed as part of the
dock/undock process. The way to do this is to create these things the first
time a window is undocked, then just "hide" them when redocking the window;
they still exist, but are just not mapped anywhere, until the next time the
window is undocked.

The bottom line is that the **wm manage** command does not do _everything_
you need when performing an undock operation; it is only a small piece of the
pie, but a very critical one.

# Copyright

This document has been placed in the public domain.

Name change from tip/126.tip to tip/126.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202

TIP:		126
Title:		Rich Strings for Representation Persistence
Created:	30-Jan-2003
Author:		Donal K. Fellows <[email protected]>
Type:		Project
Tcl-Version:	9.0
Vote:		Pending
State:		Draft
Version:	$Revision: 1.1 $
Post-History:	


~Abstract

This TIP enriches the standard UTF-8 string representation of every
''Tcl_Obj'' to allow for improved persistence of non-string
representations.  This, combined with rules for substring and
substitution handling, allows the lifetime of an object to correspond
far more closely with the more-broadly understood concept of "object
lifetime".

~Rationale

At the moment in Tcl, whenever someone wants to create a stateful
entity of limited lifespan (i.e. an object) and pass it through a Tcl
script, they have to do one of two things:

 1. Tie the lifespan of the object to the lifespan of the ''Tcl_Obj''
    value that represents it, so that when the internal representation
    of the value is deleted, so to is the object.

 2. Create a table (typically a hash table) of objects and have the
    value passed through the Tcl script be a handle that is really an
    index into this table.  Deletion happens precisely when some kind
    of delete "method" is called on the object.

Each of these techniques has problems.  With the first, difficulties
arise because it is a fundamental assumption of Tcl that it is always
possible to recreate the internal-representation part of a value from
the string-representation part of the value.  While this is a good
assumption for lists, numbers, etc. it is not true for anything where
the deletion of the internal-rep results in the deletion of the
underlying data structure.  Thus, there is a tendency for the object
to get deleted far too early.  (In practise, the problem occurs in
locations like scripts passed to Tk's [[bind]] command and in some
invocations of the [[eval]] command.)  Nevertheless, this technique
can be used subject to some caveats, and this is done in a number of
extensions (e.g. TclBlend/Jacl, where Java objects are passed through
Tcl this way.)

However, the second technique has a different set of troubles.
Although the process of explicit deletion works around all the faults
with over-early deletion as described above, it instead has a strong
tendency to not delete objects at all; it is far too easy to have a
resource leak that is fairly difficult to track down.  Most Tcl
extensions that deal with objects (and all the ones that predate
Tcl8.0, like [[incr Tcl]]) use this technique.

What we really need is a way to allow non-string object
representations to persist substantially longer, so making the first
of the two techniques outlined above much more robust.  In particular,
I have identified the string concatenation, string substitution and
substring operations as being in need of attention, though obviously
the required work will extend further as well (the script parser is an
obvious target.)  This is the focus of this TIP.

~Alterations to the Tcl_Obj

So, what is the best way of maintaining these valuable representations
within a supposedly pure-string Tcl_Obj value?  Well, since we do not
want to alter the internal representation (after all, it is that which
we would really like to preserve) we will have to add an extra field
(or potentially more) to the Tcl_Obj structure itself.  This is
technically feasible in a backward-compatible way, as allocation of
instances of this structure have always been performed by the Tcl
library, but there is a significant downside to this in that the
structure is far and away the most common structure allocated in the
entire Tcl core.  Any field added will have a significant impact on
the overall memory consumption of any Tcl-enabled binary.

What information do we actually need to store for these
representations to be preserved in a string while allowing extraction
of the underlying values?  The simplest possible option is for a list
of string-subrange/object-reference pairs to be associated with the
object, probably as an array of simple structures pointed to by a new
field of the Tcl_Obj (with a NULL indicating that no range of the
string has an object associated with it.)  The easiest way of
representing those string ranges is as pairs of byte-indexes relative
to the start of the string, though character-indexes have much to
commend them (especially when working with strings with a UCS-16
internal representation) as do direct pointers into the string (easy
to compute, but much more problematic when another string is
appended.)  The end of the list would be marked in some obvious way,
probably by using a NULL in the object-reference part.

This mechanism has the advantage that it keeps the increase in size of
the Tcl_Obj itself fairly small (i.e. an extra 4 bytes for another
pointer on 32-bit platforms) which is an advantage when you consider
the fact that it is likely that most strings in an average Tcl program
will not have objects contained within them.  This will act to
minimise the overall memory overhead.

~Concatenation, Substitution and Substring Semantics

When two strings with these object annotations are concatenated, it is
clear that the resulting string should also have the annotations (and
the actual human-readable part will use the string-representation of
the objects), and this is trivially extended to arbitrary
concatenations of strings.  Similarly for the taking of substrings
with the following restrictions:

 1. Where the portion of substring taken corresponds exactly to the
    part of a string associated with an object, the operation shall
    instead return the object in question (which shall be assumed to
    have a compatible string representation.)

 2. Where a substring wholly contains a range associated with some
    object, then the resulting substring object will also contain the
    object associated with the "same" characters.

 3. Where a substring only partially overlaps a range associated with
    an object, that object will not be associated with the
    corresponding characters in the resultant substring (unless the
    object is separately part of the substring due to the other rules,
    of course.)  The object is associated with the string segment as a
    whole, and not any one part of it.

Substitution, whether of variable contents, script execution results
or anything else, is semantically a concatenation operation where some
strings are (as it were) immediate operands and others are derived
from reading variables, executing scripts, etc.

Thus, if we start variable ''a'' containing an object ''Ob1'' and
variable ''b'' containing an object ''Ob2'', the following shall be
true:

|set var x${a}y${b}z        => xOb1yOb2z
|#  where characters 1-3 are assocaited with Ob1
|#    and characters 5-7 are associated with Ob2
|set c [string range $var 1 3]
|#  precisely equivalent to [set c $a]
|set d [string range $var 5 7]
|#  precisely equivalent to [set d $b]

~Consequences

It is an obvious consequence of this that script evaluation should
take into account of these object annotations when attached to the
scripts themselves, particularly as the process of parsing can really
be regarded as being mostly the taking of (suitable) substrings.  Only
slightly less obviously, it is also the responsibility of all code
that stores strings (and especially scripts) for future use to store
them as ''Tcl_Obj'' instances and not as just plain character strings,
and to perform any substitutions it needs to perform in a way that
preserves these object annotations on the parts that it is not
interested in.  This in turn will probably require changes on the part
of many extensions to actually turn into reality.

On the other hand, there are quite a few objects (numbers and boolean
values are probably very good examples here) for which this
representation preservation is probably not a very good option as the
objects in question are perfectly preservable.  It makes sense to add
some kind of signalling mechanism (e.g. a bit in a newly added
''flags'' field) to allow the type of a ''Tcl_Obj'' instance to
declare that it need not be preserved.  As a general note, such a flag
would only be useful in "leaf" objects; structural objects (i.e. those
that are intended to contain others, like lists) would be expected to
do without this.

Strings (now a structural as opposed to a leaf type) probably need
even more special handling, but that can really be regarded as a
type-specific special case.

The flags field mentioned a few paragraphs above would probably have
other potential uses (e.g. for marking an object as being impossible
to change into any other type) though these lie outside the scope of
this TIP.

Because these changes at the C API level are far reaching and fairly
subtle in some cases, this TIP explicitly seeks to introduce this
behaviour with a major version number change.  Although the alteration
at the script level should be small - existing code should continue
working without alteration - it is a huge philosophical leap as it
will no longer be the case that everything in Tcl will be a string, or
at least not a string that you (or anyone else) can type.  Again, that
implies introduction at a new major version number.

~Notes

 * The existing API function ''Tcl_InvalidateStringRep'' will gain
   additional significance with the introduction of this TIP: its
   invocation may well trigger the deletion of many objects.

 * It is probably a very good idea indeed for code that creates
   objects whose lifespan is meant to persist, to create those objects
   with string representations composed entirely of alphanumeric
   characters.  An ideal choice might be to use a prefix derived from
   the type/class of the object, and a suffix that is the address of
   the object or the next value from some counter variable.

~Copyright

This document is placed in the public domain.

<
|
|
|
|
|
|
|
<
|
>

|


|





|


|


|



|











|
|
|

|
|






|
|






|
|

|


|
|
|
|












|
|


|
|

|



|
|




|


|

|





|
|







|

|




|


|
|


|
|
|
|
|
|
|

|




|

|
|





|
|


|
|

|
|


|




|
|








|


|

|










|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202

# TIP 126: Rich Strings for Representation Persistence
	Created:	30-Jan-2003
	Author:		Donal K. Fellows <[email protected]>
	Type:		Project
	Tcl-Version:	9.0
	Vote:		Pending
	State:		Draft

	Post-History:	
-----

# Abstract

This TIP enriches the standard UTF-8 string representation of every
_Tcl\_Obj_ to allow for improved persistence of non-string
representations.  This, combined with rules for substring and
substitution handling, allows the lifetime of an object to correspond
far more closely with the more-broadly understood concept of "object
lifetime".

# Rationale

At the moment in Tcl, whenever someone wants to create a stateful
entity of limited lifespan \(i.e. an object\) and pass it through a Tcl
script, they have to do one of two things:

 1. Tie the lifespan of the object to the lifespan of the _Tcl\_Obj_
    value that represents it, so that when the internal representation
    of the value is deleted, so to is the object.

 2. Create a table \(typically a hash table\) of objects and have the
    value passed through the Tcl script be a handle that is really an
    index into this table.  Deletion happens precisely when some kind
    of delete "method" is called on the object.

Each of these techniques has problems.  With the first, difficulties
arise because it is a fundamental assumption of Tcl that it is always
possible to recreate the internal-representation part of a value from
the string-representation part of the value.  While this is a good
assumption for lists, numbers, etc. it is not true for anything where
the deletion of the internal-rep results in the deletion of the
underlying data structure.  Thus, there is a tendency for the object
to get deleted far too early.  \(In practise, the problem occurs in
locations like scripts passed to Tk's [bind] command and in some
invocations of the [eval] command.\)  Nevertheless, this technique
can be used subject to some caveats, and this is done in a number of
extensions \(e.g. TclBlend/Jacl, where Java objects are passed through
Tcl this way.\)

However, the second technique has a different set of troubles.
Although the process of explicit deletion works around all the faults
with over-early deletion as described above, it instead has a strong
tendency to not delete objects at all; it is far too easy to have a
resource leak that is fairly difficult to track down.  Most Tcl
extensions that deal with objects \(and all the ones that predate
Tcl8.0, like [incr Tcl]\) use this technique.

What we really need is a way to allow non-string object
representations to persist substantially longer, so making the first
of the two techniques outlined above much more robust.  In particular,
I have identified the string concatenation, string substitution and
substring operations as being in need of attention, though obviously
the required work will extend further as well \(the script parser is an
obvious target.\)  This is the focus of this TIP.

# Alterations to the Tcl\_Obj

So, what is the best way of maintaining these valuable representations
within a supposedly pure-string Tcl\_Obj value?  Well, since we do not
want to alter the internal representation \(after all, it is that which
we would really like to preserve\) we will have to add an extra field
\(or potentially more\) to the Tcl\_Obj structure itself.  This is
technically feasible in a backward-compatible way, as allocation of
instances of this structure have always been performed by the Tcl
library, but there is a significant downside to this in that the
structure is far and away the most common structure allocated in the
entire Tcl core.  Any field added will have a significant impact on
the overall memory consumption of any Tcl-enabled binary.

What information do we actually need to store for these
representations to be preserved in a string while allowing extraction
of the underlying values?  The simplest possible option is for a list
of string-subrange/object-reference pairs to be associated with the
object, probably as an array of simple structures pointed to by a new
field of the Tcl\_Obj \(with a NULL indicating that no range of the
string has an object associated with it.\)  The easiest way of
representing those string ranges is as pairs of byte-indexes relative
to the start of the string, though character-indexes have much to
commend them \(especially when working with strings with a UCS-16
internal representation\) as do direct pointers into the string \(easy
to compute, but much more problematic when another string is
appended.\)  The end of the list would be marked in some obvious way,
probably by using a NULL in the object-reference part.

This mechanism has the advantage that it keeps the increase in size of
the Tcl\_Obj itself fairly small \(i.e. an extra 4 bytes for another
pointer on 32-bit platforms\) which is an advantage when you consider
the fact that it is likely that most strings in an average Tcl program
will not have objects contained within them.  This will act to
minimise the overall memory overhead.

# Concatenation, Substitution and Substring Semantics

When two strings with these object annotations are concatenated, it is
clear that the resulting string should also have the annotations \(and
the actual human-readable part will use the string-representation of
the objects\), and this is trivially extended to arbitrary
concatenations of strings.  Similarly for the taking of substrings
with the following restrictions:

 1. Where the portion of substring taken corresponds exactly to the
    part of a string associated with an object, the operation shall
    instead return the object in question \(which shall be assumed to
    have a compatible string representation.\)

 2. Where a substring wholly contains a range associated with some
    object, then the resulting substring object will also contain the
    object associated with the "same" characters.

 3. Where a substring only partially overlaps a range associated with
    an object, that object will not be associated with the
    corresponding characters in the resultant substring \(unless the
    object is separately part of the substring due to the other rules,
    of course.\)  The object is associated with the string segment as a
    whole, and not any one part of it.

Substitution, whether of variable contents, script execution results
or anything else, is semantically a concatenation operation where some
strings are \(as it were\) immediate operands and others are derived
from reading variables, executing scripts, etc.

Thus, if we start variable _a_ containing an object _Ob1_ and
variable _b_ containing an object _Ob2_, the following shall be
true:

	set var x${a}y${b}z        => xOb1yOb2z
	#  where characters 1-3 are assocaited with Ob1
	#    and characters 5-7 are associated with Ob2
	set c [string range $var 1 3]
	#  precisely equivalent to [set c $a]
	set d [string range $var 5 7]
	#  precisely equivalent to [set d $b]

# Consequences

It is an obvious consequence of this that script evaluation should
take into account of these object annotations when attached to the
scripts themselves, particularly as the process of parsing can really
be regarded as being mostly the taking of \(suitable\) substrings.  Only
slightly less obviously, it is also the responsibility of all code
that stores strings \(and especially scripts\) for future use to store
them as _Tcl\_Obj_ instances and not as just plain character strings,
and to perform any substitutions it needs to perform in a way that
preserves these object annotations on the parts that it is not
interested in.  This in turn will probably require changes on the part
of many extensions to actually turn into reality.

On the other hand, there are quite a few objects \(numbers and boolean
values are probably very good examples here\) for which this
representation preservation is probably not a very good option as the
objects in question are perfectly preservable.  It makes sense to add
some kind of signalling mechanism \(e.g. a bit in a newly added
_flags_ field\) to allow the type of a _Tcl\_Obj_ instance to
declare that it need not be preserved.  As a general note, such a flag
would only be useful in "leaf" objects; structural objects \(i.e. those
that are intended to contain others, like lists\) would be expected to
do without this.

Strings \(now a structural as opposed to a leaf type\) probably need
even more special handling, but that can really be regarded as a
type-specific special case.

The flags field mentioned a few paragraphs above would probably have
other potential uses \(e.g. for marking an object as being impossible
to change into any other type\) though these lie outside the scope of
this TIP.

Because these changes at the C API level are far reaching and fairly
subtle in some cases, this TIP explicitly seeks to introduce this
behaviour with a major version number change.  Although the alteration
at the script level should be small - existing code should continue
working without alteration - it is a huge philosophical leap as it
will no longer be the case that everything in Tcl will be a string, or
at least not a string that you \(or anyone else\) can type.  Again, that
implies introduction at a new major version number.

# Notes

 * The existing API function _Tcl\_InvalidateStringRep_ will gain
   additional significance with the introduction of this TIP: its
   invocation may well trigger the deletion of many objects.

 * It is probably a very good idea indeed for code that creates
   objects whose lifespan is meant to persist, to create those objects
   with string representations composed entirely of alphanumeric
   characters.  An ideal choice might be to use a prefix derived from
   the type/class of the object, and a suffix that is the address of
   the object or the next value from some counter variable.

# Copyright

This document is placed in the public domain.

Name change from tip/127.tip to tip/127.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
136

137
138
139
140
141
142
143
144
145
146
147
148

TIP:            127
Title:          Add an -index Option to [lsearch]
Version:        $Revision: 1.13 $
Author:         Michael Schlenker <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        26-Feb-2003
Post-History:   
Tcl-Version:    8.5


~ Abstract

Matching the ''lsort'' functionality a ''-index'' option should be
added to the ''lsearch'' command to make searching lists in list
easier. The ''lsort -index'' and the ''lsearch -index'' options should
accept list style indices like ''lindex'' and ''lset'' do.  This TIP
proposes such added options.

~ Specification

Under this proposal the syntax of the ''lsearch'' is to be modified to
accept two extra options. 

The ''-index'' option:

The ''lsort'' -index option would get enhanced with multiple index
support.

|    lsearch ?-index index? 

The ''-index'' option should work similar to the ''-index'' option
in the ''lsort'' command.

If this option is specified, each of the elements of list must itself
be a proper Tcl sublist.  Instead of searching based on whole
sublists, ''lsearch'' will extract the index'th element from each
sublist and search based on the given element.  The keyword end is
allowed for the index to search on the last sublist element, and
end-index searches on a sublist element offset from the end. For
example,

|    lsearch -integer -index 1 {{First 24} {Second 18} {Third 30}} 18

returns ''1'', and

|    lsearch -index end-1 {{a 1 e i} {b 2 3 f g} {c 4 5 6 d h}} d

returns ''2''.

The index given to ''lsearch -index'' and ''lsort -index'' may be
either a single scalar index as in the current ''lsort''
implementation or the argument to ''-index'' may be a list of scalar
indices (similar, but not exactly like the lset/lindex multiple
indices).  The -index option causes lsearch and lsort to extract the
item for searching or sorting comparision from the list element by
using in effect ''lindex $element $index''.

For example:

|    set record {
|        {

|          {James Dean} {Musician} {some other data}
|        }
|        {


|          {Elvis Presley} {Musician} {some more data}
|        }
|     }


|
|   lsearch -index {0 0} $record "Elvis"

returns ''1''.

|   lsort -dictionary -decreasing -index {0 1} $record

returns ''{{{Elvis Presley} {Musician} {some more data}} {{James Dean}
{Musician} {some other data}}}''.

Note: The following example is invalid, -index only takes a list as
argument, unlike lset and lindex, that take either a list or multiple
arguments, that get concatenated by the command.

| lsearch -index 1 1 $record Presley

The ''-subindices'' option:

The ''-subindices'' option should be added only to the ''lsearch''
command as a convenience shortcut. It is only a valid option if the
''-index'' option is also used.

If ''-subindices'' is given, ''lsearch'' should return a list of
indices that can be used directly by ''lindex'' or ''lset'' to
manipulate the element used for searching, instead of the top level
element of the list.

If ''-subindices'' and ''-inline'' are specified at the same time, the
command returns the value instead of the index.

example:

| lsearch -subindices -index {0 0} $record Elvis

returns ''{1 0 0}''.

If no -all option is specified, this is the same as doing:

| concat [lsearch -index {0 0} $record Elvis] [list 0 0]

~ Rationale

Lists containing one or more level of sublists are a common technique to
simulated complex data structures like matrices or records, or for
results from database queries.  The ''lsort'' command was enhanced
with the ''-index'' option for this case, to handle sorting on sublist
keys.

The ''lsearch'' command does not have this functionality yet, one has
to use ''foreach'' and ''lindex'' to loop over the list one by one.

Multiple indices for the ''-index'' option to both ''lsearch'' and
''lsort'' should be added, to make the option more similar to ''lset''
and ''lindex'' style indices.

The ''-subindices'' option is a convenience option to make constructs
like this example work well:

| foreach item [lsearch -all -subindices -index {0 0} $record bla] {
|         lset record $item bar
| }


Without the subindices option it could be written as:

| foreach item [lsearch -all -index $idx $record bla] {
|         lset record [concat $idx $item] bar
| }


~ Reference Implementation

A reference implementation exists, see the files attached to the Tcl
Patch 693836 on SourceForge.
http://sf.net/tracker/?func=detail&atid=310894&aid=693836&group_id=10894

The reference implementation isn't honouring the -inline option if
given in conjuction with -subindices, at the moment.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|
|
|


|

|


|

|


|

|
|



|





|

|

|

|

|
|
|
|
|

|



|
<
>
|
<
<
>
>
|
<
<
>
>
|
|

|

|

|
|





|

|

|

|

|
|



|




|

|



|

|



|
|


|
|

|
|
|

|


|
|
<
>



|
|
<
|
>
|



|




|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148

# TIP 127: Add an -index Option to [lsearch]

	Author:         Michael Schlenker <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        26-Feb-2003
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

Matching the _lsort_ functionality a _-index_ option should be
added to the _lsearch_ command to make searching lists in list
easier. The _lsort -index_ and the _lsearch -index_ options should
accept list style indices like _lindex_ and _lset_ do.  This TIP
proposes such added options.

# Specification

Under this proposal the syntax of the _lsearch_ is to be modified to
accept two extra options. 

The _-index_ option:

The _lsort_ -index option would get enhanced with multiple index
support.

	    lsearch ?-index index? 

The _-index_ option should work similar to the _-index_ option
in the _lsort_ command.

If this option is specified, each of the elements of list must itself
be a proper Tcl sublist.  Instead of searching based on whole
sublists, _lsearch_ will extract the index'th element from each
sublist and search based on the given element.  The keyword end is
allowed for the index to search on the last sublist element, and
end-index searches on a sublist element offset from the end. For
example,

	    lsearch -integer -index 1 {{First 24} {Second 18} {Third 30}} 18

returns _1_, and

	    lsearch -index end-1 {{a 1 e i} {b 2 3 f g} {c 4 5 6 d h}} d

returns _2_.

The index given to _lsearch -index_ and _lsort -index_ may be
either a single scalar index as in the current _lsort_
implementation or the argument to _-index_ may be a list of scalar
indices \(similar, but not exactly like the lset/lindex multiple
indices\).  The -index option causes lsearch and lsort to extract the
item for searching or sorting comparision from the list element by
using in effect _lindex $element $index_.

For example:

	    set record {

	        {
	          {James Dean} {Musician} {some other data}


	        }
	        {
	          {Elvis Presley} {Musician} {some more data}


	        }
	     }
	
	   lsearch -index {0 0} $record "Elvis"

returns _1_.

	   lsort -dictionary -decreasing -index {0 1} $record

returns _\{\{\{Elvis Presley\} \{Musician\} \{some more data\}\} \{\{James Dean\}
\{Musician\} \{some other data\}\}\}_.

Note: The following example is invalid, -index only takes a list as
argument, unlike lset and lindex, that take either a list or multiple
arguments, that get concatenated by the command.

	 lsearch -index 1 1 $record Presley

The _-subindices_ option:

The _-subindices_ option should be added only to the _lsearch_
command as a convenience shortcut. It is only a valid option if the
_-index_ option is also used.

If _-subindices_ is given, _lsearch_ should return a list of
indices that can be used directly by _lindex_ or _lset_ to
manipulate the element used for searching, instead of the top level
element of the list.

If _-subindices_ and _-inline_ are specified at the same time, the
command returns the value instead of the index.

example:

	 lsearch -subindices -index {0 0} $record Elvis

returns _\{1 0 0\}_.

If no -all option is specified, this is the same as doing:

	 concat [lsearch -index {0 0} $record Elvis] [list 0 0]

# Rationale

Lists containing one or more level of sublists are a common technique to
simulated complex data structures like matrices or records, or for
results from database queries.  The _lsort_ command was enhanced
with the _-index_ option for this case, to handle sorting on sublist
keys.

The _lsearch_ command does not have this functionality yet, one has
to use _foreach_ and _lindex_ to loop over the list one by one.

Multiple indices for the _-index_ option to both _lsearch_ and
_lsort_ should be added, to make the option more similar to _lset_
and _lindex_ style indices.

The _-subindices_ option is a convenience option to make constructs
like this example work well:

	 foreach item [lsearch -all -subindices -index {0 0} $record bla] {
	         lset record $item bar

	 }

Without the subindices option it could be written as:

	 foreach item [lsearch -all -index $idx $record bla] {
	         lset record [concat $idx $item] bar

	 }

# Reference Implementation

A reference implementation exists, see the files attached to the Tcl
Patch 693836 on SourceForge.
<http://sf.net/tracker/?func=detail&atid=310894&aid=693836&group\_id=10894>

The reference implementation isn't honouring the -inline option if
given in conjuction with -subindices, at the moment.

# Copyright

This document has been placed in the public domain.

Name change from tip/128.tip to tip/128.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

TIP:            128
Title:          Ability to Install a Custom Memory Allocator
Version:        $Revision: 1.5 $
Author:         Christophe Cap <[email protected]>
Author:         Mike Jackson <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        13-Mar-2003
Post-History:   
Tcl-Version:    8.6


~ Abstract

This TIP alters Tcl to allow embedded uses of the Tcl library (and any
extensions) to either use the Tcl memory allocators as their main
allocator (especially in C++) or to set the memory allocator that Tcl
uses for itself through ''ckalloc()''.

~ Background

A while ago I was experiencing troubles when allocating images
([[image create photo]]) while memory was already exhausted, my app
crashed (due to known bug item #698571, which is in the HEAD by now!)
This shouldn't happen anyway since my application had it's new handler
set.

Tracing down the source of the allocators I noticed that Tcl uses
''HeapAlloc()'' (on Win32) to allocate its memory.  Why not use
''malloc()''?

~ New/Malloc Handler 

It would be nice to be able to catch memory allocation errors with a
custom new handler.

A solution could be to replace ''HeapAlloc()'' (on Win32) and other
platform specific memory handlers should be replaced by ''malloc()''.

This way a new handler can by set through ''set_new_handler()''.

Note that the Microsoft VC++ compiler has some ANSI incompatibility in
that it uses ''_set_new_handler()'' rather than ''set_new_handler()''.
We would naturally conceal this platform difference.

For example:

|#include <new> 
|
|//
|// New handler for Microsoft Visual C++ compiler
|//
|
|#ifdef _MSC_VER
|#include <new.h>
|
|int __cdecl _newHandler(size_t size )
|{

|   // Do whatever
|
|   return 0;
|}

|
|#else
|
|//
|// Ansi C/C++ new handler
|//
|
|void __cdecl _newHandler( void )
|{
|   // Do whatever
|}
|#endif
|
|void sethandlers(void)
|{
|// Microsoft compiler 
|#ifdef _MSC_VER  
|
|   _set_new_handler (_newHandler); // Setup new handler
|   _set_new_mode( 1 ); // Re-route malloc failures to new handler !
|
|// Ansi compiler 
|
|#else 
|
|   set_new_handler (_newHandler); // ANSI new handler
|
|#endif
|}






















~ Tcl Implementation 

The above suggested solution could work for some compilers, but may
not for all (some compilers might not support setting a malloc failure
callback.)  Therefore a Tcl custom new handler functionality could be
implemented that handles Tcl specific memory allocation failures.

Something like: ''Tcl_SetMemHandler()''?

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|
|
|

|


|
|




|
|

|




|
|

|

|
|




|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
|
|
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|


|
|


|

|


>

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

# TIP 128: Ability to Install a Custom Memory Allocator

	Author:         Christophe Cap <[email protected]>
	Author:         Mike Jackson <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        13-Mar-2003
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

This TIP alters Tcl to allow embedded uses of the Tcl library \(and any
extensions\) to either use the Tcl memory allocators as their main
allocator \(especially in C\+\+\) or to set the memory allocator that Tcl
uses for itself through _ckalloc\(\)_.

# Background

A while ago I was experiencing troubles when allocating images
\([image create photo]\) while memory was already exhausted, my app
crashed \(due to known bug item \#698571, which is in the HEAD by now!\)
This shouldn't happen anyway since my application had it's new handler
set.

Tracing down the source of the allocators I noticed that Tcl uses
_HeapAlloc\(\)_ \(on Win32\) to allocate its memory.  Why not use
_malloc\(\)_?

# New/Malloc Handler 

It would be nice to be able to catch memory allocation errors with a
custom new handler.

A solution could be to replace _HeapAlloc\(\)_ \(on Win32\) and other
platform specific memory handlers should be replaced by _malloc\(\)_.

This way a new handler can by set through _set\_new\_handler\(\)_.

Note that the Microsoft VC\+\+ compiler has some ANSI incompatibility in
that it uses _\_set\_new\_handler\(\)_ rather than _set\_new\_handler\(\)_.
We would naturally conceal this platform difference.

For example:

	#include <new> 
	
	//
	// New handler for Microsoft Visual C++ compiler
	//
	
	#ifdef _MSC_VER
	#include <new.h>
	
	int __cdecl _newHandler(size_t size )

	{
	   // Do whatever
	
	   return 0;

	}
	
	#else
	
	//
	// Ansi C/C++ new handler
	//
	
	void __cdecl _newHandler( void )





















	{
	   // Do whatever
	}
	#endif
	
	void sethandlers(void)
	{
	// Microsoft compiler 
	#ifdef _MSC_VER  
	
	   _set_new_handler (_newHandler); // Setup new handler
	   _set_new_mode( 1 ); // Re-route malloc failures to new handler !
	
	// Ansi compiler 
	
	#else 
	
	   set_new_handler (_newHandler); // ANSI new handler
	
	#endif
	}

# Tcl Implementation 

The above suggested solution could work for some compilers, but may
not for all \(some compilers might not support setting a malloc failure
callback.\)  Therefore a Tcl custom new handler functionality could be
implemented that handles Tcl specific memory allocation failures.

Something like: _Tcl\_SetMemHandler\(\)_?

# Copyright

This document has been placed in the public domain.

Name change from tip/129.tip to tip/129.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

TIP:            129
Title:          New Format Codes for the [binary] Command
Version:        $Revision: 1.5 $
Author:         Arjen Markus <[email protected]>
Author:         Torsten Reincke <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        14-Mar-2003
Post-History:   
Keywords:       IEEE,binary data,Tcl
Tcl-Version:    8.5


~ Abstract

This TIP proposes to add a set of new format codes to the '''binary'''
command to enhance its ability to deal with especially non-native
floating-point data.  The assumption is that current limitations are
due to the distinction between little-endian and big-endian storage of
such data.

~ Introduction

The current '''binary''' command can manipulate little-endian and
big-endian ''integer'' data, but only ''native'' floating-point data.
This means that binary data from other computer systems that use a
different representation of floating-point data can not be directly
handled.

The lack of format codes to handle "native" integer data means that
one has to distinguish the current platform's byte ordering to be
platform-independent, whenever the '''binary''' command is used.

Most current computer systems use either little-endian or big-endian
byte order and the so-called IEEE representation for the exponent and
mantissa.  So, the main variation to deal with is the endian-ness.

Some popular file formats, like ESRI's ArcView shape files, use both
types of byte order.  It is difficult (though not impossible) to
handle these files with the current set of format codes.

It should be noted that there ''is'' more variety among floating-point
representation than just the byte order.  This TIP will not solve this
more general problem.

~ Proposed Format Codes

Format codes should be available to catch the two main varieties of
byte ordering.  There should, both for reasons of symmetry and for
practical purposes, also be a full set to deal with "native" data.

For integer types there are no codes to deal with native ordering. So:

 * '''t''' (tiny) for short integers, using native ordering.

 * '''n''' (normal) for ordinary integers, using native ordering.

 * '''m''' (mirror of "w") for wide integers, using native ordering.

The floating-point types will be handled via:

 * '''r'''/'''R''' (real) for single-precision reals.

 * '''q'''/'''Q''' (mirror of "d") for double-precision reals.

where the lower-case is associated with little-endian order and the
upper-case with big-endian order.

~ Implementation Notes

The implementation for the integer types is simple:

 * The new format codes are synonyms for the current ones, but
   different ones for each endian-ness.

The implementation for the floating-point types is somewhat more
complicated, this involves adding byte swapping, if the ordering of
the platform does not correspond to that of the format code.

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|





|

|
|






|






|


|



|







|

|

|



|

|




|










|


>

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

# TIP 129: New Format Codes for the [binary] Command

	Author:         Arjen Markus <[email protected]>
	Author:         Torsten Reincke <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        14-Mar-2003
	Post-History:   
	Keywords:       IEEE,binary data,Tcl
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to add a set of new format codes to the **binary**
command to enhance its ability to deal with especially non-native
floating-point data.  The assumption is that current limitations are
due to the distinction between little-endian and big-endian storage of
such data.

# Introduction

The current **binary** command can manipulate little-endian and
big-endian _integer_ data, but only _native_ floating-point data.
This means that binary data from other computer systems that use a
different representation of floating-point data can not be directly
handled.

The lack of format codes to handle "native" integer data means that
one has to distinguish the current platform's byte ordering to be
platform-independent, whenever the **binary** command is used.

Most current computer systems use either little-endian or big-endian
byte order and the so-called IEEE representation for the exponent and
mantissa.  So, the main variation to deal with is the endian-ness.

Some popular file formats, like ESRI's ArcView shape files, use both
types of byte order.  It is difficult \(though not impossible\) to
handle these files with the current set of format codes.

It should be noted that there _is_ more variety among floating-point
representation than just the byte order.  This TIP will not solve this
more general problem.

# Proposed Format Codes

Format codes should be available to catch the two main varieties of
byte ordering.  There should, both for reasons of symmetry and for
practical purposes, also be a full set to deal with "native" data.

For integer types there are no codes to deal with native ordering. So:

 * **t** \(tiny\) for short integers, using native ordering.

 * **n** \(normal\) for ordinary integers, using native ordering.

 * **m** \(mirror of "w"\) for wide integers, using native ordering.

The floating-point types will be handled via:

 * **r**/**R** \(real\) for single-precision reals.

 * **q**/**Q** \(mirror of "d"\) for double-precision reals.

where the lower-case is associated with little-endian order and the
upper-case with big-endian order.

# Implementation Notes

The implementation for the integer types is simple:

 * The new format codes are synonyms for the current ones, but
   different ones for each endian-ness.

The implementation for the floating-point types is somewhat more
complicated, this involves adding byte swapping, if the ordering of
the platform does not correspond to that of the format code.

# Copyright

This document is placed in the public domain.

Name change from tip/13.tip to tip/13.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251

TIP:            13
Title:          Web Service for Drafting and Archiving TIPs
Version:        $Revision: 1.26 $
Author:         Don Porter <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Accepted
Type:           Process
Vote:           Done
Created:        21-Nov-2000
Post-History:   


~ Abstract

This document proposes the TCT provide a service on the World Wide
Web for drafting and archiving TIPs and for providing TIPs in a
variety of formats.  A reference implementation is provided, and its
server requirements are outlined.

~ Background

It has been proposed (see [2]) that the TCT manage its projects and
procedures through a set of public documents known as Tcl Improvement
Proposals, or TIPs.  A format for TIPs has been approved (see [3]),
and although final approval of [2] is still pending, several TIPs
have been submitted, discussed, and revised, and a few have been
approved, so acceptance of TIPs in some form seems likely.

A prototype system has been provided by Donal
Fellows <[email protected]>
[http://www.cs.man.ac.uk/fellowsd-bin/TIP/]
that delivers TIPs to visitors in a variety of formats.  However,
that system lacks archiving of each revision of each TIP, and
offers no interface (through the web or otherwise) for making
revisions to TIPs.  

The TIP format was inspired by the format used by the Tcl'ers
Wiki [http://www.purl.org/thecliff/tcl/wiki/].  The true power
of the Tcl'ers Wiki, though, is not in the particular format it
uses, but in the fact that it empowers the whole Tcl community to
contribute to a common set of resources.  The Tcl'ers Wiki
shows that valuable resources can arise out of the unrestricted
efforts of volunteers from the community.

~ Problems with Current TIP Infrastructure.

The Fellows web interface to the TIP Document Collection
[http://www.cs.man.ac.uk/fellowsd-bin/TIP/] offers valuable
browsing access to TIPs in a variety of formats.  It accomplishes
the important goal of making TIPs public.  However, it suffers from
two significant shortcomings:

   * Revisions are only possible through the TIP Editor:

   > Currently the only way to revise a TIP is to e-mail a new
     revision to the TIP Editor and wait for it to replace the old
     revision.  As more TIPs are submitted, and as each TIP is more
     frequently revised, this bottleneck will not be tolerable.

   > Discussion about TIPs currently takes place in Usenet newsgroups
     and on mailing lists, but because there is no easy access to
     revising the TIPs themselves, the new information and viewpoints
     arising in these discussions are not being folded back into the
     TIPs.  This means the TIPs are failing in their intended role to
     present a full history of an issue to later readers.  It also
     means newcomers to a TIP cannot receive a full briefing in one
     place, but must chase down discussions in mailing list and Usenet
     archives.  Few people do that, but instead repeat points already
     made.  The discussions about [6] reflect this problem.

   * An archive of each revision of each TIP is not maintained:

   > Although [2] refers to TIPs as being stored in a revision control
     system, probably a CVS repository, the Fellows TIP collection is
     not maintained in such a system.  Since a TIP is an archive of a
     public discussion of an issue, it is important to be able to
     access the history of changes to each TIP.

   > The ability to retrieve and restore earlier revisions of a TIP
     will be especially important if public revision is permitted, so
     that any TIP contents that are incorrectly removed, whether by
     accident or malice, can be restored.

~ Proposal

An improved system for archiving and revising TIPs is proposed:

   1. TIPs will be archived in a CVS repository.

   1. Anyone with the power to call a TYANNOTT vote will have commit
      access to this repository through either :pserver: or ssh
      access.  With this access, they will be able to revise any part
      (header or body) of any TIP (whether in ''State: Draft'' or
      not).  Everyone having this access will be trusted to modify
      TIPs only in conformance with the TIP format and the TCT
      procedures.

   1. An enhanced version of the Fellows TIP rendering engine will
      display an [[Edit]] link at the bottom of each TIP eligible
      for web-editing when that TIP is rendered in HTML.

   1. For any TIP in state Draft, and for which a vote is still
      pending, the [[Edit]] link will lead to an HTML form for
      submitting a revised TIP.  For other TIPs, no [[Edit]] link
      will appear, and an attempt to directly access web-editing of
      such a TIP will lead to a message stating that the TIP may not
      be edited through the web interface.

   1. The HTML editing form will display the TIP header, but will not
      make it available for editing.  The HTML form will require that
      an e-mail address be entered, and will allow a name to be
      entered as well.  A <TEXTAREA> will be initialized to hold the
      current TIP abstract.  A second <TEXTAREA> will be initialized
      to hold the current TIP body.  Users of the form will revise
      the abstract and the body, then submit the form.

   1. The TIP rendering engine will receive the revisions, and
      will use CVS client commands to merge the revisions with other
      revisions and commit the revised TIP to the TIP CVS repository.
      If a conflict occurs during a merge, the TIP body including the
      conflicts will be returned to the user in another HTML form to
      resolve the conflict.

    > Note that the CVS commit function of the TIP rendering engine
      implies that the CGI process in which the TIP rendering engine
      runs must have a user ID with commit access to the TIP CVS
      repository.

   1. In the revised TIP checked in to CVS the submitter of the
      revision will be added as an Author in the header of that TIP.

~ Reference Implementation

The modifications to the Fellows TIP rendering engine that add the
capabilities proposed above are now merged in.  The TIP rendering
engine is maintained and publically available
[http://sourceforge.net/projects/tiprender/].  To enable the
web-editing features, set the Tcl variable FEATURE(EDIT) to 1 in
the file config.tcl.  A working version of the proposed web service
is available at http://purl.org/tcl/tip/

For what it's worth, this TIP was created primarily within a web
browser, making revisions through the web interface provided by the
reference implementation.

One remaining shortcoming of the reference implementation is that it
provides no mechanism for uploading images to the TIP repository.
Images still need to be submitted through the TIP Editor, or
someone else with commit access to the TIP CVS repository.

~ Server Requirements

The reference implementation imposes the following requirements on a
server:

   1. The server provides an HTTP server that serves the public
      Internet, and supports the CGI interface.

   1. CVS client software must be installed on the server.

   1. The CVS repository containing TIPs must be on the server itself.
      This is due to a CVS limitation that ''loginfo'' scripts run on
      the machine housing the CVS repository, and the reference
      implementation uses a ''loginfo'' script to keep the TIPs
      presented through the web up to date with the commits to the
      repository.

   1. The CVS repository must offer commit access over the Internet
      using either :pserver: or ssh to everyone with authority to call
      a TYANNOTT vote.

   1. The user under which the HTTP server runs its CGI processes must
      have commit access to the TIP CVS repository.  This may have
      security implications.

~ Future Improvements

Once the TIPs are housed in a CVS repository, other services should be
easier to implement.  Another browsing interface could be provided
using cvsweb [http://stud.fh-heilbronn.de/~zeller/cgi/cvsweb.cgi/] to
allow anyone in the community to browse TIP history.  Another
''loginfo'' script could provide e-mail notices when a TIP is revised
to users who registered their interest in that TIP.

~ Acknowledgments

Thanks to Donal Fellows for the original TIP rendering engine and
his assistance merging in the changes.  Thanks to Brent Welch for
providing the server and his assistance getting it configured for
use.  Thanks to Mark Harrison for his assistance with managing
browser caching issues.

----

~ Comments from the TCT

 > It might be a good idea to make the Abstract into a seperate <textarea> and
   treat that specially; I've been applying the rule that a TIP's abstract
   should be a single paragraph (it is implicit in the way I generate XML for
   instance) and that would be much easier to enforce through this route.  It
   would also have the advantage of discouraging people from placing their
   whole rationale in the abstract - which I've seen in several first drafts by
   people who shall remain nameless - and prompting the creation of TIPs more in
   keeping with the general concept of publishable documents.

 > It would also be nice if each page had a way of viewing the TIP's revision
   history (by a link to a suitably setup CVSweb URL?)  The way that SourceForge
   does its CVS-over-the-web is very nice indeed...

 > ''Donal K. Fellows <[email protected]>''

~ Author replies to comments

Some comments I see above, or received in e-mail:

 * ''Add a link to [3] on the edit page.  Display [3] in a new window.''

 > Link added.  I don't believe in deciding to open new browser windows for
   the user.  If the user wants to open the link in a new window, she knows
   how to do that.

 * ''Add an interface to create a new TIP''

 > For now, I'm trying to stick with the TIP procedures proposed in [2],
   where only the TIP Editor gets to create a new TIP, so all TIPs
   should still be originally submitted to him.  If the TCT rejects
   this proposal and adopts a different policy, we can revisit this
   question.

 * ''Browser caching makes it look like the edits were not made''

 > Based on advice from Mark Harrison and others, I've added HTTP
   headers that should prevent caching.  Please try it again.

 * ''I had the server time out on me''

 > That's troubling.  Can anyone seeing this problem provide any more
   information.  What were the circumstances, in detail?

 * ''Add links to an interface showing revision history''

 > Check out the [History] links at the bottom of the HTML rendered pages.
   Thanks to Donal Fellows for coding that up.  (OK, so we *did* reinvent
   CVSWeb.)

 * ''A separate <TEXTAREA> for the Abstract''

 > This is now implemented.  Please give it a try.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|






|

|

|
|





|


|



|






|


|






|




|








|



|





|




|








|
|




|



|
|



















|







|




|
|

|










|










|

|











|



|

|


|









|



|
|






|


|

|



|

|



|

|





|

|


|

|


|

|
|
|

|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251

# TIP 13: Web Service for Drafting and Archiving TIPs

	Author:         Don Porter <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Accepted
	Type:           Process
	Vote:           Done
	Created:        21-Nov-2000
	Post-History:   
-----

# Abstract

This document proposes the TCT provide a service on the World Wide
Web for drafting and archiving TIPs and for providing TIPs in a
variety of formats.  A reference implementation is provided, and its
server requirements are outlined.

# Background

It has been proposed \(see [[2]](2.md)\) that the TCT manage its projects and
procedures through a set of public documents known as Tcl Improvement
Proposals, or TIPs.  A format for TIPs has been approved \(see [[3]](3.md)\),
and although final approval of [[2]](2.md) is still pending, several TIPs
have been submitted, discussed, and revised, and a few have been
approved, so acceptance of TIPs in some form seems likely.

A prototype system has been provided by Donal
Fellows <[email protected]>
<http://www.cs.man.ac.uk/fellowsd-bin/TIP/> 
that delivers TIPs to visitors in a variety of formats.  However,
that system lacks archiving of each revision of each TIP, and
offers no interface \(through the web or otherwise\) for making
revisions to TIPs.  

The TIP format was inspired by the format used by the Tcl'ers
Wiki <http://www.purl.org/thecliff/tcl/wiki/> .  The true power
of the Tcl'ers Wiki, though, is not in the particular format it
uses, but in the fact that it empowers the whole Tcl community to
contribute to a common set of resources.  The Tcl'ers Wiki
shows that valuable resources can arise out of the unrestricted
efforts of volunteers from the community.

# Problems with Current TIP Infrastructure.

The Fellows web interface to the TIP Document Collection
<http://www.cs.man.ac.uk/fellowsd-bin/TIP/>  offers valuable
browsing access to TIPs in a variety of formats.  It accomplishes
the important goal of making TIPs public.  However, it suffers from
two significant shortcomings:

   * Revisions are only possible through the TIP Editor:

	   > Currently the only way to revise a TIP is to e-mail a new
     revision to the TIP Editor and wait for it to replace the old
     revision.  As more TIPs are submitted, and as each TIP is more
     frequently revised, this bottleneck will not be tolerable.

	   > Discussion about TIPs currently takes place in Usenet newsgroups
     and on mailing lists, but because there is no easy access to
     revising the TIPs themselves, the new information and viewpoints
     arising in these discussions are not being folded back into the
     TIPs.  This means the TIPs are failing in their intended role to
     present a full history of an issue to later readers.  It also
     means newcomers to a TIP cannot receive a full briefing in one
     place, but must chase down discussions in mailing list and Usenet
     archives.  Few people do that, but instead repeat points already
     made.  The discussions about [[6]](6.md) reflect this problem.

   * An archive of each revision of each TIP is not maintained:

	   > Although [[2]](2.md) refers to TIPs as being stored in a revision control
     system, probably a CVS repository, the Fellows TIP collection is
     not maintained in such a system.  Since a TIP is an archive of a
     public discussion of an issue, it is important to be able to
     access the history of changes to each TIP.

	   > The ability to retrieve and restore earlier revisions of a TIP
     will be especially important if public revision is permitted, so
     that any TIP contents that are incorrectly removed, whether by
     accident or malice, can be restored.

# Proposal

An improved system for archiving and revising TIPs is proposed:

   1. TIPs will be archived in a CVS repository.

   1. Anyone with the power to call a TYANNOTT vote will have commit
      access to this repository through either :pserver: or ssh
      access.  With this access, they will be able to revise any part
      \(header or body\) of any TIP \(whether in _State: Draft_ or
      not\).  Everyone having this access will be trusted to modify
      TIPs only in conformance with the TIP format and the TCT
      procedures.

   1. An enhanced version of the Fellows TIP rendering engine will
      display an [Edit] link at the bottom of each TIP eligible
      for web-editing when that TIP is rendered in HTML.

   1. For any TIP in state Draft, and for which a vote is still
      pending, the [Edit] link will lead to an HTML form for
      submitting a revised TIP.  For other TIPs, no [Edit] link
      will appear, and an attempt to directly access web-editing of
      such a TIP will lead to a message stating that the TIP may not
      be edited through the web interface.

   1. The HTML editing form will display the TIP header, but will not
      make it available for editing.  The HTML form will require that
      an e-mail address be entered, and will allow a name to be
      entered as well.  A <TEXTAREA> will be initialized to hold the
      current TIP abstract.  A second <TEXTAREA> will be initialized
      to hold the current TIP body.  Users of the form will revise
      the abstract and the body, then submit the form.

   1. The TIP rendering engine will receive the revisions, and
      will use CVS client commands to merge the revisions with other
      revisions and commit the revised TIP to the TIP CVS repository.
      If a conflict occurs during a merge, the TIP body including the
      conflicts will be returned to the user in another HTML form to
      resolve the conflict.

	    > Note that the CVS commit function of the TIP rendering engine
      implies that the CGI process in which the TIP rendering engine
      runs must have a user ID with commit access to the TIP CVS
      repository.

   1. In the revised TIP checked in to CVS the submitter of the
      revision will be added as an Author in the header of that TIP.

# Reference Implementation

The modifications to the Fellows TIP rendering engine that add the
capabilities proposed above are now merged in.  The TIP rendering
engine is maintained and publically available
<http://sourceforge.net/projects/tiprender/> .  To enable the
web-editing features, set the Tcl variable FEATURE\(EDIT\) to 1 in
the file config.tcl.  A working version of the proposed web service
is available at <http://purl.org/tcl/tip/>

For what it's worth, this TIP was created primarily within a web
browser, making revisions through the web interface provided by the
reference implementation.

One remaining shortcoming of the reference implementation is that it
provides no mechanism for uploading images to the TIP repository.
Images still need to be submitted through the TIP Editor, or
someone else with commit access to the TIP CVS repository.

# Server Requirements

The reference implementation imposes the following requirements on a
server:

   1. The server provides an HTTP server that serves the public
      Internet, and supports the CGI interface.

   1. CVS client software must be installed on the server.

   1. The CVS repository containing TIPs must be on the server itself.
      This is due to a CVS limitation that _loginfo_ scripts run on
      the machine housing the CVS repository, and the reference
      implementation uses a _loginfo_ script to keep the TIPs
      presented through the web up to date with the commits to the
      repository.

   1. The CVS repository must offer commit access over the Internet
      using either :pserver: or ssh to everyone with authority to call
      a TYANNOTT vote.

   1. The user under which the HTTP server runs its CGI processes must
      have commit access to the TIP CVS repository.  This may have
      security implications.

# Future Improvements

Once the TIPs are housed in a CVS repository, other services should be
easier to implement.  Another browsing interface could be provided
using cvsweb <http://stud.fh-heilbronn.de/~zeller/cgi/cvsweb.cgi/>  to
allow anyone in the community to browse TIP history.  Another
_loginfo_ script could provide e-mail notices when a TIP is revised
to users who registered their interest in that TIP.

# Acknowledgments

Thanks to Donal Fellows for the original TIP rendering engine and
his assistance merging in the changes.  Thanks to Brent Welch for
providing the server and his assistance getting it configured for
use.  Thanks to Mark Harrison for his assistance with managing
browser caching issues.

----

# Comments from the TCT

 > It might be a good idea to make the Abstract into a seperate <textarea> and
   treat that specially; I've been applying the rule that a TIP's abstract
   should be a single paragraph \(it is implicit in the way I generate XML for
   instance\) and that would be much easier to enforce through this route.  It
   would also have the advantage of discouraging people from placing their
   whole rationale in the abstract - which I've seen in several first drafts by
   people who shall remain nameless - and prompting the creation of TIPs more in
   keeping with the general concept of publishable documents.

 > It would also be nice if each page had a way of viewing the TIP's revision
   history \(by a link to a suitably setup CVSweb URL?\)  The way that SourceForge
   does its CVS-over-the-web is very nice indeed...

 > _Donal K. Fellows <[email protected]>_

# Author replies to comments

Some comments I see above, or received in e-mail:

 * _Add a link to [[3]](3.md) on the edit page.  Display [[3]](3.md) in a new window._

	 > Link added.  I don't believe in deciding to open new browser windows for
   the user.  If the user wants to open the link in a new window, she knows
   how to do that.

 * _Add an interface to create a new TIP_

	 > For now, I'm trying to stick with the TIP procedures proposed in [[2]](2.md),
   where only the TIP Editor gets to create a new TIP, so all TIPs
   should still be originally submitted to him.  If the TCT rejects
   this proposal and adopts a different policy, we can revisit this
   question.

 * _Browser caching makes it look like the edits were not made_

	 > Based on advice from Mark Harrison and others, I've added HTTP
   headers that should prevent caching.  Please try it again.

 * _I had the server time out on me_

	 > That's troubling.  Can anyone seeing this problem provide any more
   information.  What were the circumstances, in detail?

 * _Add links to an interface showing revision history_

	 > Check out the [History] links at the bottom of the HTML rendered pages.
   Thanks to Donal Fellows for coding that up.  \(OK, so we \*did\* reinvent
   CVSWeb.\)

 * _A separate <TEXTAREA> for the Abstract_

	 > This is now implemented.  Please give it a try.

# Copyright

This document has been placed in the public domain.

Name change from tip/130.tip to tip/130.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

TIP:		130
Title:		Unique DDE server names.
Version:	$Revision: 1.4 $
Author:		Pat Thoyts <[email protected]>
State:		Final
Tcl-Version:	8.5
Created:	23-Mar-2003
Type:		Project
Vote:		Done
Post-History:	


~ Abstract

The ''dde'' package server registration code should ensure that the
server names are unique. The proposed changes will mean end-user
visible changes for some scripts.

~ Rationale

This TIP is really driven by Bug 219293
[[http://sf.net/tracker/?func=detail&aid=219293&group_id=10894&atid=110894]]

The DDE system actually identifies servers by combination of window ID
and a service and topic string identifier. There is nothing to prevent
multiple servers having the same string identifiers but it is then a
problem to determine which server you need to communicate with.

The ''tk appname'' command handles a similar situation by making the
name unique during registration by appending a numerical suffix to the
suggested name and then returning the name registered as the result of
the command.

~ Proposed Changes

This TIP proposes to use the ''tk appname'' unique name algorithm
within the DDE server-name registration code.  This TIP also proposes a
''-force'' option to this command to force the suggested name to be
registered.  The ''-force'' option would then provide the current
registration scheme.

~ Reference Implementation

See the patch attached to SF patch 690354
[https://sourceforge.net/tracker/?func=detail&aid=690354&group_id=10894&atid=310894]

~ Consequences

Firstly the ''dde servername'' command may register a different name
than that provided to the command.  Scripts will need to check the
name actually registered by either maintaining the result of this
command, or by executing the ''dde servername'' command without any
arguments.  This may impact scripts that assume the supplied argument
was in fact the name registered.

Secondly, the name registration code must obtain a list of the dde
server names currently registered on the system.  It can do this by
effectively calling ''dde services TclEval''.  In previous versions of
the ''dde'' package there is a potential for the ''dde services''
command to hang in the presence of applications that are not
processing messages.  However, this issue has been addressed by Bug
707822's resolution.

~ Copyright

This document is hereby placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|



|


|






|




|

|

|
|


|


|

|

|


|





|
|




|


>

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

# TIP 130: Unique DDE server names.

	Author:		Pat Thoyts <[email protected]>
	State:		Final
	Tcl-Version:	8.5
	Created:	23-Mar-2003
	Type:		Project
	Vote:		Done
	Post-History:	
-----

# Abstract

The _dde_ package server registration code should ensure that the
server names are unique. The proposed changes will mean end-user
visible changes for some scripts.

# Rationale

This TIP is really driven by Bug 219293
<http://sf.net/tracker/?func=detail&aid=219293&group_id=10894&atid=110894> 

The DDE system actually identifies servers by combination of window ID
and a service and topic string identifier. There is nothing to prevent
multiple servers having the same string identifiers but it is then a
problem to determine which server you need to communicate with.

The _tk appname_ command handles a similar situation by making the
name unique during registration by appending a numerical suffix to the
suggested name and then returning the name registered as the result of
the command.

# Proposed Changes

This TIP proposes to use the _tk appname_ unique name algorithm
within the DDE server-name registration code.  This TIP also proposes a
_-force_ option to this command to force the suggested name to be
registered.  The _-force_ option would then provide the current
registration scheme.

# Reference Implementation

See the patch attached to SF patch 690354
<https://sourceforge.net/tracker/?func=detail&aid=690354&group_id=10894&atid=310894> 

# Consequences

Firstly the _dde servername_ command may register a different name
than that provided to the command.  Scripts will need to check the
name actually registered by either maintaining the result of this
command, or by executing the _dde servername_ command without any
arguments.  This may impact scripts that assume the supplied argument
was in fact the name registered.

Secondly, the name registration code must obtain a list of the dde
server names currently registered on the system.  It can do this by
effectively calling _dde services TclEval_.  In previous versions of
the _dde_ package there is a potential for the _dde services_
command to hang in the presence of applications that are not
processing messages.  However, this issue has been addressed by Bug
707822's resolution.

# Copyright

This document is hereby placed in the public domain.

Name change from tip/131.tip to tip/131.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

TIP:		131
Title:		Read My Mind and Do What I Mean
Version:	$Revision: 1.2 $
Author:		Joe English <[email protected]>
State:		Draft
Type:		Project
Vote:		No voting
Tcl-Version:	8.5
Created:	01-Apr-2003
Post-History:	


~ Abstract

A new Tcl command is proposed, ''rmmadwim''.  This is an acronym for
``Read My Mind and Do What I Mean''.  This command has obvious
utility.

~ Specification

The ''rmmadwim'' command shall take no arguments.  When invoked, the
Tcl interpreter shall read the programmer's mind and do what he or she
intends.

''NOTE:'' It is very important that ''rmmadwim'' read the
''programmer's'' mind, not the end user's.  Otherwise the consequences
could be disastrous, since end users rarely have a firm grasp of what
the original programmer was up to.

As a consequence of this command, there is also a corresponding
function for ''expr'' which applies the same principles to general
mathematical computation:

|  set result [expr {rmmadwim()}]

This extra functionality is easy to enable:

|  rmmadwim

~ Rationale

What Tcl needs in order to succeed in the marketplace is a feature
that no other programming language provides, a "killer app" as it
were.  The Tk toolkit, Expect, cross-platform portability, scripted
documents, tkcon, and the [[incr Tcl]] "toaster" example are all well
and good, but they have clearly failed to push Tcl usage to the point
of having critical mass.  The ''rmmadwim'' command would provide a
powerful enough incentive that even Perl programmers would be
compelled to switch languages.

~ Reference Implementation

A skeletal implementation is included below.  Clearly some of the
details remain to be flushed out, but this is a simple matter of
programming (SMOP).  It should be a fun weekend project for Richard
Suchenwirth.

File: ''tcl/generic/tclCmdMZ.c''

Function: ''Tcl_RmmAndDWIMObjCmd''

|       /*ARGSUSED*/
|   int
|   Tcl_RmmAndDWIMObjCmd(dummy, interp, objc, objv)
|       ClientData dummy;                   /* Not used. */
|       Tcl_Interp *interp;                 /* Current interpreter. */
|       int objc;                           /* Number of arguments. */
|       Tcl_Obj *CONST objv[];              /* Argument objects. */
|   {

|       int status;
|       Tcl_Obj *intentions;
|
|       if (objc != 1) {
|           Tcl_WrongNumArgs(interp, 1, objv, NULL);
|           return TCL_ERROR;
|       }

|
|       status = TclReadProgrammersMind(interp, &intentions);
|       if (status != TCL_OK) {
|           return status;
|       }

|
|       status = TclDoWhatIsMeant(interp, intentions);
|       return status;
|   }


~ Security Implications

It was pointed out that the ability to read the programmers' mind
carries with it certain security and privacy implementations.

To address this, the following code should be executed whenever a safe
interpreter is created:

|   #

|   # Query the programmer's mind to obtain his or her
|   # P3P settings (See "Platform for Privacy Preferences",
|   # <URL: http://www.w3.org/P3P >)
|   #

|       rmmadwim
|
|   #

|   # Disable any internal commands that are in conflict
|   # with those settings:
|   #

|       rmmadwim

In addition, the Tcl release notes should give a clear indication to
programmers about the new security implications for non-Safe
interpreters.

~ Copyright

This TIP is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License; either version 2 of
the License, or (at Richard Stallman's discretion), any later version.

Just kidding.  Public domain, as usual.

<
|
<
|
|
|
|
|
|
|
>

|

|
|


|

|



|
|




|


|



|

|




|

|



|



|


|

|

|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
<
|
>
|







<
>
|
|
|
<
>
|
|
<
>
|
|
<
>
|





|



|


>

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

# TIP 131: Read My Mind and Do What I Mean

	Author:		Joe English <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		No voting
	Tcl-Version:	8.5
	Created:	01-Apr-2003
	Post-History:	
-----

# Abstract

A new Tcl command is proposed, _rmmadwim_.  This is an acronym for
\`\`Read My Mind and Do What I Mean_.  This command has obvious
utility.

# Specification

The _rmmadwim_ command shall take no arguments.  When invoked, the
Tcl interpreter shall read the programmer's mind and do what he or she
intends.

_NOTE:_ It is very important that _rmmadwim_ read the
_programmer's_ mind, not the end user's.  Otherwise the consequences
could be disastrous, since end users rarely have a firm grasp of what
the original programmer was up to.

As a consequence of this command, there is also a corresponding
function for _expr_ which applies the same principles to general
mathematical computation:

	  set result [expr {rmmadwim()}]

This extra functionality is easy to enable:

	  rmmadwim

# Rationale

What Tcl needs in order to succeed in the marketplace is a feature
that no other programming language provides, a "killer app" as it
were.  The Tk toolkit, Expect, cross-platform portability, scripted
documents, tkcon, and the [incr Tcl] "toaster" example are all well
and good, but they have clearly failed to push Tcl usage to the point
of having critical mass.  The _rmmadwim_ command would provide a
powerful enough incentive that even Perl programmers would be
compelled to switch languages.

# Reference Implementation

A skeletal implementation is included below.  Clearly some of the
details remain to be flushed out, but this is a simple matter of
programming \(SMOP\).  It should be a fun weekend project for Richard
Suchenwirth.

File: _tcl/generic/tclCmdMZ.c_

Function: _Tcl\_RmmAndDWIMObjCmd_

	       /*ARGSUSED*/
	   int
	   Tcl_RmmAndDWIMObjCmd(dummy, interp, objc, objv)
	       ClientData dummy;                   /* Not used. */
	       Tcl_Interp *interp;                 /* Current interpreter. */
	       int objc;                           /* Number of arguments. */
	       Tcl_Obj *CONST objv[];              /* Argument objects. */

	   {
	       int status;
	       Tcl_Obj *intentions;
	
	       if (objc != 1) {
	           Tcl_WrongNumArgs(interp, 1, objv, NULL);
	           return TCL_ERROR;

	       }
	
	       status = TclReadProgrammersMind(interp, &intentions);
	       if (status != TCL_OK) {
	           return status;

	       }
	
	       status = TclDoWhatIsMeant(interp, intentions);
	       return status;

	   }

# Security Implications

It was pointed out that the ability to read the programmers' mind
carries with it certain security and privacy implementations.

To address this, the following code should be executed whenever a safe
interpreter is created:


	   #
	   # Query the programmer's mind to obtain his or her
	   # P3P settings (See "Platform for Privacy Preferences",
	   # <URL: http://www.w3.org/P3P >)

	   #
	       rmmadwim
	

	   #
	   # Disable any internal commands that are in conflict
	   # with those settings:

	   #
	       rmmadwim

In addition, the Tcl release notes should give a clear indication to
programmers about the new security implications for non-Safe
interpreters.

# Copyright

This TIP is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License; either version 2 of
the License, or \(at Richard Stallman's discretion\), any later version.

Just kidding.  Public domain, as usual.

Name change from tip/132.tip to tip/132.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226

TIP:            132
Title:          Revised Floating-Point Conversions in Tcl
Version:        $Revision: 1.14 $
Author:         Kevin Kenny <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        31-Mar-2003
Post-History:   
Keywords:       floating point,IEEE,precision
Tcl-Version:    8.5


~ Abstract

This TIP proposes several changes to the conversion between floating
point numbers and character strings. The changes are made to restore
the "everything is a string" contract that Tcl implicitly makes;
without them, there are observable differences in the behavior of
floating point numbers, depending on the state of the internal
representation.

~ Rationale

In today's (8.4) Tcl, there are several gaffes that make
floating-point arithmetic less useful than it might be, and cause
confusion for the users.  Chief among these is that string equality
does ''not'' imply value equality for floating point numbers:

|    % set tcl_precision 12
|    12
|    % set a [expr 1.00000000000123]
|    1.0
|    % set b [expr 1.0]
|    1.0
|    % expr { $a == $b }
|    0

|    % expr { $a eq $b }
|    1


This behavior flies in the face of Tcl's "everything is a string"
mantra.  In the interaction above, it is visible that ''a'' and ''b''
are ''not'' entirely strings; they have identical string
representations, but still test to be unequal with "==".  The
underlying cause of the behavior is the fact that the default setting
for ''tcl_precision'' loses precision when converting the
floating-point number to a string.  Behaviors like this have caused
Tcl's ''cognoscenti'' to recommend that all programs set
''tcl_precision'' to 17; once this setting is made, double-to-string
conversions are invertible, and everything is once again a string.

(Why 17? With IEEE-754 arithmetic, 17 decimal digits suffice to
distinguish between any two floating point numbers, no matter how
small their difference. No smaller number of digits suffices.)

Why is ''tcl_precision'' not 17 by default? The reason appears to be
that when the precision is set that high, the default IEEE-754
semantics for floating point conversions cause a certain degree of
trouble.  They require that the decimal representation be the nearest
decimal representation to the value of the floating-point number that
has the given number of significant digits.  This conversion gives
rise to peculiarities:

|    % set tcl_precision 17; expr 0.2
|    0.20000000000000001

The peculiar behavior is, for the most part, suppressed by a lower
value for ''tcl_precision'':

|    % set tcl_precision 16; expr 0.2
|    0.2

The lower value, nevertheless, introduces the trouble above.  This TIP
proposes a solution to both problems.

~ Specification

This TIP proposes the following changes to the floating point
conversions in the Tcl library:

 1. The default value of ''::tcl_precision'' shall be changed to 0.
    A value of 0 (currently an error) shall be interpreted to mean
    that a number shall be formatted using
    the smallest number of decimal digits required to distinguish
    it from the next floating point number above it and the next
    floating point number below.  Other values of ''tcl_precision''
    shall continue to work as they do in Tcl 8.4.
    The documentation shall formally deprecate changing
    ''::tcl_precision'' to any other value, warning that doing so
    risks both loss of precision and inconsistency between string
    equality and "==".

 1. The default input conversion of floating-point numbers,
    ''SetDoubleFromAny'' shall be documented to guarantee precise
    rounding (generally to within one-half a unit of the least
    significant place [[1/2 ULP]]).  IEEE-754 rounding semantics are
    correct for this input.  The ''strtod'' procedure from the
    standard C library shall ''not'' be used for this conversion,
    since so many implementations are buggy; instead, a Tcl
    implementation shall be developed from scratch based on
    the algorithms developed by Burger and Dybvig
    [http://citeseer.ist.psu.edu/28233.html].
    (It is worthy of note that several
    platforms already eschew the native ''strtod'' in favour of
    one provided in the ''compat/'' library, because of known bugs.)

 1. When ''tcl_precision'' is zero, the output conversion 
    of floating-point numbers, ''UpdateStringOfDouble,'' shall convert a
    floating-point number to the unique string that satisfies the
    following constraints:

 > * if reconverted to a binary floating point number, it yields a
     number that is the closest among all strings having the given
     number of significant digits.

 > * if there is more than one string that is equally close but
     neither string yields the given number exactly, then the string
     with the even digit in the least significant place is
     chosen. 

 > * if there is more than one string with at most the given number of
     significant digits that yields the given floating-point number,
     but one has fewer significant digits than the other, then the
     shorter one is chosen. For example,

|              % expr 1e23

 > > returns ''1e+23'', not ''9.9999999999999992e+22'', even though
     the latter is a nearer representation of the exact floating-point
     value.

 > * if there is more than one string with at most the given number of
     significant digits that reconverts exactly to the same floating
     point number, and all such strings are equally long, then the one
     closest to the given floating point number is chosen.

 > * if a floating point number lies exactly at the midpoint of two
     strings with the same number of significant digits, the one
     with an even digit in the least significant place is chosen.

 1. The test suite for Tcl shall be upgraded to include suitable test
    vectors for assessing correct rounding behavior.  The paper by
    Verdonk, Cuyt and Verschaeren in the References, and the
    associated software, present a suitable data set for inclusion.

 1. The input and output conversions shall allow for the IEEE special
    values +Inf, -Inf, and NaN (and for denormalized numbers).  The
    [[expr]] command shall be changed to allow +Inf and -Inf as
    the result of an expression; NaN shall still cause an error.
    Tcl_GetDoubleFromObj shall treat +Inf and -Inf as it does any
    ordinary floating point number, and return an error for NaN.

 1. The [[binary scan]] and [[binary format]] commands shall explicitly
    permit infinities and NaN as values.

''Donal K. Fellows notes that...'' the '''expr''' command will handle Inf and NaN quite well if asked nicely; it just won't return them.

| % expr {1 / Inf}
| 0.0

~ References

The basic principles of correctly-rounded floating point conversions
have been known for a good many years.  Perhaps the two most seminal
papers on modern floating point conversion are:

 > William D. Clinger, ''How to Read Floating Point Numbers
   Accurately'', Proceedings of the ACM Conference on Programming
   Language Design and Implementation, June 20-22 1990, pp. 92-101.
   [http://citeseer.nj.nec.com/clinger90how.html]

 > Guy L. Steele Jr. and Jon L. White, ''How to print floating-point
   numbers accurately''. In Proceedings of the ACM Conference on
   Programming Language Design and Implementation, June 20-22 1990,
   pp. 112-126.  [http://doi.acm.org/10.1145/93542.93559]

Both of these papers inspired David Gay to implement a library to do
correct rounding in floating point input and output conversions:

 > David M. Gay, ''Correctly rounded binary-decimal and decimal-binary
   conversions'', Numerical Analysis Manuscript 90-10, AT&T Bell
   Laboratories, Murray Hill, New Jersey, November 1990.
   [http://citeseer.nj.nec.com/gay90correctly.html]

The algorithms for output conversion that appear in the reference
implmentation are a hybrid of Gay's and the ones presented in:

 > Robert G. Burger and R. Kent Dybvig, ''Printing Floating-Point Numbers
   Quickly and Accurately'', SIGPLAN Conf. on Programming Language Design
   and Implementation, 1996, pp. 108-116.
   [http://citeseer.ist.psu.edu/28233.html]

A reasonably comprehensive set of test vectors detailing problem cases
for rounding conversions is documented in:

 > Brigitte Verdonk, Annie Cuyt, Dennis Verschaeren, ''A precision and
   range independent tool for testing floating-point arithmetic II:
   Conversions'', ACM Transactions on Mathematical Software 27:2
   (March 2001), pp. 119-140.
   [http://citeseer.nj.nec.com/verdonk99precision.html]

~ Reference Implementation

A partial reference implementation of this TIP is available in CVS on the
''kennykb-tcl-numerics'' branch.  Since it requires additional third-party
code that is not yet in the core, a different module name is required
to check it out:

| export CVSROOT=:ext:[email protected]:/cvsroot/tcl
| cvs -q checkout -rkennykb-tip-132 tcl_numerics

The implementation is essentially complete; it includes changes to
the documentation and test suite needed for this TIP.

~ Acknowledgments

The discussion of just why 17 is magical was prompted by a suggestion
from Lars Hellstroem.

~ Copyright

Copyright (c) 2005 by Kevin B. Kenny.  All rights reserved.

This document may be distributed subject to the terms and conditions
set forth in the Open Publication License, version 1.0
[http://www.opencontent.org/openpub/].

<
|
<
|
|
|
|
|
|
|
|
|
>

|








|

|


|

|
|
|
|
|
|
|
<
>
|
<
|
>

|
|


|

|
|


|

|

|







|
|


|

|
|




|




|
|



|


|




|
|
|
|
|



|
|
|
|

|
|



|



|




|




|

|



|




|









|
|

|


|


|

|
|

|





|
|

|

|
|

|




|
|

|




|
|

|




|

|
|
|

|


|



|
|




|




|

|



|
>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226

# TIP 132: Revised Floating-Point Conversions in Tcl

	Author:         Kevin Kenny <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        31-Mar-2003
	Post-History:   
	Keywords:       floating point,IEEE,precision
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes several changes to the conversion between floating
point numbers and character strings. The changes are made to restore
the "everything is a string" contract that Tcl implicitly makes;
without them, there are observable differences in the behavior of
floating point numbers, depending on the state of the internal
representation.

# Rationale

In today's \(8.4\) Tcl, there are several gaffes that make
floating-point arithmetic less useful than it might be, and cause
confusion for the users.  Chief among these is that string equality
does _not_ imply value equality for floating point numbers:

	    % set tcl_precision 12
	    12
	    % set a [expr 1.00000000000123]
	    1.0
	    % set b [expr 1.0]
	    1.0
	    % expr { $a == $b }

	    0
	    % expr { $a eq $b }

	    1

This behavior flies in the face of Tcl's "everything is a string"
mantra.  In the interaction above, it is visible that _a_ and _b_
are _not_ entirely strings; they have identical string
representations, but still test to be unequal with "==".  The
underlying cause of the behavior is the fact that the default setting
for _tcl\_precision_ loses precision when converting the
floating-point number to a string.  Behaviors like this have caused
Tcl's _cognoscenti_ to recommend that all programs set
_tcl\_precision_ to 17; once this setting is made, double-to-string
conversions are invertible, and everything is once again a string.

\(Why 17? With IEEE-754 arithmetic, 17 decimal digits suffice to
distinguish between any two floating point numbers, no matter how
small their difference. No smaller number of digits suffices.\)

Why is _tcl\_precision_ not 17 by default? The reason appears to be
that when the precision is set that high, the default IEEE-754
semantics for floating point conversions cause a certain degree of
trouble.  They require that the decimal representation be the nearest
decimal representation to the value of the floating-point number that
has the given number of significant digits.  This conversion gives
rise to peculiarities:

	    % set tcl_precision 17; expr 0.2
	    0.20000000000000001

The peculiar behavior is, for the most part, suppressed by a lower
value for _tcl\_precision_:

	    % set tcl_precision 16; expr 0.2
	    0.2

The lower value, nevertheless, introduces the trouble above.  This TIP
proposes a solution to both problems.

# Specification

This TIP proposes the following changes to the floating point
conversions in the Tcl library:

 1. The default value of _::tcl\_precision_ shall be changed to 0.
    A value of 0 \(currently an error\) shall be interpreted to mean
    that a number shall be formatted using
    the smallest number of decimal digits required to distinguish
    it from the next floating point number above it and the next
    floating point number below.  Other values of _tcl\_precision_
    shall continue to work as they do in Tcl 8.4.
    The documentation shall formally deprecate changing
    _::tcl\_precision_ to any other value, warning that doing so
    risks both loss of precision and inconsistency between string
    equality and "==".

 1. The default input conversion of floating-point numbers,
    _SetDoubleFromAny_ shall be documented to guarantee precise
    rounding \(generally to within one-half a unit of the least
    significant place [1/2 ULP]\).  IEEE-754 rounding semantics are
    correct for this input.  The _strtod_ procedure from the
    standard C library shall _not_ be used for this conversion,
    since so many implementations are buggy; instead, a Tcl
    implementation shall be developed from scratch based on
    the algorithms developed by Burger and Dybvig
    <http://citeseer.ist.psu.edu/28233.html> .
    \(It is worthy of note that several
    platforms already eschew the native _strtod_ in favour of
    one provided in the _compat/_ library, because of known bugs.\)

 1. When _tcl\_precision_ is zero, the output conversion 
    of floating-point numbers, _UpdateStringOfDouble,_ shall convert a
    floating-point number to the unique string that satisfies the
    following constraints:

	 > \* if reconverted to a binary floating point number, it yields a
     number that is the closest among all strings having the given
     number of significant digits.

	 > \* if there is more than one string that is equally close but
     neither string yields the given number exactly, then the string
     with the even digit in the least significant place is
     chosen. 

	 > \* if there is more than one string with at most the given number of
     significant digits that yields the given floating-point number,
     but one has fewer significant digits than the other, then the
     shorter one is chosen. For example,

		              % expr 1e23

	 > > returns _1e\+23_, not _9.9999999999999992e\+22_, even though
     the latter is a nearer representation of the exact floating-point
     value.

	 > \* if there is more than one string with at most the given number of
     significant digits that reconverts exactly to the same floating
     point number, and all such strings are equally long, then the one
     closest to the given floating point number is chosen.

	 > \* if a floating point number lies exactly at the midpoint of two
     strings with the same number of significant digits, the one
     with an even digit in the least significant place is chosen.

 1. The test suite for Tcl shall be upgraded to include suitable test
    vectors for assessing correct rounding behavior.  The paper by
    Verdonk, Cuyt and Verschaeren in the References, and the
    associated software, present a suitable data set for inclusion.

 1. The input and output conversions shall allow for the IEEE special
    values \+Inf, -Inf, and NaN \(and for denormalized numbers\).  The
    [expr] command shall be changed to allow \+Inf and -Inf as
    the result of an expression; NaN shall still cause an error.
    Tcl\_GetDoubleFromObj shall treat \+Inf and -Inf as it does any
    ordinary floating point number, and return an error for NaN.

 1. The [binary scan] and [binary format] commands shall explicitly
    permit infinities and NaN as values.

_Donal K. Fellows notes that..._ the **expr** command will handle Inf and NaN quite well if asked nicely; it just won't return them.

	 % expr {1 / Inf}
	 0.0

# References

The basic principles of correctly-rounded floating point conversions
have been known for a good many years.  Perhaps the two most seminal
papers on modern floating point conversion are:

 > William D. Clinger, _How to Read Floating Point Numbers
   Accurately_, Proceedings of the ACM Conference on Programming
   Language Design and Implementation, June 20-22 1990, pp. 92-101.
   <http://citeseer.nj.nec.com/clinger90how.html> 

 > Guy L. Steele Jr. and Jon L. White, _How to print floating-point
   numbers accurately_. In Proceedings of the ACM Conference on
   Programming Language Design and Implementation, June 20-22 1990,
   pp. 112-126.  <http://doi.acm.org/10.1145/93542.93559> 

Both of these papers inspired David Gay to implement a library to do
correct rounding in floating point input and output conversions:

 > David M. Gay, _Correctly rounded binary-decimal and decimal-binary
   conversions_, Numerical Analysis Manuscript 90-10, AT&T Bell
   Laboratories, Murray Hill, New Jersey, November 1990.
   <http://citeseer.nj.nec.com/gay90correctly.html> 

The algorithms for output conversion that appear in the reference
implmentation are a hybrid of Gay's and the ones presented in:

 > Robert G. Burger and R. Kent Dybvig, _Printing Floating-Point Numbers
   Quickly and Accurately_, SIGPLAN Conf. on Programming Language Design
   and Implementation, 1996, pp. 108-116.
   <http://citeseer.ist.psu.edu/28233.html> 

A reasonably comprehensive set of test vectors detailing problem cases
for rounding conversions is documented in:

 > Brigitte Verdonk, Annie Cuyt, Dennis Verschaeren, _A precision and
   range independent tool for testing floating-point arithmetic II:
   Conversions_, ACM Transactions on Mathematical Software 27:2
   \(March 2001\), pp. 119-140.
   <http://citeseer.nj.nec.com/verdonk99precision.html> 

# Reference Implementation

A partial reference implementation of this TIP is available in CVS on the
_kennykb-tcl-numerics_ branch.  Since it requires additional third-party
code that is not yet in the core, a different module name is required
to check it out:

	 export CVSROOT=:ext:[email protected]:/cvsroot/tcl
	 cvs -q checkout -rkennykb-tip-132 tcl_numerics

The implementation is essentially complete; it includes changes to
the documentation and test suite needed for this TIP.

# Acknowledgments

The discussion of just why 17 is magical was prompted by a suggestion
from Lars Hellstroem.

# Copyright

Copyright \(c\) 2005 by Kevin B. Kenny.  All rights reserved.

This document may be distributed subject to the terms and conditions
set forth in the Open Publication License, version 1.0
<http://www.opencontent.org/openpub/> .

Name change from tip/133.tip to tip/133.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

TIP:            133
Title:          Extending [expr] Operators
Version:        $Revision: 1.6 $
Author:         Richard Suchenwirth <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        08-Apr-2003
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes a way to define new operators for conditions and the
'''expr''' command.  It also includes demonstrations of how it might work
in the examples: '''in''' tests inclusion in a list, and '''and''',
'''or''', and '''not''' are aliases for "'''&&'''", "'''||'''", "'''!'''".

~ Rationale

Inclusion of a value in a list is frequently tested with the construct

|   if {[lsearch -exact $list $value] >= 0} {...}

The proposal, first brought by Reinhard Max in the Tcl Chatroom, is to
allow an ''in'' operator in the language understood by '''expr''', and
the condition parts of '''for''', '''if''' and '''while''', so that
the above can be written as

|   if {$value in $list} {...}

This is shorter to type and much better to read.

In the same vein, I propose to allow operators "'''and'''",
"'''or'''", "'''not'''" to be resolved exactly like the current
"'''&&'''", "'''||'''" resp "'''!'''"  The new "operator aliases" are
not shorter than the original operators, but definitely better
readable - and easier typed too, as no Shift (or Alt-Gr on German
keyboards) key is needed.

When Tcl was young, almost all users knew C, so the C style operators
were a good choice.  In recent years, there is tendency that Tcl is
used by persons who have no or less experience with C, but come from
other languages (etc. BASIC variants have the AND, OR, NOT operators)
or have Tcl as a first language. For all these, the option of
natural-language operators will make the learning just a little bit
easier.

~ Implementation Proposals

Donal K. Fellows remarked (on an earlier proposal relating to just an
'''in''' operator) in the Tcl Chatroom: "On the plus side, it
shouldn't be hard to implement (might need an extra opcode for
'''lsearch''', but that's pretty straightforward.)"

Pascal Scheffers proposed an extension mechanism for '''expr''' and
conditions, so the proposed extensions to the expression language can
be done in Tcl, with the commands:

| expr_register_operator in  {val list} {expr {[lsearch -exact $list $val]>=0}}
| expr_register_operator and {p q}      {expr {$p && $q}}
| expr_register_operator or  {p q}      {expr {$p || $q}}
| expr_register_operator not {p}        {expr {!$p}}

Such operator registrations can have one or two arguments (for unary
and binary operators, respective) in the second argument. The third
argument is a body that is evaluated, with local variables from the
argument list substituted, and returns the resulting value, to be
substituted for the operator and its operands.

Alternatively, one could stipulate that '''expr''' interprets its
arguments in the above sense when called like this:

| expr operator in  {val list} {expr {[lsearch -exact $list $val]>=0}}
| expr operator and {p q}      {expr {$p && $q}}

This would currently raise an error, hence cannot break existing code.

For a simple start, it shall be an error to define an operator both as
unary and binary.

Rules for operator precedence, and a way of specifying the precedence
level, will still be needed.

A feature sometimes discussed in news:comp.lang.tcl, an assignment
operator, could in the same way easily be added by users who so want:

| expr operator = {varName value} {upvar 1 $varName var; set var $value}

Reinhard Max has also proposed a unary '''empty''' operator:

|  expr operator empty {list} {expr {[llength $list]==0}}

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|
|
|

|



|


|
|


|



|
|
|

|
|




|




|

|
|
|
|

|



|
|
|
|

|
|




|


|
|












|

|

|

|


>

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

# TIP 133: Extending [expr] Operators

	Author:         Richard Suchenwirth <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        08-Apr-2003
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes a way to define new operators for conditions and the
**expr** command.  It also includes demonstrations of how it might work
in the examples: **in** tests inclusion in a list, and **and**,
**or**, and **not** are aliases for "**&&**", "**\|\|**", "**!**".

# Rationale

Inclusion of a value in a list is frequently tested with the construct

	   if {[lsearch -exact $list $value] >= 0} {...}

The proposal, first brought by Reinhard Max in the Tcl Chatroom, is to
allow an _in_ operator in the language understood by **expr**, and
the condition parts of **for**, **if** and **while**, so that
the above can be written as

	   if {$value in $list} {...}

This is shorter to type and much better to read.

In the same vein, I propose to allow operators "**and**",
"**or**", "**not**" to be resolved exactly like the current
"**&&**", "**\|\|**" resp "**!**"  The new "operator aliases" are
not shorter than the original operators, but definitely better
readable - and easier typed too, as no Shift \(or Alt-Gr on German
keyboards\) key is needed.

When Tcl was young, almost all users knew C, so the C style operators
were a good choice.  In recent years, there is tendency that Tcl is
used by persons who have no or less experience with C, but come from
other languages \(etc. BASIC variants have the AND, OR, NOT operators\)
or have Tcl as a first language. For all these, the option of
natural-language operators will make the learning just a little bit
easier.

# Implementation Proposals

Donal K. Fellows remarked \(on an earlier proposal relating to just an
**in** operator\) in the Tcl Chatroom: "On the plus side, it
shouldn't be hard to implement \(might need an extra opcode for
**lsearch**, but that's pretty straightforward.\)"

Pascal Scheffers proposed an extension mechanism for **expr** and
conditions, so the proposed extensions to the expression language can
be done in Tcl, with the commands:

	 expr_register_operator in  {val list} {expr {[lsearch -exact $list $val]>=0}}
	 expr_register_operator and {p q}      {expr {$p && $q}}
	 expr_register_operator or  {p q}      {expr {$p || $q}}
	 expr_register_operator not {p}        {expr {!$p}}

Such operator registrations can have one or two arguments \(for unary
and binary operators, respective\) in the second argument. The third
argument is a body that is evaluated, with local variables from the
argument list substituted, and returns the resulting value, to be
substituted for the operator and its operands.

Alternatively, one could stipulate that **expr** interprets its
arguments in the above sense when called like this:

	 expr operator in  {val list} {expr {[lsearch -exact $list $val]>=0}}
	 expr operator and {p q}      {expr {$p && $q}}

This would currently raise an error, hence cannot break existing code.

For a simple start, it shall be an error to define an operator both as
unary and binary.

Rules for operator precedence, and a way of specifying the precedence
level, will still be needed.

A feature sometimes discussed in news:comp.lang.tcl, an assignment
operator, could in the same way easily be added by users who so want:

	 expr operator = {varName value} {upvar 1 $varName var; set var $value}

Reinhard Max has also proposed a unary **empty** operator:

	  expr operator empty {list} {expr {[llength $list]==0}}

# Copyright

This document has been placed in the public domain.

Name change from tip/134.tip to tip/134.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

TIP:            134
Title:          Subsystem Per-Thread Data Interfaces
Version:        $Revision: 1.4 $
Author:         Colin McCormack <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        12-May-2003
Post-History:   
Tcl-Version:    8.5


~ Abstract

Tcl core subsystems per-thread data is good, because it modularises the
core.  None of the structures or access keys are exported, which is
bad, because it makes modification to these subsystems difficult in a
CVS world.

~ Rationale

If one wishes to track the CVS while writing modifications to core
subsystems one needs to minimally impact the existing source files
while adding or changing subsystem functionality.  Since most
subsystem global state is kept in Thread Specific Data, and access to
this state is necessary for subsystem modifications, providing an
interface would ease coding at the core subsystem level.  Modular
encapsulation would be preserved by conditionally compiling API
elements useful only to subsystem development and not intended for
extension development.

~ Justification

The degree of modularity of the core would remain unchanged, access to
subsystem TSD would presumably only be used for subsystem development,
but would enable that development to proceed more easily - one could
extend subsystems as easily as one currently writes extensions.  I
think the degree of potential abuse is likely to be low.

~ Outline of Proposal

Each Thread Specific Data structure should be named uniquely for each
subsystem.

Each subsystem should have its own .h header file

Each subsystem should export a function like ''tclTSD<subsystem>''
returning pointer to its TSD.  This API should be conditionally
compiled, so that it's clear that it's not available to normal
extensions.

~ Implementation

The implementation of this TIP is trivial.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|






|











|







|






|




|



|


>

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

# TIP 134: Subsystem Per-Thread Data Interfaces

	Author:         Colin McCormack <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        12-May-2003
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

Tcl core subsystems per-thread data is good, because it modularises the
core.  None of the structures or access keys are exported, which is
bad, because it makes modification to these subsystems difficult in a
CVS world.

# Rationale

If one wishes to track the CVS while writing modifications to core
subsystems one needs to minimally impact the existing source files
while adding or changing subsystem functionality.  Since most
subsystem global state is kept in Thread Specific Data, and access to
this state is necessary for subsystem modifications, providing an
interface would ease coding at the core subsystem level.  Modular
encapsulation would be preserved by conditionally compiling API
elements useful only to subsystem development and not intended for
extension development.

# Justification

The degree of modularity of the core would remain unchanged, access to
subsystem TSD would presumably only be used for subsystem development,
but would enable that development to proceed more easily - one could
extend subsystems as easily as one currently writes extensions.  I
think the degree of potential abuse is likely to be low.

# Outline of Proposal

Each Thread Specific Data structure should be named uniquely for each
subsystem.

Each subsystem should have its own .h header file

Each subsystem should export a function like _tclTSD<subsystem>_
returning pointer to its TSD.  This API should be conditionally
compiled, so that it's clear that it's not available to normal
extensions.

# Implementation

The implementation of this TIP is trivial.

# Copyright

This document has been placed in the public domain.

Name change from tip/135.tip to tip/135.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

TIP:		135
Title:		Change 'dde servername -exact' Option to -force
Author:		Pat Thoyts <[email protected]>
Type:		Project
State:		Final
Vote:		Done
Version:	$Revision: 1.5 $
Tcl-Version:	8.5
Keywords:	dde
Created:	17-May-2003
Post-History:	


~ Abstract

[130] provides for unique DDE server name registration.  This TIP
renames one of the options it defines to better reflect its
behaviour.

~ Rationale

The dde extension, as modified by [130], includes an option ''-exact''
to force the name to be that specified.  This TIP proposes to change
this options name to ''-force'' which better reflects its purpose.  As
[130] has only just been implemented, now is the time to make this
change before it is is included in any public release of Tcl.

~ Copyright

This document is placed in the public domain.

<
|
|
|
|
|
<
|
|
|
|
>

|

|



|

|

|
|


|


>

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

# TIP 135: Change 'dde servername -exact' Option to -force
	Author:		Pat Thoyts <[email protected]>
	Type:		Project
	State:		Final
	Vote:		Done

	Tcl-Version:	8.5
	Keywords:	dde
	Created:	17-May-2003
	Post-History:	
-----

# Abstract

[[130]](130.md) provides for unique DDE server name registration.  This TIP
renames one of the options it defines to better reflect its
behaviour.

# Rationale

The dde extension, as modified by [[130]](130.md), includes an option _-exact_
to force the name to be that specified.  This TIP proposes to change
this options name to _-force_ which better reflects its purpose.  As
[[130]](130.md) has only just been implemented, now is the time to make this
change before it is is included in any public release of Tcl.

# Copyright

This document is placed in the public domain.

Name change from tip/136.tip to tip/136.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

TIP:            136
Title:          Large List Initialisation
Version:        $Revision: 1.5 $
Author:         Simon Geard <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        25-May-2003
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes the addition of a list initialisation command so
that large lists can be easily and efficiently initialised.

~Rationale

With the advent of the ''lset'' command in Tcl 8.4 it seems to me that
we need a method of efficiently initialising large lists that can then
be used as areas of preallocated memory. From a users point of view it
can be much easier to preallocate say a 1000 element array and then
use ''lset'' and ''lindex'' to manipulate it than using ''lappend'' to
build it up. Having posted the idea to the tcl-core mailing list
various alternatives were suggested to create a list of 1000 x
characters:

 1.	''lappend'' in a loop

| unset -nocomplain s
| for {set i 0} {$i < 1000} {incr i} {lappend s {x}}

 2.	''split''ting of a string

| set s [split [string repeat x 1000] ""]

 3.	Direct construction of the string form

| set s x[string repeat " x" 999]

None of these is particularly satisfactory.  (1) seems inefficient
since there are 1000 lappend operations, (2) is not general enough
since it doesn't generalise to more than one character and (3) doesn't
actually create a list.  (2) and (3) also suffer from the problem that
they are not at all obvious to new users and do nothing to dispel the
notion that "everything is a string" in Tcl.

~Implementation

I propose the introduction of a new command, ''lrepeat'':

| lrepeat <number> <element1> ?<element2>? ?<element3>? ...

which returns a list of length <number> * (number of elements). The new list is the given element sequence repeated <number> times.
<number> must be a positive integer and each <element.> a list or
string.

Examples:

| lrepeat 100 0                 - returns a list of 100 zeros
| lrepeat 100 [lrepeat 100 0]   - returns a 100x100 matrix (list of lists) of zeros
| lrepeat 3 a b c               - returns a nine-element list {a b c a b c a b c}
| lrepeat 1 a b c               - identical to [list a b c]

~Reference Implementation

I have implemented this command.  A patch against the Tcl 8.4.3
source, which implements the command and provides both tests and
documentation, is available from
http://homepage.ntlworld.com/whiteowl/tcl/tcl843-lrepeat.patch
The directory also contains timing information and code which demonstrates a performance gain of over ten times for large lists.

~Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|




|

|



|




|

|
|

|

|



|

|
|
|
|



|

|

|

|





|
|
|
|

|




|


|


>

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

# TIP 136: Large List Initialisation

	Author:         Simon Geard <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        25-May-2003
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes the addition of a list initialisation command so
that large lists can be easily and efficiently initialised.

# Rationale

With the advent of the _lset_ command in Tcl 8.4 it seems to me that
we need a method of efficiently initialising large lists that can then
be used as areas of preallocated memory. From a users point of view it
can be much easier to preallocate say a 1000 element array and then
use _lset_ and _lindex_ to manipulate it than using _lappend_ to
build it up. Having posted the idea to the tcl-core mailing list
various alternatives were suggested to create a list of 1000 x
characters:

 1.	_lappend_ in a loop

		 unset -nocomplain s
		 for {set i 0} {$i < 1000} {incr i} {lappend s {x}}

 2.	_split_ting of a string

		 set s [split [string repeat x 1000] ""]

 3.	Direct construction of the string form

		 set s x[string repeat " x" 999]

None of these is particularly satisfactory.  \(1\) seems inefficient
since there are 1000 lappend operations, \(2\) is not general enough
since it doesn't generalise to more than one character and \(3\) doesn't
actually create a list.  \(2\) and \(3\) also suffer from the problem that
they are not at all obvious to new users and do nothing to dispel the
notion that "everything is a string" in Tcl.

# Implementation

I propose the introduction of a new command, _lrepeat_:

	 lrepeat <number> <element1> ?<element2>? ?<element3>? ...

which returns a list of length <number> \* \(number of elements\). The new list is the given element sequence repeated <number> times.
<number> must be a positive integer and each <element.> a list or
string.

Examples:

	 lrepeat 100 0                 - returns a list of 100 zeros
	 lrepeat 100 [lrepeat 100 0]   - returns a 100x100 matrix (list of lists) of zeros
	 lrepeat 3 a b c               - returns a nine-element list {a b c a b c a b c}
	 lrepeat 1 a b c               - identical to [list a b c]

# Reference Implementation

I have implemented this command.  A patch against the Tcl 8.4.3
source, which implements the command and provides both tests and
documentation, is available from
<http://homepage.ntlworld.com/whiteowl/tcl/tcl843-lrepeat.patch>
The directory also contains timing information and code which demonstrates a performance gain of over ten times for large lists.

# Copyright

This document has been placed in the public domain.

Name change from tip/137.tip to tip/137.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

TIP:            137
Title:          Specifying Script Encodings for [source] and tclsh
Version:        $Revision: 1.6 $
Author:         Anton Kovalenko <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        29-May-2003
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes a way to specify encoding used to read a script 
with ''source'' command and (tclsh, wish) shell.

~ Rationale

Now all Tcl scripts are expected to be in the system encoding.  An
author of a script or a package can't specify concrete encoding to
source the script or the files of package.  Common practise is to
assume that encoding to be superset of ASCII, and not to use non-ASCII
characters in the scripts that are targeting the wide audience of
potential users.

There's a way to specify UNICODE literals with \uXXXX sequences.  But
it's not an universal and convenient way - this sequences aren't
substituted in {}-quoted strings, and they can't be edited in WYSIWYG
editors without special (and hence uncommon) support.

This TIP proposes to add the ''-encoding'' option support to
''source'' command and to tclsh and wish.  Thus, package authors will be able
to specify encoding of the package files in ''pkgIndex.tcl''; and
script authors will be able to specify the script encoding when
calling tclsh (either in the first line beginning with ''#!'' or in
the line where the ''exec tclsh "$0" "$@"'' is located).

This TIP also proposes to use utf-8 for all the standard system
scripts, for ''pkgIndex.tcl'' and ''tclIndex'' files. Now they all are
supposed to be in the system encoding (message catalogs do not need
this support, as they are already always loaded using the UTF-8
encoding scheme), and it could event prevent Tcl itself from running
when system encoding is not a compatible superset of ASCII.

~ Specification

Tclsh will allow the encoding to be specified on the command-line in
two forms: the first form is ''-encoding name'' as two separate
arguments, and the second is ''-e:name'' (a single argument.)
The second form is intended for when the script begins with ''#!'' and
is because Unix kernels pass extra parameters from the ''#!'' line as
a single argument. This very short notation (-e:) is chosen because
some Unices limit the ''#!'' line to the length of 32.

To implement all these options, this TIP proposes a new C-level public API function Tcl_FSEvalFileEx, which is similar to Tcl_FSEvalFile, but
takes one extra argument that must be an encoding name or NULL (to use
system encoding).

| int Tcl_FSEvalFileEx(Tcl_Interp *interp, Tcl_Obj *pathPtr,
|                      CONST char *encodingName);

Common use of this new options will be like this:

 1. In a script:

| !#/usr/bin/tclsh -e:utf-8
| do something...

 > or it could be:

| #!/bin/sh
| # I wish to use tclsh \
| exec tclsh -encoding utf-8 "$0" "$@"

 2. In a ''pkgIndex.tcl'':

| package ifneeded pkg 1.02 [list source -encoding utf-8 \
|      [file join $dir pkg.tcl]]

~ Implementation

The partial implementation of this TIP can be found at
http://sourceforge.net/projects/tcl as Patch #742683. Some
fixes to source system scripts and pkgIndex'es in utf-8 are not
yet there. But with the existing implementation of "-encoding",
it would be really easy to implement.

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|

|








|

|
|

|
|
|

|
|


|
|

|


|


|
|
|
|
|
|

|
|
|

|
|





|
|

|

|
|
|

|

|
|

|


|




|


>

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

# TIP 137: Specifying Script Encodings for [source] and tclsh

	Author:         Anton Kovalenko <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        29-May-2003
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes a way to specify encoding used to read a script 
with _source_ command and \(tclsh, wish\) shell.

# Rationale

Now all Tcl scripts are expected to be in the system encoding.  An
author of a script or a package can't specify concrete encoding to
source the script or the files of package.  Common practise is to
assume that encoding to be superset of ASCII, and not to use non-ASCII
characters in the scripts that are targeting the wide audience of
potential users.

There's a way to specify UNICODE literals with \\uXXXX sequences.  But
it's not an universal and convenient way - this sequences aren't
substituted in \{\}-quoted strings, and they can't be edited in WYSIWYG
editors without special \(and hence uncommon\) support.

This TIP proposes to add the _-encoding_ option support to
_source_ command and to tclsh and wish.  Thus, package authors will be able
to specify encoding of the package files in _pkgIndex.tcl_; and
script authors will be able to specify the script encoding when
calling tclsh \(either in the first line beginning with _\#!_ or in
the line where the _exec tclsh "$0" "$@"_ is located\).

This TIP also proposes to use utf-8 for all the standard system
scripts, for _pkgIndex.tcl_ and _tclIndex_ files. Now they all are
supposed to be in the system encoding \(message catalogs do not need
this support, as they are already always loaded using the UTF-8
encoding scheme\), and it could event prevent Tcl itself from running
when system encoding is not a compatible superset of ASCII.

# Specification

Tclsh will allow the encoding to be specified on the command-line in
two forms: the first form is _-encoding name_ as two separate
arguments, and the second is _-e:name_ \(a single argument.\)
The second form is intended for when the script begins with _\#!_ and
is because Unix kernels pass extra parameters from the _\#!_ line as
a single argument. This very short notation \(-e:\) is chosen because
some Unices limit the _\#!_ line to the length of 32.

To implement all these options, this TIP proposes a new C-level public API function Tcl\_FSEvalFileEx, which is similar to Tcl\_FSEvalFile, but
takes one extra argument that must be an encoding name or NULL \(to use
system encoding\).

	 int Tcl_FSEvalFileEx(Tcl_Interp *interp, Tcl_Obj *pathPtr,
	                      CONST char *encodingName);

Common use of this new options will be like this:

 1. In a script:

		 !#/usr/bin/tclsh -e:utf-8
		 do something...

	 > or it could be:

		 #!/bin/sh
		 # I wish to use tclsh \
		 exec tclsh -encoding utf-8 "$0" "$@"

 2. In a _pkgIndex.tcl_:

		 package ifneeded pkg 1.02 [list source -encoding utf-8 \
		      [file join $dir pkg.tcl]]

# Implementation

The partial implementation of this TIP can be found at
<http://sourceforge.net/projects/tcl> as Patch \#742683. Some
fixes to source system scripts and pkgIndex'es in utf-8 are not
yet there. But with the existing implementation of "-encoding",
it would be really easy to implement.

# Copyright

This document is placed in the public domain.

Name change from tip/138.tip to tip/138.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

TIP:		138
Title:		New TCL_HASH_KEY_SYSTEM_HASH option for Tcl hash tables
Version:	$Revision: 1.5 $
Author:		Kevin Kenny <[email protected]>
Author:		Joe Mistachkin <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	29-May-2003
Post-History:	
Keywords:	thread specific data, hash table, memory allocation
Tcl-Version:	8.5


~ Abstract

This TIP proposes a new flag in the Tcl hash table API in support of a
proposed rework of thread-specific data management.

~ Introduction

The Tcl hash table constructor, ''Tcl_InitCustomHashTable'', provides
a reasonably flexible means of creating a hash table that is managed
by the application.  It allows for custom procedures to calculate hash
values for keys, to compare keys for equality, and to allocate and
free hash table entries.

It always, however, allocates the hash table itself by means of
''ckalloc'' and ''ckfree''. This use of Tcl's main allocator is
normally not a problem, but a recent application of custom hash tables
has exposed the need, from time to time, of using the system allocator
(''TclpSysAlloc'' and ''TclpSysFree'') directly.

The motivating problem is that thread-specific data on certain
versions of Windows is limited to only a small number of blocks per
process (64 on at least one version).  The proposed fix, which Joe
Mistachkin is pursuing, involves replacing the system calls for
managing thread-local storage with calls that manage the
thread-specific data blocks in a per-thread hash table.

Reviewing and testing the change revealed an unfortunate circular
dependency.  A call to ''Tcl_InitCustomHashTable'' would attempt to
allocate the array of hash buckets by a call to ''ckalloc'' - which
translates to ''TclpAlloc''.  On a threaded build, the first thing
done in this routine is to retrieve the allocation cache via
''TclpGetAllocCache.''  This in turn, once we avoid the use of
''TlsAlloc'', winds up trying to create a thread-specific data block
to hold the allocation cache.  The new thread-specific data manager in
turn must allocate a hash table for the thread-specific data blocks.
The outcome is endless recursion.

The fix for the problem is simple - have either the allocation cache,
the thread-specific data hash, or both, allocated off the system heap
rather than the thread-specific allocation cache.  Unfortunately,
''Tcl_InitCustomHashTable'' provides no way to accomplish this.

~ Proposal

The ''flags'' word in the ''Tcl_HashKeyType'' data structure shall be
augmented with an additional value, ''TCL_HASH_KEY_SYSTEM_HASH''.  If
this bit is set in the structure passed to ''Tcl_InitCustomHashTable'',
then all memory allocated internally to manage the hash keys shall be
obtained via direct calls to ''TclpSysAlloc'', ''TclpSysRealloc'', and
''TclpSysFree'' rather than ''Tcl_Alloc'', ''Tcl_Realloc'' and
''Tcl_Free.''

~ Alternatives

The authors considered and rejected the alternative of advancing
''TCL_HASH_KEY_TYPE_VERSION'' and defining in the structure three new
function pointers to allocate, reallocate, and free memory blocks.
The additional complexity (and associated performance degradation)
associated with dealing with two structure versions appeared to be
unnecessary; it is difficult to imagine a situation where any
allocator other than the system allocator or Tcl's own will be desired
for the 'buckets' array, which varies widely in size.  Custom
small-block allocators make much more sense for the hash values than
they do for the table of hash buckets.

~ Implementation Notes

An implementation of this change is available from the SourceForge
patch manager as item 731356.  It is part of a larger overhaul of the
thread-specific data manager.

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|




|

|






|


|



|





|
|
|

|
|







|

|

|
|
|

|
|
|

|


|

|







|





|


>

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

# TIP 138: New TCL_HASH_KEY_SYSTEM_HASH option for Tcl hash tables

	Author:		Kevin Kenny <[email protected]>
	Author:		Joe Mistachkin <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	29-May-2003
	Post-History:	
	Keywords:	thread specific data, hash table, memory allocation
	Tcl-Version:	8.5
-----

# Abstract

This TIP proposes a new flag in the Tcl hash table API in support of a
proposed rework of thread-specific data management.

# Introduction

The Tcl hash table constructor, _Tcl\_InitCustomHashTable_, provides
a reasonably flexible means of creating a hash table that is managed
by the application.  It allows for custom procedures to calculate hash
values for keys, to compare keys for equality, and to allocate and
free hash table entries.

It always, however, allocates the hash table itself by means of
_ckalloc_ and _ckfree_. This use of Tcl's main allocator is
normally not a problem, but a recent application of custom hash tables
has exposed the need, from time to time, of using the system allocator
\(_TclpSysAlloc_ and _TclpSysFree_\) directly.

The motivating problem is that thread-specific data on certain
versions of Windows is limited to only a small number of blocks per
process \(64 on at least one version\).  The proposed fix, which Joe
Mistachkin is pursuing, involves replacing the system calls for
managing thread-local storage with calls that manage the
thread-specific data blocks in a per-thread hash table.

Reviewing and testing the change revealed an unfortunate circular
dependency.  A call to _Tcl\_InitCustomHashTable_ would attempt to
allocate the array of hash buckets by a call to _ckalloc_ - which
translates to _TclpAlloc_.  On a threaded build, the first thing
done in this routine is to retrieve the allocation cache via
_TclpGetAllocCache._  This in turn, once we avoid the use of
_TlsAlloc_, winds up trying to create a thread-specific data block
to hold the allocation cache.  The new thread-specific data manager in
turn must allocate a hash table for the thread-specific data blocks.
The outcome is endless recursion.

The fix for the problem is simple - have either the allocation cache,
the thread-specific data hash, or both, allocated off the system heap
rather than the thread-specific allocation cache.  Unfortunately,
_Tcl\_InitCustomHashTable_ provides no way to accomplish this.

# Proposal

The _flags_ word in the _Tcl\_HashKeyType_ data structure shall be
augmented with an additional value, _TCL\_HASH\_KEY\_SYSTEM\_HASH_.  If
this bit is set in the structure passed to _Tcl\_InitCustomHashTable_,
then all memory allocated internally to manage the hash keys shall be
obtained via direct calls to _TclpSysAlloc_, _TclpSysRealloc_, and
_TclpSysFree_ rather than _Tcl\_Alloc_, _Tcl\_Realloc_ and
_Tcl\_Free._

# Alternatives

The authors considered and rejected the alternative of advancing
_TCL\_HASH\_KEY\_TYPE\_VERSION_ and defining in the structure three new
function pointers to allocate, reallocate, and free memory blocks.
The additional complexity \(and associated performance degradation\)
associated with dealing with two structure versions appeared to be
unnecessary; it is difficult to imagine a situation where any
allocator other than the system allocator or Tcl's own will be desired
for the 'buckets' array, which varies widely in size.  Custom
small-block allocators make much more sense for the hash values than
they do for the table of hash buckets.

# Implementation Notes

An implementation of this change is available from the SourceForge
patch manager as item 731356.  It is part of a larger overhaul of the
thread-specific data manager.

# Copyright

This document is placed in the public domain.

Name change from tip/139.tip to tip/139.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

TIP:		139
Title:		Publish Part of Tcl's Namespace API
Author:		Donal K. Fellows <[email protected]>
Created:	03-Jun-2003
Type:		Project
State:		Final
Vote:		Done
Tcl-Version:	8.5
Version:	$Revision: 1.5 $
Post-History:	


~ Abstract

This TIP makes the simpler parts of Tcl's Namespace API available to
the general C-coding public.

~ Rationale

Tcl has had namespace support for a number of years now, ever since
version 8.0.  However, the C API for working with namespaces (as
opposed to the script-level [[namespace]] command) has been hidden
inside Tcl's private header files for all that time.  This is mainly
because of the complexity of some of the interfaces; name resolution
is definitely difficult to document.

But about half the API is not so encumbered, being the parts that deal
with basic features like creation and destruction of namespaces
themselves.  It is these simpler parts that this TIP exposes as they
have little risk of changing in the future, and I believe they should
be made public particularly as it would allow extensions that create
commands in namespaces to ensure the existence of the namespace first
without resorting to applying ''Tcl_Eval'' to a small script.

This TIP does not call for any alteration to the name, signature or
behaviour of any API function at all.  Note that these functions
already have "public" names.

~ Exposed API Functions

There are the following new public functions (with signatures included
for reference only):

 Tcl_CreateNamespace:	Creates a new namespace.

|    Tcl_Namespace * Tcl_CreateNamespace(Tcl_Interp *interp, CONST char *name,
|	    ClientData clientData, Tcl_NamespaceDeleteProc *deleteProc)

 Tcl_DeleteNamespace:	Deletes an existing namespace.

|    void Tcl_DeleteNamespace(Tcl_Namespace *nsPtr)

 Tcl_AppendExportList:	Retrieves the export patterns for a namespace.

|    int Tcl_AppendExportList(Tcl_Interp *interp, Tcl_Namespace *nsPtr,
|            Tcl_Obj *objPtr)

 Tcl_Export:		Set/append to the export patterns for a namespace.

|    int Tcl_Export(Tcl_Interp *interp, Tcl_Namespace *nsPtr,
|            CONST char *pattern, int resetListFirst)

 Tcl_Import:		Import commands matching a pattern into a namespace.

|    int Tcl_Import(Tcl_Interp *interp, Tcl_Namespace *nsPtr,
|            CONST char *pattern, int allowOverwrite)

 Tcl_ForgetImport:	Remove imports matching a pattern.

|    int Tcl_ForgetImport(Tcl_Interp *interp, Tcl_Namespace *nsPtr,
|            CONST char *pattern)

 Tcl_GetCurrentNamespace: Retrieve the current namespace.

|    Tcl_Namespace * Tcl_GetCurrentNamespace(Tcl_Interp *interp)

 Tcl_GetGlobalNamespace: Retrieve the global namespace.

|    Tcl_Namespace * Tcl_GetGlobalNamespace(Tcl_Interp *interp)

 Tcl_FindNamespace:	Search for a namespace.

|    Tcl_Namespace * Tcl_FindNamespace(Tcl_Interp *interp, CONST char *name,
|            Tcl_Namespace *contextNsPtr, int flags)

 Tcl_FindCommand:	Search for a command and return its token,
    optionally in a namespace.  Note that command tokens are already
    returned from ''Tcl_CreateCommand'' and ''Tcl_CreateObjCommand''
    so this is not a new type of result.

|    Tcl_Command Tcl_FindCommand(Tcl_Interp *interp, CONST char *name,
|            Tcl_Namespace *contextNsPtr, int flags)

 Tcl_GetCommandFromObj:	Get a command token given a name.

|    Tcl_Command Tcl_GetCommandFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr)

 Tcl_GetCommandFullName: Get the full name of a command from its token.

|    void Tcl_GetCommandFullName(Tcl_Interp *interp, Tcl_Command command,
|            Tcl_Obj *objPtr)

Each of these functions will be declared in future within
''tcl.decls'' (with the entries in ''tclInt.decls'' deprecated) and
will also be documented.

~ Copyright

This document is placed in the public domain.

<
|
|
|
|
|
|
|
<
|
>

|




|


|
|










|





|

|
|

|

|
|

|

|

|

|
|

|

|
|

|

|
|

|

|
|

|

|

|

|

|

|
|

|

|


|
|

|

|

|

|
|


|


|


>

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

# TIP 139: Publish Part of Tcl's Namespace API
	Author:		Donal K. Fellows <[email protected]>
	Created:	03-Jun-2003
	Type:		Project
	State:		Final
	Vote:		Done
	Tcl-Version:	8.5

	Post-History:	
-----

# Abstract

This TIP makes the simpler parts of Tcl's Namespace API available to
the general C-coding public.

# Rationale

Tcl has had namespace support for a number of years now, ever since
version 8.0.  However, the C API for working with namespaces \(as
opposed to the script-level [namespace] command\) has been hidden
inside Tcl's private header files for all that time.  This is mainly
because of the complexity of some of the interfaces; name resolution
is definitely difficult to document.

But about half the API is not so encumbered, being the parts that deal
with basic features like creation and destruction of namespaces
themselves.  It is these simpler parts that this TIP exposes as they
have little risk of changing in the future, and I believe they should
be made public particularly as it would allow extensions that create
commands in namespaces to ensure the existence of the namespace first
without resorting to applying _Tcl\_Eval_ to a small script.

This TIP does not call for any alteration to the name, signature or
behaviour of any API function at all.  Note that these functions
already have "public" names.

# Exposed API Functions

There are the following new public functions \(with signatures included
for reference only\):

 Tcl\_CreateNamespace:	Creates a new namespace.

	    Tcl_Namespace * Tcl_CreateNamespace(Tcl_Interp *interp, CONST char *name,
		    ClientData clientData, Tcl_NamespaceDeleteProc *deleteProc)

 Tcl\_DeleteNamespace:	Deletes an existing namespace.

	    void Tcl_DeleteNamespace(Tcl_Namespace *nsPtr)

 Tcl\_AppendExportList:	Retrieves the export patterns for a namespace.

	    int Tcl_AppendExportList(Tcl_Interp *interp, Tcl_Namespace *nsPtr,
	            Tcl_Obj *objPtr)

 Tcl\_Export:		Set/append to the export patterns for a namespace.

	    int Tcl_Export(Tcl_Interp *interp, Tcl_Namespace *nsPtr,
	            CONST char *pattern, int resetListFirst)

 Tcl\_Import:		Import commands matching a pattern into a namespace.

	    int Tcl_Import(Tcl_Interp *interp, Tcl_Namespace *nsPtr,
	            CONST char *pattern, int allowOverwrite)

 Tcl\_ForgetImport:	Remove imports matching a pattern.

	    int Tcl_ForgetImport(Tcl_Interp *interp, Tcl_Namespace *nsPtr,
	            CONST char *pattern)

 Tcl\_GetCurrentNamespace: Retrieve the current namespace.

	    Tcl_Namespace * Tcl_GetCurrentNamespace(Tcl_Interp *interp)

 Tcl\_GetGlobalNamespace: Retrieve the global namespace.

	    Tcl_Namespace * Tcl_GetGlobalNamespace(Tcl_Interp *interp)

 Tcl\_FindNamespace:	Search for a namespace.

	    Tcl_Namespace * Tcl_FindNamespace(Tcl_Interp *interp, CONST char *name,
	            Tcl_Namespace *contextNsPtr, int flags)

 Tcl\_FindCommand:	Search for a command and return its token,
    optionally in a namespace.  Note that command tokens are already
    returned from _Tcl\_CreateCommand_ and _Tcl\_CreateObjCommand_
    so this is not a new type of result.

	    Tcl_Command Tcl_FindCommand(Tcl_Interp *interp, CONST char *name,
	            Tcl_Namespace *contextNsPtr, int flags)

 Tcl\_GetCommandFromObj:	Get a command token given a name.

	    Tcl_Command Tcl_GetCommandFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr)

 Tcl\_GetCommandFullName: Get the full name of a command from its token.

	    void Tcl_GetCommandFullName(Tcl_Interp *interp, Tcl_Command command,
	            Tcl_Obj *objPtr)

Each of these functions will be declared in future within
_tcl.decls_ \(with the entries in _tclInt.decls_ deprecated\) and
will also be documented.

# Copyright

This document is placed in the public domain.

Name change from tip/14.tip to tip/14.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

TIP:            14
Title:          Access to Tk Photo Image Transparency
Version:        $Revision: 2.5 $
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        22-Nov-2000
Post-History:   
Keywords:       Tk,photo,transparency,internal,access
Tcl-Version:    8.4.0


~ Abstract

It is useful for some code (both extensions and scripts) to have
access to the transparency information in photo images for various
reasons, but this is not currently available, even via an internal
structure defined in ''generic/tkInt.h''.  This TIP is aimed at making
the information available, and in such a way at the C level that
backward compatibility is maintained in the future even if the
internal structure definitions change.

~ Rationale

I have been working for several years (on-and-off) on an extension for
Tk that allows it to have non-rectangular windows
(http://www.cs.man.ac.uk/~fellowsd/tcl/shapeidx.html) which is an
effect that is great for all sorts of purposes but which comes
particularly into its own when used in conjunction with drag-and-drop
to make drag tokens that obscure only part of what lies underneath
them.  However, one of the most useful ways of specifying the shape of
a window turns out to be via images of various kinds, and the natural
way to do this is with the transparency data within the image.  The
problem is that this data is locked up entirely within structures that
are completely private to ''generic/tkImgPhoto.c''; none of it is
visible at all anywhere else, even within the core.  (There is code
that uses colour data instead to do this sort of trick,
http://www.sys.uea.ac.uk/~fuzz/tktrans/default.html, but this is a
slow process and frankly a little strange if we already have
transparency data available.)

There is also a more general need for scripts to be able to discover
more about the transparent areas of a photo image; at the moment,
there is no access at all to that information at the script level.

~ Changes to the C-Level API

To get around this problem, the data member ''validRegion'' of the
''PhotoMaster'' structure needs to be made available by some
mechanism.  There are two ways of doing this:

 1. Placing the ''PhotoMaster'' structure, or some version of it, in
    ''generic/tkInt.h'', or

 2. Creating a function to access the data member.

The first way is very cheap initially, but also very inflexible and
creates yet another hidden version dependency (such as is tackled in
[5]) should we decide to change the structure for any reason (we also
have had problems with this sort of thing in the past in relation to
the ''Tcl_Interp'' member ''result'', direct access to which has been
deprecated for years, but where there is still existing code that does
it and which forms one of the largest barriers for some extensions
from upgrading to Tcl 8.0 or later.)  It is also unnecessary since
only the core needs to know how to create new instances of the
structure.

The second way, by contrast, is far more flexible in the future as it
will allow us to completely change the internal implementation of
photo image transparency without affecting any extensions at all.  The
cost of doing this is that a new entry in one of the stub tables must
be created.  Due to the fact that the type of the ''validRegion''
member is (currently) internal, I propose adding the function to the
''tkInt'' stub interface, and I propose calling the function
''TkPhotoGetValidRegion''.

~ Changes to the Tcl-Level API

I propose to add an extra subcommand to photo image instances which
will provide all the access to and manipulation of transparency data.
I propose to call this subcommand ''transparency'' and it will have
subsubcommands to provide access to the various facilities it provides.
Initially I will provide a ''get'' subsubcommand to allow the testing
of the transparency of a single pixel (returned as a boolean value),
and a ''set'' subsubcommand to allow the setting of the transparency of
a single pixel.  I anticipate that these will be expanded in the future
to allow the manipulation of transparencies of rectangular regions
(both getting and setting) but I do not supply such at this stage.

|   image create photo phImg -file thingy.gif
|   if {[phImg transparency get 0 0]} {
|      # Top-left pixel is transparent...
|   }

|
|   # Toggle transparency...
|   phImg transparency set 0 0 [expr {![phImg transparency get 0 0]}]

~ Sample Implementation Patches

Exposing the transparency to C:
http://www.cs.man.ac.uk/~fellowsd/tcl/validRegion.patch

Exposing the transparency to Tcl:
http://www.cs.man.ac.uk/~fellowsd/tcl/patches/transCmd.patch

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|




|

|

|







|
|

|

|





|

|
|


|
|




|
|

|


|







|
|
|
|

|



|

|
|
|


|

|
|
|
<
>
|
|
|

|


|


|

|


>

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

# TIP 14: Access to Tk Photo Image Transparency

	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        22-Nov-2000
	Post-History:   
	Keywords:       Tk,photo,transparency,internal,access
	Tcl-Version:    8.4.0
-----

# Abstract

It is useful for some code \(both extensions and scripts\) to have
access to the transparency information in photo images for various
reasons, but this is not currently available, even via an internal
structure defined in _generic/tkInt.h_.  This TIP is aimed at making
the information available, and in such a way at the C level that
backward compatibility is maintained in the future even if the
internal structure definitions change.

# Rationale

I have been working for several years \(on-and-off\) on an extension for
Tk that allows it to have non-rectangular windows
\(<http://www.cs.man.ac.uk/~fellowsd/tcl/shapeidx.html\)> which is an
effect that is great for all sorts of purposes but which comes
particularly into its own when used in conjunction with drag-and-drop
to make drag tokens that obscure only part of what lies underneath
them.  However, one of the most useful ways of specifying the shape of
a window turns out to be via images of various kinds, and the natural
way to do this is with the transparency data within the image.  The
problem is that this data is locked up entirely within structures that
are completely private to _generic/tkImgPhoto.c_; none of it is
visible at all anywhere else, even within the core.  \(There is code
that uses colour data instead to do this sort of trick,
<http://www.sys.uea.ac.uk/~fuzz/tktrans/default.html,> but this is a
slow process and frankly a little strange if we already have
transparency data available.\)

There is also a more general need for scripts to be able to discover
more about the transparent areas of a photo image; at the moment,
there is no access at all to that information at the script level.

# Changes to the C-Level API

To get around this problem, the data member _validRegion_ of the
_PhotoMaster_ structure needs to be made available by some
mechanism.  There are two ways of doing this:

 1. Placing the _PhotoMaster_ structure, or some version of it, in
    _generic/tkInt.h_, or

 2. Creating a function to access the data member.

The first way is very cheap initially, but also very inflexible and
creates yet another hidden version dependency \(such as is tackled in
[[5]](5.md)\) should we decide to change the structure for any reason \(we also
have had problems with this sort of thing in the past in relation to
the _Tcl\_Interp_ member _result_, direct access to which has been
deprecated for years, but where there is still existing code that does
it and which forms one of the largest barriers for some extensions
from upgrading to Tcl 8.0 or later.\)  It is also unnecessary since
only the core needs to know how to create new instances of the
structure.

The second way, by contrast, is far more flexible in the future as it
will allow us to completely change the internal implementation of
photo image transparency without affecting any extensions at all.  The
cost of doing this is that a new entry in one of the stub tables must
be created.  Due to the fact that the type of the _validRegion_
member is \(currently\) internal, I propose adding the function to the
_tkInt_ stub interface, and I propose calling the function
_TkPhotoGetValidRegion_.

# Changes to the Tcl-Level API

I propose to add an extra subcommand to photo image instances which
will provide all the access to and manipulation of transparency data.
I propose to call this subcommand _transparency_ and it will have
subsubcommands to provide access to the various facilities it provides.
Initially I will provide a _get_ subsubcommand to allow the testing
of the transparency of a single pixel \(returned as a boolean value\),
and a _set_ subsubcommand to allow the setting of the transparency of
a single pixel.  I anticipate that these will be expanded in the future
to allow the manipulation of transparencies of rectangular regions
\(both getting and setting\) but I do not supply such at this stage.

	   image create photo phImg -file thingy.gif
	   if {[phImg transparency get 0 0]} {
	      # Top-left pixel is transparent...

	   }
	
	   # Toggle transparency...
	   phImg transparency set 0 0 [expr {![phImg transparency get 0 0]}]

# Sample Implementation Patches

Exposing the transparency to C:
<http://www.cs.man.ac.uk/~fellowsd/tcl/validRegion.patch>

Exposing the transparency to Tcl:
<http://www.cs.man.ac.uk/~fellowsd/tcl/patches/transCmd.patch>

# Copyright

This document is placed in the public domain.

Name change from tip/140.tip to tip/140.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

TIP:		140
Title:		Tracing Namespace Modifications
State:		Deferred
Type:		Project
Tcl-Version:	8.5
Vote:		Pending
Post-History:	
Version:	$Revision: 1.2 $
Author:		Donal K. Fellows <[email protected]>
Created:	04-Jun-2003


~ Abstract

This TIP allows scripts to register callbacks to monitor alterations
to namespaces, such as their deletion, the creation, renaming and
deletion of commands within the namespace and modifications to the
exports list of the namespace.

~ Rationale

As part of my work on an experimental [112] implementation, I have
discovered that computing the list of public (i.e. exported) commands
from a namespace is a comparatively expensive operation.  This means
that it is necessary (well, highly desirable) to cache the list of
exports from a namespace.  But then I thought that it might be nice to
expose that interface to use to better enable namespaces to support
other interesting uses, and that it should be possible to implement
the default behaviour in a Tcl script.  It is in support of this that
I present this TIP; I also add the ability to trace deletion of the
namespace as a fairly obvious extension.

~ Proposed Change at Tcl Script Level

I propose that the [[trace]] command be extended with a new type of
thing to trace: a namespace.  The operations that would trigger a
trace are:

 * Namespace deletion (subject to the same sorts of restrictions in
   relation to deleted interpreters that are present for traces of
   command deletion) with the ops value ''delete''.

 * Command list modification (being creation, renaming or deletion of
   any command within that namespace) with the ops value ''command''.
   Modification due to deletion of the namespace will not trigger
   traces with this operation, but instead the ''delete'' operation
   outlined above (subject to the caveats relating to interpreter
   deletion.)

 * Exports list modification (i.e. updates with [[namespace export]])
   with the ops value ''export''.  Modification due to the deletion of
   the namespace will not trigger this traces with this operation, but
   instead the ''delete'' operation outlined above (subject to the
   caveats relating to interpreter deletion.)

In each case, the trace callback script will have the fully qualified
name of the namespace and the name of the triggering operation
appended to it before execution.  In the case of command list
modification by the ''creation'' of a command (which might also be
through import of commands from another namespace, for example) there
will be an extra parameter being the ''local'' name of the command
(without namespace separators.)

These changes will be propagated to each of the [[trace add]], [[trace
remove]] and [[trace info]] subcommands, of course.

~ Proposed Change at C API Level

Yet to be designed, but will be based as closely as possible on the
existing Tcl trace APIs.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
>

|






|

|
|

|







|

|



|

|

|
|

|
|
|

|
|

|
|




|
|
|
|

|
|

|




|


>

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

# TIP 140: Tracing Namespace Modifications
	State:		Deferred
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Pending
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	04-Jun-2003
-----

# Abstract

This TIP allows scripts to register callbacks to monitor alterations
to namespaces, such as their deletion, the creation, renaming and
deletion of commands within the namespace and modifications to the
exports list of the namespace.

# Rationale

As part of my work on an experimental [[112]](112.md) implementation, I have
discovered that computing the list of public \(i.e. exported\) commands
from a namespace is a comparatively expensive operation.  This means
that it is necessary \(well, highly desirable\) to cache the list of
exports from a namespace.  But then I thought that it might be nice to
expose that interface to use to better enable namespaces to support
other interesting uses, and that it should be possible to implement
the default behaviour in a Tcl script.  It is in support of this that
I present this TIP; I also add the ability to trace deletion of the
namespace as a fairly obvious extension.

# Proposed Change at Tcl Script Level

I propose that the [trace] command be extended with a new type of
thing to trace: a namespace.  The operations that would trigger a
trace are:

 * Namespace deletion \(subject to the same sorts of restrictions in
   relation to deleted interpreters that are present for traces of
   command deletion\) with the ops value _delete_.

 * Command list modification \(being creation, renaming or deletion of
   any command within that namespace\) with the ops value _command_.
   Modification due to deletion of the namespace will not trigger
   traces with this operation, but instead the _delete_ operation
   outlined above \(subject to the caveats relating to interpreter
   deletion.\)

 * Exports list modification \(i.e. updates with [namespace export]\)
   with the ops value _export_.  Modification due to the deletion of
   the namespace will not trigger this traces with this operation, but
   instead the _delete_ operation outlined above \(subject to the
   caveats relating to interpreter deletion.\)

In each case, the trace callback script will have the fully qualified
name of the namespace and the name of the triggering operation
appended to it before execution.  In the case of command list
modification by the _creation_ of a command \(which might also be
through import of commands from another namespace, for example\) there
will be an extra parameter being the _local_ name of the command
\(without namespace separators.\)

These changes will be propagated to each of the [trace add], [trace
remove] and [trace info] subcommands, of course.

# Proposed Change at C API Level

Yet to be designed, but will be based as closely as possible on the
existing Tcl trace APIs.

# Copyright

This document has been placed in the public domain.

Name change from tip/141.tip to tip/141.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

TIP:		141
Title:		Multiple Initial-Files in [tk_getOpenFile]
Version:	$Revision: 1.8 $
Author:		David N. Welton <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Created:	18-Jul-2003
Post-History:	


~ Abstract

This TIP proposes modifying the semantics of the '''-initialfile'''
option when the '''tk_get*File''' commands are asked to select
multiple files so as to allow several files to be selected initially.

~ Rationale

The '''tk_getOpenFile''' command has a '''-multiple''' option, which
allows multiple files to be selected in the dialog.  It also has an
'''-initialfile''' argument.  However, at the present time, at least
on Unix, it is impossible to have multiple files selected initially
with '''-initialfile'''.  This TIP proposes that '''-initialfile'''
take a list of files if '''-multiple''' is also passed as an argument.

As it is possible to select multiple files, it should also be possible
to have multiple files be selected when the widget is created via the
'''-initialfile''' switch.

~~ Additional Notes from Kevin Kenny

~~~ On -initialdir

If the '''-initialdir''' value is not a well-formed path name in its
filesystem (for instance, if a component name contains a null byte or
a character that is not permissible), the behavior is as if
'''-initialdir''' was not specified.

If the object designated by the '''-initialdir''' value does not
exist, or if it is not a directory, nor a symbolic link to one, the
behavior is as if '''-initialdir''' was not specified.

If the '''-initialdir''' value is the empty string, the behavior is as
if '''-initialdir''' was not specified.

~~~ On -initialfile

If '''-multiple''' ''0'' is specified, or '''tk_getSaveFile''' was
called, the '''-initialfile''' value is interpreted as a file name.
If '''-multiple''' ''1'' is specified to '''tk_getOpenFile''', the
'''-initialfile''' value is interpreted as a list of file names.  A
list that is not well formed (for example, one containing unbalanced
braces) is not an error, but instead causes the '''-initialfile'''
option to be ignored.

For each file name in the '''-initialfile''' value, the system joins
the directory provided on the '''-initialdir''' option (or the current
working directory if no '''-initialdir''' is supplied) with the
'''-initialfile'''.  The resulting path name is normalized as with
'''file normalize''' and then separated into directory and tail
components as with '''file dirname''' and '''file tail'''.  Any errors
in this process cause the file name to be ignored.

Once the file name is separated into its components, the directory
part is checked:

 * If the '''-initialdir''' option was supplied, and the directory
   part of the file name differs from the result of normalizing the
   '''-initialdir''' value, the file name is ignored.

 * If the '''-initialdir''' option was not supplied, and the directory
   part of the file name designates a directory in the file system,
   the '''-initialdir''' value is set to that directory.  Otherwise,
   (since the file cannot exist), the file name is ignored.

 * If the given file exists, or if '''tk_getSaveFile was called''',
   the tail part of the file name is added to a list of files to
   select within the initial directory.

Once '''-initialdir''' and '''-initialfile''' have both been parsed,
the initial directory is known, and the list of initial files is
identified; the files are known to be relative to the initial
directory, and (for '''tk_getOpenFile''') are known to exist.

~ Reference Implementation

The reference implementation exists in a patch
[http://sf.net/tracker/?func=detail&aid=657656&group_id=12997&atid=362997]
which also includes new tests for the Tk test suite and updated
documentation.

~ Copyright

This document is in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|


|

|

|

|
|



|

|

|

|
|
|
|

|

|

|
|

|

|
|
|
|
|
|


|
|
|
|
|
|





|

|

|

|
|

|



|


|

|


|



|


>

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

# TIP 141: Multiple Initial-Files in [tk_getOpenFile]

	Author:		David N. Welton <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Created:	18-Jul-2003
	Post-History:	
-----

# Abstract

This TIP proposes modifying the semantics of the **-initialfile**
option when the **tk\_get\*File** commands are asked to select
multiple files so as to allow several files to be selected initially.

# Rationale

The **tk\_getOpenFile** command has a **-multiple** option, which
allows multiple files to be selected in the dialog.  It also has an
**-initialfile** argument.  However, at the present time, at least
on Unix, it is impossible to have multiple files selected initially
with **-initialfile**.  This TIP proposes that **-initialfile**
take a list of files if **-multiple** is also passed as an argument.

As it is possible to select multiple files, it should also be possible
to have multiple files be selected when the widget is created via the
**-initialfile** switch.

## Additional Notes from Kevin Kenny

### On -initialdir

If the **-initialdir** value is not a well-formed path name in its
filesystem \(for instance, if a component name contains a null byte or
a character that is not permissible\), the behavior is as if
**-initialdir** was not specified.

If the object designated by the **-initialdir** value does not
exist, or if it is not a directory, nor a symbolic link to one, the
behavior is as if **-initialdir** was not specified.

If the **-initialdir** value is the empty string, the behavior is as
if **-initialdir** was not specified.

### On -initialfile

If **-multiple** _0_ is specified, or **tk\_getSaveFile** was
called, the **-initialfile** value is interpreted as a file name.
If **-multiple** _1_ is specified to **tk\_getOpenFile**, the
**-initialfile** value is interpreted as a list of file names.  A
list that is not well formed \(for example, one containing unbalanced
braces\) is not an error, but instead causes the **-initialfile**
option to be ignored.

For each file name in the **-initialfile** value, the system joins
the directory provided on the **-initialdir** option \(or the current
working directory if no **-initialdir** is supplied\) with the
**-initialfile**.  The resulting path name is normalized as with
**file normalize** and then separated into directory and tail
components as with **file dirname** and **file tail**.  Any errors
in this process cause the file name to be ignored.

Once the file name is separated into its components, the directory
part is checked:

 * If the **-initialdir** option was supplied, and the directory
   part of the file name differs from the result of normalizing the
   **-initialdir** value, the file name is ignored.

 * If the **-initialdir** option was not supplied, and the directory
   part of the file name designates a directory in the file system,
   the **-initialdir** value is set to that directory.  Otherwise,
   \(since the file cannot exist\), the file name is ignored.

 * If the given file exists, or if **tk\_getSaveFile was called**,
   the tail part of the file name is added to a list of files to
   select within the initial directory.

Once **-initialdir** and **-initialfile** have both been parsed,
the initial directory is known, and the list of initial files is
identified; the files are known to be relative to the initial
directory, and \(for **tk\_getOpenFile**\) are known to exist.

# Reference Implementation

The reference implementation exists in a patch
<http://sf.net/tracker/?func=detail&aid=657656&group_id=12997&atid=362997> 
which also includes new tests for the Tk test suite and updated
documentation.

# Copyright

This document is in the public domain.

Name change from tip/142.tip to tip/142.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

TIP:		142
Title:		Search Path Variable to Lookup Command Names in Namespaces
Version:	$Revision: 1.3 $
Author:		Ulrich Schoebel <[email protected]>
Tcl-Version:	8.5
State:		Withdrawn
Type:		Project
Vote:		Pending
Created:	23-Jul-2003
Post-History:	
Keywords:	namespace, command lookup, search path


~ Abstract

This TIP adds a Tcl variable to define the search path for command
name lookup across namespaces.

~ Rationale

Command names (as well as variable names) are currently looked up
first in the current namspace, then, if not found, in the global
namespace.

It is often very useful to hide the commands defined in a subnamespace
from being visible from upper namespaces by ''info commands
namespace::*''. On the other hand, programmers want to use these
commands without having to type a qualified name.

 * Example:

| namespace eval ns1 {
|   proc p1 {} {
|     puts "[p2]"
|   }
| }


|
| namespace eval ns1::ns2 {
|   proc p2 {} {
|     return hello
|   }
| }



Evaluation of ''ns1::p1'' would currently lead to an error, because
''p2'' could not be found.  Even worse, if a procedure ''p2'' exists
in the global namespace, the wrong procedure would be evaluated.

~ Proposal

Add a variable ''tcl_namespacePath'' or, to avoid confusion with
variables containing file system paths, ''tcl_namespaceSearch'', that
contains a list of namespaces to be searched in that order.

The default value would be ''[[list [[namespace current]] ::]]''.

In the above example ''tcl_namespacePath'' would be set to ''[[list
[[namespace current]] [[namespace current]]::ns2]]''. ''p2'' would be
found and not unintentionally be substituted by ''::p2''.

~ Alternative

For ease of implementation and, maybe, for programmers convenience it
might be useful to always prepend the contents of this variable with
''[[namespace current]]''. The programmer expects a certain
"automatism" for this component of the search path.

Then the default value would be ''::''.

~ Implementation

To be done when this TIP is accepted.

~ Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > Insufficiently subtle.  52 will break any code that assumes the
   current behaviour (and you can bet someone will have that
   assumption) and 142 doesn't let two namespaces have different
   search paths (unless the variable is always interpreted locally,
   which just creates bizarre variable name magic.)


~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|

|




|
|




|
|
|
<
<
>
>
|
|
|
|
<
<
|
>
>
|
|


|

|
|


|

|
|
|

|



|


|

|



|






|
|
|
|


|


>

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

# TIP 142: Search Path Variable to Lookup Command Names in Namespaces

	Author:		Ulrich Schoebel <[email protected]>
	Tcl-Version:	8.5
	State:		Withdrawn
	Type:		Project
	Vote:		Pending
	Created:	23-Jul-2003
	Post-History:	
	Keywords:	namespace, command lookup, search path
-----

# Abstract

This TIP adds a Tcl variable to define the search path for command
name lookup across namespaces.

# Rationale

Command names \(as well as variable names\) are currently looked up
first in the current namspace, then, if not found, in the global
namespace.

It is often very useful to hide the commands defined in a subnamespace
from being visible from upper namespaces by _info commands
namespace::\*_. On the other hand, programmers want to use these
commands without having to type a qualified name.

 * Example:

		 namespace eval ns1 {
		   proc p1 {} {
		     puts "[p2]"


		   }
		 }
		
		 namespace eval ns1::ns2 {
		   proc p2 {} {
		     return hello


		   }
		 }

Evaluation of _ns1::p1_ would currently lead to an error, because
_p2_ could not be found.  Even worse, if a procedure _p2_ exists
in the global namespace, the wrong procedure would be evaluated.

# Proposal

Add a variable _tcl\_namespacePath_ or, to avoid confusion with
variables containing file system paths, _tcl\_namespaceSearch_, that
contains a list of namespaces to be searched in that order.

The default value would be _[list [namespace current] ::]_.

In the above example _tcl\_namespacePath_ would be set to _[list
[namespace current] [namespace current]::ns2]_. _p2_ would be
found and not unintentionally be substituted by _::p2_.

# Alternative

For ease of implementation and, maybe, for programmers convenience it
might be useful to always prepend the contents of this variable with
_[namespace current]_. The programmer expects a certain
"automatism" for this component of the search path.

Then the default value would be _::_.

# Implementation

To be done when this TIP is accepted.

# Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > Insufficiently subtle.  52 will break any code that assumes the
   current behaviour \(and you can bet someone will have that
   assumption\) and 142 doesn't let two namespaces have different
   search paths \(unless the variable is always interpreted locally,
   which just creates bizarre variable name magic.\)


# Copyright

This document is placed in the public domain.

Name change from tip/143.tip to tip/143.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363

TIP:            143
Title:          An Interpreter Resource Limiting Framework
Version:        $Revision: 1.13 $
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        25-Jul-2003
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP introduces a mechanism for creating and manipulating
per-interpreter resource limits.  This stops several significant
classes of denial-of-service attack, and can also be used to do things
like guaranteeing an answer within a particular amount of time.

~Rationale

Currently it is trivial for scripts running in even safe Tcl
interpreters to conduct a denial-of-service attack on the thread in
which they are running.  All they have to do is write a simple
infinite loop with the '''for''' or '''while''' commands.  Of course, it
is possible to put a stop to this by hiding those commands from the
interpreter, but even then it is possible to simulate the DoS effect
with the help of a procedure like this (which even under ideal
conditions will take over three days to run):

|proc x s {eval $s; eval $s; eval $s; eval $s}
|x {x {x {x {x {x {x {x {x {x {x {x {x {x {sleep 1}}}}}}}}}}}}}}

The easiest way around this, of course, is the resource quota as used
by heavyweight operating systems, perhaps combined with the
''alarm(2)'' system call.  Or at least that would be the way to do it
if it wasn't for the fact that those are ridiculously heavy
sledgehammers to take to this particular nut.  Luckily we control the
execution environment - it is a Tcl interpreter after all - so we can
implement our own checks.  It is this that is the aim of this TIP.

~~Efficiency

Efficiency of any resource monitoring system is naturally a major
concern; it is relatively simple to create a resource monitoring system
but quite a lot harder to arrange for that monitoring to be cheap enough
that its use does not greatly impact on the general speed of the program
(in this case, Tcl.)  The costs of checking time limits in particular
can be somewhat excessive because of the necessity of performing a
system call to carry out the check, but if you're performing any action
a lot, it can get costly.

My strategy for limiting the impact upon performance is to provide a
programmer-tunable per-limit parameter called the granularity.  This
specifies how often (out of all the locations in the processing of the
Tcl interpreter and bytecode engine) the limits should be checked; the
granularity is per-limit because there is this distinct difference in
the cost of checking different kinds of limits, and the limits are
tunable because the ideal frequency depends very largely on the code
being limited.  This can be combined with the fact that the test to see
if ''any'' limits have been turned on can be made extremely cheap (i.e.
just a comparison of a memory location to zero) and it allows unlimited
interpreters to perform at almost the same speed as before.

~A Tcl API for Limit Control

I propose to add a subcommand '''limit''' to the '''interp''' command and
to the object-like interpreter access commands.  It will be an error
for any safe interpreter to call the '''limit''' subcommand; master
interpreters may enable it for their safe slaves via the mechanism
interpreter aliases, as is normal for security policies.

The first argument to the '''interp limit''' command will be the name of
the interpreter whose limit is to be inspected.  The second argument
will be the name of the limit being modified; this TIP defines two
kinds of limits:

 time: Specifies when the interpreter will be prohibited from
   performing further executions.  The limit is not guaranteed to be
   hit at exactly the time given, but will not be hit before then.

 command: Specifies a maximum number of commands (see '''info
   cmdcount''') to be executed.

The third and subsequent arguments specify a series of properties
(each of which has a name that begins with a hyphen) which may be set
(if there are pairs of arguments, being the property name and the
value to set it to) or read (if there is just the property name on its
own).  If no properties are listed at all, all dictionary (see [111])
of all properties for the particular limit is returned. The set of
properties is limit-specific, but always includes the following:

 -command: A Tcl script to be executed in the global namespace of the
   interpreter reading/writing the property when the limit is found to
   be exceeded in the limited interpreter.  If no command callback is
   defined ''for this interpreter'', the '''-command''' option will be
   the empty string.  Note that multiple interpreters may set command
   callbacks that are distinct from each other; an interpreter may not
   see what other interpreters have installed (except by running a
   script in those foreign interpreters, of course.)  The order of
   calling of the callbacks is not defined by this TIP.

 > Where a callback returns any kind of exceptional condition
   (i.e. the result isn't TCL_OK) a background error is flagged up.

 -granularity: Limits will always be checked in locations where the
   ''Tcl_Async*()'' API is called, as this is called regularly by the Tcl
   interpreter (with a few exceptions relating to event loop
   handling.)  However, the cost of just checking a limit can be
   quite appreciable (it might involve system calls, say) so this
   property allows the control of how frequently, out of the
   opportunities to check a limit, are such limits actually checked.
   If the granularity is ''1'', the limit will be checked
   every time.  It is an error to try to set the granularity to less
   than ''1''.

When an interpreter hits a limit, it first runs all command callbacks
in their respective interpreters.  Once that is done, the interpreter
rechecks the limit (since the command callbacks might have decided to
raise or remove it) and if it is still exceeded it bails out the
interpreter in the following way:

 * A flag is set in the interpreter to mark the interpreter as having
   exceeded its limits.

 * The currently executing command/script in the interpreter is made
   to return with code TCL_ERROR.  (This is superior to using a novel
   return code, as third-party extensions are usually far better at
   handling error cases!)

 * The '''catch''' command will only catch errors if the interpreter
   containing it does not have the flag mentioned just above set.
   Similarly, further trips round the internal loops of the
   '''vwait''', '''update''' and '''tkwait''' commands will not
   proceed with that flag set.  (Extensions can find this information
   out by using ''Tcl_LimitExceeded()''; see below.)  No calls to
   '''bgerror''' should be made.

 * Once the execution unwinds out of the interpreter so that no
   further invocations of the interpreter are left on the call-stack,
   the flag is reset.  The same is true if the limits are adjusted in
   any way.  Note that attempting to execute things within the
   interpreter without raising the limits will result in the limit
   being hit immediately.

When resource limits are being used, unlimited master interpreters
should take care to use the '''catch''' command when calling their
limited slaves.  Otherwise hitting the limit in the slave might well
smash the master as well, just because of general error propagation.
But that is good practise anyway.

~~Time Limits

Time limits are specified in terms of the time when the limit will be
hit.  Setting the limit to the current time ensures that the limit
will be immediately activated.  Time limits have two options for
specifying the limit.

 -seconds: This sets the absolute time (in seconds from the epoch, as
   returned by '''clock seconds''') that the time limit is hit.  If
   set to the empty string, the limit is removed.  If no time limit is
   set, this option is empty when inspected.

 -milliseconds: This sets the number of milliseconds after the start
   of the second specified in the '''-seconds''' option that the time
   limit is hit.  May only be set to the empty string if the
   '''-seconds''' option is empty and present, and may only be set to
   a numeric value if the '''-seconds''' option is unspecified or
   present and non-empty (it is always safe to leave this option
   unspecified.)  If no time limit is set, this option is empty when
   inspected.

Where a time-limited interpreter creates a slave interpreter, the
slave will get the same time-limit as the creating master interpreter.

~~Command Limits

Command limits are specified in terms of the number of commands (see
'''info cmdcount''' for a definition of the metric) that may be
executed before the limit is hit.  Command limits have the following
extra option for specifying and inspecting the limit.

 -value: The number of commands (integer of course) that may actually
   be executed.  If set to the empty string, the limit is removed, and
   when introspecting, unlimited interpreters return empty strings for
   this value.

Where a command-limited interpreter creates a slave interpreter, the
slave will get the command-limit ''0'' after initialisation
(i.e. after the return from the call to ''Tcl_CreateSlave()'') and
will be unable to execute and commands until the limit for the slave
is raised.  Master interpreters implementing security policies for
safe interpreters might want to set such limits semi-automatically to
something more useful by deducting command-executions from the
creating interpreter to its new slave.

~A C-level API for Limit Control

It is also desirable for there to be a general C API for controlling
resource limits.  Not only does this provide control to extension
authors that can't be easily smashed by Tcl scripts by accident, but
it also makes implementation of the Tcl API to the limit subsystem
easier to create as well.

 * int '''Tcl_LimitReady'''(Tcl_Interp *''interp'')

 > Test whether a limit is ready to be checked according to its
   granularity rules.  Result is boolean.  Note that this is a cheap
   call.

 * int '''Tcl_LimitCheck'''(Tcl_Interp *''interp'')

 > Test whether a limit has been exceeded.  Result is boolean.  Note
   that this call is potentially expensive (checking a time limit
   requires a minimum of one system call.)

 * int '''Tcl_LimitExceeded'''(Tcl_Interp *''interp'')

 > Test whether the interpreter is in a state where a limit has been
   previously exceeded (i.e. whether a previous call to
   '''Tcl_LimitCheck''' had indicated that a limit had been hit) and
   not yet reset (by extending or removing the relevant limit.)
   Result is boolean.  Note that this is a cheap call.

 * int '''Tcl_LimitTypeEnabled'''(Tcl_Interp *''interp'', int ''type'')

 > Test whether the given type of limit is turned on.  Result is boolean.
   Note that this is a cheap call.

 * int '''Tcl_LimitTypeExceeded'''(Tcl_Interp *''interp'', int ''type'')

 > Test whether the given type of limit has been hit (in the notion of
   '''Tcl_LimitExceeded''') and not yet reset.  Result is boolean.
   Note that this is a cheap call.

 * void '''Tcl_LimitTypeSet'''(Tcl_Interp *''interp'', int ''type'')

 > Turn on the given type of limit.

 * void '''Tcl_LimitTypeReset'''(Tcl_Interp *''interp'', int ''type'')

 > Turn off the given type of limit.

 * void '''Tcl_LimitAddHandler'''(Tcl_Interp *''interp'', int ''type'',
	Tcl_LimitHandlerProc *''handlerProc'', ClientData ''clientData'',
	Tcl_LimitHandlerDeleteProc *''deleteProc'')

 > Add a limit handler for the given type of limit and specify some
   caller context and a scheme for deleting that context.

 * void '''Tcl_LimitRemoveHandler'''(Tcl_Interp *''interp'', int ''type'',
	Tcl_LimitHandlerProc *''handlerProc'', ClientData ''clientData'')

 > Remove a limit handler for the given type of limit.  It is not an
   error to delete a limit that was not set; in that case, nothing is
   changed.

 * void '''Tcl_LimitSetCommands'''(Tcl_Interp *''interp'',
	int ''commandLimit'')

 > Set a limiting value on the number of commands, and reset whether
   the limit has been triggered.  Does not enable the limit.

 * int '''Tcl_LimitGetCommands'''(Tcl_Interp *''interp'')

 > Get the current limit on the number of commands.

 * void '''Tcl_LimitSetTime'''(Tcl_Interp *''interp'', Tcl_Time *''timeLimitPtr'')

 > Set a limiting value (copying it from the buffer pointed to by
   ''timeLimitPtr'') on the latest time that the code may execute, and
   reset whether the limit has been triggered.  Does not enable the
   limit.  The ''usec'' field of the buffer should be in the range 0
   to 999999.

 * void '''Tcl_LimitGetTime'''(Tcl_Interp *''interp'', Tcl_Time *''timeLimitPtr'')

 > Get the current limit on the execution time, writing it into the
   buffer pointed to by ''timeLimitPtr''.

 * void '''Tcl_LimitSetGranularity'''(Tcl_Interp *''interp'', int ''type'',
	int ''granularity'')

 > Set the checking granularity for the given type of limit.

 * int '''Tcl_LimitGetGranularity'''(Tcl_Interp *''interp'', int ''type'')

 > Get the checking granularity for the given type of limit.

Above, ''type'' is either TCL_LIMIT_COMMANDS or TCL_LIMIT_TIME,
''handlerProc'' is a pointer to a function that takes two parameters
(a ClientData and a Tcl_Interp*) and returns void, and ''deleteProc''
is a pointer to a function that takes a single parameter (a
ClientData) and returns void.  The key is that ''handlerProc''s are
called when a limit is hit (they are used to implement the guts of the
'''-command''' option), and when the callback is deleted for any
reason (including a call to '''Tcl_LimitRemoveHandler''' and deleting
the limited interpreter) the ''deleteProc'' is called to release the
resources consumed by the ''clientData'' context.

~Use Cases

~~WebServices

One use for this sort of code might be in a web-services context where
it is important to return a message to some client code within some
interval.  Using an in-process limiting mechanism allows this to be
implemented in a far more light-weight fashion, as the alternative would
be to fork off a new small application server for each incoming request
and it would be considerably more complex to have a scripted executive
that decides (possibly by examining the stack) whether a failure to
deliver an answer within bounds is serious, or whether some extra
resources should be granted to allow execution to run to completion.
Other high-performance server applications would also be likely to gain
from this sort of thing.

~~Profiling

It is possible to use the limiting code (and especially the script
callbacks) to write a Tcl profiler.  Every time the limit runs out, the
callback can examine the Tcl stack in the limited interpreter and then
assign some more resources to last up until the next profile trap.

~~Untrusted Code Execution

As indicated earlier, these limits can be used to increase control over
untrusted code running in safe interpreters.  While it would be
necessary to extend this to memory consumption for every aspect that
could be impacted by some malicious code to be controllable, having
control over the number of commands that may be executed and how long
those commands may take gives a much higher degree of control than
currently exists, and is thus a monotonic improvement.

~Possible Future Directions

There are some obvious other things that could be brought within this
framework, but which I've left out for various reasons:

 call stack: We already do limiting of this, so bring that within this
   framework would be a nice regularisation.  On the other hand, such
   a change would not be backward-compatible, and it might not be safe
   to perform the callbacks either (especially as overflowing the
   stack is fatal in a way that overrunning on time is not.)

 memory: Limiting the amount of memory that an interpreter may
   allocate for its own use would be very nice.  But conceptually
   difficult to do (what about memory shared between interpreters?),
   expensive to keep track of (memory debugging is known to add a lot
   of overhead, and memory limiting would be more intrusive) and a
   really big change technically too (i.e. you'd be rewriting a
   significant fraction of the Tcl C API to make sure that every
   memory allocation knows which interpreter owns it.)

 open channels, file sizes, etc.: Most other things can be limited in
   Tcl right now without special support.

~Implementation

An example implementation of this TIP is available as a patch
[http://sf.net/tracker/?func=detail&aid=926771&group_id=10894&atid=310894].

~Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|






|




|


|
|

|
|



|





|





|






|
|




|
|


|

|

|



|








|
|


|
|
|
|






|


|
|



|


|
|
|
|


|

|



|
|






|

|

|


|
|
|
|









|




|






|
|




|

|
|
|
|





|

|
|



|





|
|






|







|

|



|

|
|
|

|

|
|
|
|


|

|


|

|
|


|

|

|

|

|
|
|

|


|
|

|



|
|

|


|

|

|

|
|

|


|

|
|

|
|

|

|

|

|
|
|
|
|
|
|
|
|
|

|

|







|





|

|
|



|









|







|
|



|
|
|
|

|




|


|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363

# TIP 143: An Interpreter Resource Limiting Framework

	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        25-Jul-2003
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP introduces a mechanism for creating and manipulating
per-interpreter resource limits.  This stops several significant
classes of denial-of-service attack, and can also be used to do things
like guaranteeing an answer within a particular amount of time.

# Rationale

Currently it is trivial for scripts running in even safe Tcl
interpreters to conduct a denial-of-service attack on the thread in
which they are running.  All they have to do is write a simple
infinite loop with the **for** or **while** commands.  Of course, it
is possible to put a stop to this by hiding those commands from the
interpreter, but even then it is possible to simulate the DoS effect
with the help of a procedure like this \(which even under ideal
conditions will take over three days to run\):

	proc x s {eval $s; eval $s; eval $s; eval $s}
	x {x {x {x {x {x {x {x {x {x {x {x {x {x {sleep 1}}}}}}}}}}}}}}

The easiest way around this, of course, is the resource quota as used
by heavyweight operating systems, perhaps combined with the
_alarm\(2\)_ system call.  Or at least that would be the way to do it
if it wasn't for the fact that those are ridiculously heavy
sledgehammers to take to this particular nut.  Luckily we control the
execution environment - it is a Tcl interpreter after all - so we can
implement our own checks.  It is this that is the aim of this TIP.

## Efficiency

Efficiency of any resource monitoring system is naturally a major
concern; it is relatively simple to create a resource monitoring system
but quite a lot harder to arrange for that monitoring to be cheap enough
that its use does not greatly impact on the general speed of the program
\(in this case, Tcl.\)  The costs of checking time limits in particular
can be somewhat excessive because of the necessity of performing a
system call to carry out the check, but if you're performing any action
a lot, it can get costly.

My strategy for limiting the impact upon performance is to provide a
programmer-tunable per-limit parameter called the granularity.  This
specifies how often \(out of all the locations in the processing of the
Tcl interpreter and bytecode engine\) the limits should be checked; the
granularity is per-limit because there is this distinct difference in
the cost of checking different kinds of limits, and the limits are
tunable because the ideal frequency depends very largely on the code
being limited.  This can be combined with the fact that the test to see
if _any_ limits have been turned on can be made extremely cheap \(i.e.
just a comparison of a memory location to zero\) and it allows unlimited
interpreters to perform at almost the same speed as before.

# A Tcl API for Limit Control

I propose to add a subcommand **limit** to the **interp** command and
to the object-like interpreter access commands.  It will be an error
for any safe interpreter to call the **limit** subcommand; master
interpreters may enable it for their safe slaves via the mechanism
interpreter aliases, as is normal for security policies.

The first argument to the **interp limit** command will be the name of
the interpreter whose limit is to be inspected.  The second argument
will be the name of the limit being modified; this TIP defines two
kinds of limits:

 time: Specifies when the interpreter will be prohibited from
   performing further executions.  The limit is not guaranteed to be
   hit at exactly the time given, but will not be hit before then.

 command: Specifies a maximum number of commands \(see **info
   cmdcount**\) to be executed.

The third and subsequent arguments specify a series of properties
\(each of which has a name that begins with a hyphen\) which may be set
\(if there are pairs of arguments, being the property name and the
value to set it to\) or read \(if there is just the property name on its
own\).  If no properties are listed at all, all dictionary \(see [[111]](111.md)\)
of all properties for the particular limit is returned. The set of
properties is limit-specific, but always includes the following:

 -command: A Tcl script to be executed in the global namespace of the
   interpreter reading/writing the property when the limit is found to
   be exceeded in the limited interpreter.  If no command callback is
   defined _for this interpreter_, the **-command** option will be
   the empty string.  Note that multiple interpreters may set command
   callbacks that are distinct from each other; an interpreter may not
   see what other interpreters have installed \(except by running a
   script in those foreign interpreters, of course.\)  The order of
   calling of the callbacks is not defined by this TIP.

 > Where a callback returns any kind of exceptional condition
   \(i.e. the result isn't TCL\_OK\) a background error is flagged up.

 -granularity: Limits will always be checked in locations where the
   _Tcl\_Async\*\(\)_ API is called, as this is called regularly by the Tcl
   interpreter \(with a few exceptions relating to event loop
   handling.\)  However, the cost of just checking a limit can be
   quite appreciable \(it might involve system calls, say\) so this
   property allows the control of how frequently, out of the
   opportunities to check a limit, are such limits actually checked.
   If the granularity is _1_, the limit will be checked
   every time.  It is an error to try to set the granularity to less
   than _1_.

When an interpreter hits a limit, it first runs all command callbacks
in their respective interpreters.  Once that is done, the interpreter
rechecks the limit \(since the command callbacks might have decided to
raise or remove it\) and if it is still exceeded it bails out the
interpreter in the following way:

 * A flag is set in the interpreter to mark the interpreter as having
   exceeded its limits.

 * The currently executing command/script in the interpreter is made
   to return with code TCL\_ERROR.  \(This is superior to using a novel
   return code, as third-party extensions are usually far better at
   handling error cases!\)

 * The **catch** command will only catch errors if the interpreter
   containing it does not have the flag mentioned just above set.
   Similarly, further trips round the internal loops of the
   **vwait**, **update** and **tkwait** commands will not
   proceed with that flag set.  \(Extensions can find this information
   out by using _Tcl\_LimitExceeded\(\)_; see below.\)  No calls to
   **bgerror** should be made.

 * Once the execution unwinds out of the interpreter so that no
   further invocations of the interpreter are left on the call-stack,
   the flag is reset.  The same is true if the limits are adjusted in
   any way.  Note that attempting to execute things within the
   interpreter without raising the limits will result in the limit
   being hit immediately.

When resource limits are being used, unlimited master interpreters
should take care to use the **catch** command when calling their
limited slaves.  Otherwise hitting the limit in the slave might well
smash the master as well, just because of general error propagation.
But that is good practise anyway.

## Time Limits

Time limits are specified in terms of the time when the limit will be
hit.  Setting the limit to the current time ensures that the limit
will be immediately activated.  Time limits have two options for
specifying the limit.

 -seconds: This sets the absolute time \(in seconds from the epoch, as
   returned by **clock seconds**\) that the time limit is hit.  If
   set to the empty string, the limit is removed.  If no time limit is
   set, this option is empty when inspected.

 -milliseconds: This sets the number of milliseconds after the start
   of the second specified in the **-seconds** option that the time
   limit is hit.  May only be set to the empty string if the
   **-seconds** option is empty and present, and may only be set to
   a numeric value if the **-seconds** option is unspecified or
   present and non-empty \(it is always safe to leave this option
   unspecified.\)  If no time limit is set, this option is empty when
   inspected.

Where a time-limited interpreter creates a slave interpreter, the
slave will get the same time-limit as the creating master interpreter.

## Command Limits

Command limits are specified in terms of the number of commands \(see
**info cmdcount** for a definition of the metric\) that may be
executed before the limit is hit.  Command limits have the following
extra option for specifying and inspecting the limit.

 -value: The number of commands \(integer of course\) that may actually
   be executed.  If set to the empty string, the limit is removed, and
   when introspecting, unlimited interpreters return empty strings for
   this value.

Where a command-limited interpreter creates a slave interpreter, the
slave will get the command-limit _0_ after initialisation
\(i.e. after the return from the call to _Tcl\_CreateSlave\(\)_\) and
will be unable to execute and commands until the limit for the slave
is raised.  Master interpreters implementing security policies for
safe interpreters might want to set such limits semi-automatically to
something more useful by deducting command-executions from the
creating interpreter to its new slave.

# A C-level API for Limit Control

It is also desirable for there to be a general C API for controlling
resource limits.  Not only does this provide control to extension
authors that can't be easily smashed by Tcl scripts by accident, but
it also makes implementation of the Tcl API to the limit subsystem
easier to create as well.

 * int **Tcl\_LimitReady**\(Tcl\_Interp \*_interp_\)

	 > Test whether a limit is ready to be checked according to its
   granularity rules.  Result is boolean.  Note that this is a cheap
   call.

 * int **Tcl\_LimitCheck**\(Tcl\_Interp \*_interp_\)

	 > Test whether a limit has been exceeded.  Result is boolean.  Note
   that this call is potentially expensive \(checking a time limit
   requires a minimum of one system call.\)

 * int **Tcl\_LimitExceeded**\(Tcl\_Interp \*_interp_\)

	 > Test whether the interpreter is in a state where a limit has been
   previously exceeded \(i.e. whether a previous call to
   **Tcl\_LimitCheck** had indicated that a limit had been hit\) and
   not yet reset \(by extending or removing the relevant limit.\)
   Result is boolean.  Note that this is a cheap call.

 * int **Tcl\_LimitTypeEnabled**\(Tcl\_Interp \*_interp_, int _type_\)

	 > Test whether the given type of limit is turned on.  Result is boolean.
   Note that this is a cheap call.

 * int **Tcl\_LimitTypeExceeded**\(Tcl\_Interp \*_interp_, int _type_\)

	 > Test whether the given type of limit has been hit \(in the notion of
   **Tcl\_LimitExceeded**\) and not yet reset.  Result is boolean.
   Note that this is a cheap call.

 * void **Tcl\_LimitTypeSet**\(Tcl\_Interp \*_interp_, int _type_\)

	 > Turn on the given type of limit.

 * void **Tcl\_LimitTypeReset**\(Tcl\_Interp \*_interp_, int _type_\)

	 > Turn off the given type of limit.

 * void **Tcl\_LimitAddHandler**\(Tcl\_Interp \*_interp_, int _type_,
	Tcl\_LimitHandlerProc \*_handlerProc_, ClientData _clientData_,
	Tcl\_LimitHandlerDeleteProc \*_deleteProc_\)

	 > Add a limit handler for the given type of limit and specify some
   caller context and a scheme for deleting that context.

 * void **Tcl\_LimitRemoveHandler**\(Tcl\_Interp \*_interp_, int _type_,
	Tcl\_LimitHandlerProc \*_handlerProc_, ClientData _clientData_\)

	 > Remove a limit handler for the given type of limit.  It is not an
   error to delete a limit that was not set; in that case, nothing is
   changed.

 * void **Tcl\_LimitSetCommands**\(Tcl\_Interp \*_interp_,
	int _commandLimit_\)

	 > Set a limiting value on the number of commands, and reset whether
   the limit has been triggered.  Does not enable the limit.

 * int **Tcl\_LimitGetCommands**\(Tcl\_Interp \*_interp_\)

	 > Get the current limit on the number of commands.

 * void **Tcl\_LimitSetTime**\(Tcl\_Interp \*_interp_, Tcl\_Time \*_timeLimitPtr_\)

	 > Set a limiting value \(copying it from the buffer pointed to by
   _timeLimitPtr_\) on the latest time that the code may execute, and
   reset whether the limit has been triggered.  Does not enable the
   limit.  The _usec_ field of the buffer should be in the range 0
   to 999999.

 * void **Tcl\_LimitGetTime**\(Tcl\_Interp \*_interp_, Tcl\_Time \*_timeLimitPtr_\)

	 > Get the current limit on the execution time, writing it into the
   buffer pointed to by _timeLimitPtr_.

 * void **Tcl\_LimitSetGranularity**\(Tcl\_Interp \*_interp_, int _type_,
	int _granularity_\)

	 > Set the checking granularity for the given type of limit.

 * int **Tcl\_LimitGetGranularity**\(Tcl\_Interp \*_interp_, int _type_\)

	 > Get the checking granularity for the given type of limit.

Above, _type_ is either TCL\_LIMIT\_COMMANDS or TCL\_LIMIT\_TIME,
_handlerProc_ is a pointer to a function that takes two parameters
\(a ClientData and a Tcl\_Interp\*\) and returns void, and _deleteProc_
is a pointer to a function that takes a single parameter \(a
ClientData\) and returns void.  The key is that _handlerProc_s are
called when a limit is hit \(they are used to implement the guts of the
**-command** option\), and when the callback is deleted for any
reason \(including a call to **Tcl\_LimitRemoveHandler** and deleting
the limited interpreter\) the _deleteProc_ is called to release the
resources consumed by the _clientData_ context.

# Use Cases

## WebServices

One use for this sort of code might be in a web-services context where
it is important to return a message to some client code within some
interval.  Using an in-process limiting mechanism allows this to be
implemented in a far more light-weight fashion, as the alternative would
be to fork off a new small application server for each incoming request
and it would be considerably more complex to have a scripted executive
that decides \(possibly by examining the stack\) whether a failure to
deliver an answer within bounds is serious, or whether some extra
resources should be granted to allow execution to run to completion.
Other high-performance server applications would also be likely to gain
from this sort of thing.

## Profiling

It is possible to use the limiting code \(and especially the script
callbacks\) to write a Tcl profiler.  Every time the limit runs out, the
callback can examine the Tcl stack in the limited interpreter and then
assign some more resources to last up until the next profile trap.

## Untrusted Code Execution

As indicated earlier, these limits can be used to increase control over
untrusted code running in safe interpreters.  While it would be
necessary to extend this to memory consumption for every aspect that
could be impacted by some malicious code to be controllable, having
control over the number of commands that may be executed and how long
those commands may take gives a much higher degree of control than
currently exists, and is thus a monotonic improvement.

# Possible Future Directions

There are some obvious other things that could be brought within this
framework, but which I've left out for various reasons:

 call stack: We already do limiting of this, so bring that within this
   framework would be a nice regularisation.  On the other hand, such
   a change would not be backward-compatible, and it might not be safe
   to perform the callbacks either \(especially as overflowing the
   stack is fatal in a way that overrunning on time is not.\)

 memory: Limiting the amount of memory that an interpreter may
   allocate for its own use would be very nice.  But conceptually
   difficult to do \(what about memory shared between interpreters?\),
   expensive to keep track of \(memory debugging is known to add a lot
   of overhead, and memory limiting would be more intrusive\) and a
   really big change technically too \(i.e. you'd be rewriting a
   significant fraction of the Tcl C API to make sure that every
   memory allocation knows which interpreter owns it.\)

 open channels, file sizes, etc.: Most other things can be limited in
   Tcl right now without special support.

# Implementation

An example implementation of this TIP is available as a patch
<http://sf.net/tracker/?func=detail&aid=926771&group_id=10894&atid=310894> .

# Copyright

This document is placed in the public domain.

Name change from tip/144.tip to tip/144.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

TIP:            144
Title:          Argument Expansion Syntax
Version:        $Revision: 1.8 $
Author:         Peter Spjuth <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        26-Jul-2003
Post-History:   
Obsoleted-By:	157
Tcl-Version:    8.5


~ Abstract

This TIP proposes to add syntax in Tcl to 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
something specialised in doing this would be better.

~ Background

See also [103].  Please also see a summary of a
poll of TCLCORE readers taken after [103] was
rejected.
http://wiki.tcl.tk/9462

~ Rationale

For examples three statements are used.  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 syntax they become:

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

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.

~ Specification

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:

|cmd "{}$temp" \{}[something]

''Note 2:'' Expansion is typically most useful with words like:

|cmd {}$var {}[somecmd $arg] {}$arr([cmd $arg])

But things like this are also legal:

|cmd {}word {}$x,$y {}[foo]xy[apa] {}{apa bepa}

~ Motivating Examples

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:

|exec prog1 {}$optlist1 | prog2 {}$optlist2 | prog3 -staticOption

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:

|set id [$canv create polygon {}$coords -fill {} {}$opts -tags {foo bar}]

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:

|namespace eval my {
|   variable defaults {
|      -bg white
|      -fg black
|   }

|   proc entry {path args} {
|      variable defaults
|      ::entry $path {}$defaults {}[platformOpts $::tcl_platform(platform)] {}$args
|   }
|}



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:

|$text delete {}[$text tag ranges $tagToCleanUp]

In this case, the obvious alternative:

|foreach {s e} [$text tag ranges $theTag] { $text delete $s $e }

is wrong, because the positions of the tags move with each deletion (by contrast, the [[$text delete]] operation is careful in this regard.)

~ Reference Implementation

Not done yet.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|




|






|





|

|
|

|

|



|
|
|





|



|
|
|





|

|



|


|






|


|

|

|



|

|


|





|







|


|
|
|








|
|
|
|
<
>
|
|
|
<
<
|
>
>
|



|
|


|



|

|

|



|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

# TIP 144: Argument Expansion Syntax

	Author:         Peter Spjuth <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        26-Jul-2003
	Post-History:   
	Obsoleted-By:	157
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to add syntax in Tcl to 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
something specialised in doing this would be better.

# Background

See also [[103]](103.md).  Please also see a summary of a
poll of TCLCORE readers taken after [[103]](103.md) was
rejected.
<http://wiki.tcl.tk/9462>

# Rationale

For examples three statements are used.  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 syntax they become:

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

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.

# Specification

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:

	cmd "{}$temp" \{}[something]

_Note 2:_ Expansion is typically most useful with words like:

	cmd {}$var {}[somecmd $arg] {}$arr([cmd $arg])

But things like this are also legal:

	cmd {}word {}$x,$y {}[foo]xy[apa] {}{apa bepa}

# Motivating Examples

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:

	exec prog1 {}$optlist1 | prog2 {}$optlist2 | prog3 -staticOption

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:

	set id [$canv create polygon {}$coords -fill {} {}$opts -tags {foo bar}]

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:

	namespace eval my {
	   variable defaults {
	      -bg white
	      -fg black

	   }
	   proc entry {path args} {
	      variable defaults
	      ::entry $path {}$defaults {}[platformOpts $::tcl_platform(platform)] {}$args


	   }
	}

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:

	$text delete {}[$text tag ranges $tagToCleanUp]

In this case, the obvious alternative:

	foreach {s e} [$text tag ranges $theTag] { $text delete $s $e }

is wrong, because the positions of the tags move with each deletion \(by contrast, the [$text delete] operation is careful in this regard.\)

# Reference Implementation

Not done yet.

# Copyright

This document has been placed in the public domain.

Name change from tip/145.tip to tip/145.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217

TIP:            145
Title:          Enhanced Tk Font Handling
Version:        $Revision: 1.10 $
Author:         Pat Thoyts <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        31-Jul-2003
Post-History:   
Obsoletes:      64
Tcl-Version:    8.5


~ Abstract

[64] suggests some improvements to font handling under windows.
However, not all of this TIP appears to have been implemented and I
believe this can be done better using the Tk named fonts mechanism.

~ Rationale

Windows, and no doubt MacOS as well, provide a number of system
defined fonts.  These are fonts that may be configured by the end user
and that all applications are expected to use.  The list includes the
menu font, the caption font, the tooltip font and others.  Some of the
special fonts have been given symbolic names but these are not
available to dynamic inspection.  This TIP proposes to make these
fonts available using the named font mechanism as used by the '''font
create''' command.  This has some significant advantages.  The set of
special font names becomes available to the programmer using the
'''font names''' command.  The font configuration is available using the
'''font configure''' command.  Also there is already a scheme in place
to update all widgets using a named font when that fonts configuration
changes.  It is now a simple matter of re-defining the system fonts on
receipt of the WM_SETTINGCHANGE message to have Tk properly reflect
changes to the system-wide font selection.

~ Proposed Changes

~~ Generic changes

The named font creation routine '''CreateNamedFont()''' is to be exposed
on the public API as '''Tk_CreateNamedFont()'''.  Also, the code used to
delete a named font should be factored out into an API function,
'''Tk_DeleteNamedFont()'''.

~~ Windows Platform-Specific Changes

A '''TkWinSetupSystemFonts()''' function is to be created which obtains
the font description for the system fonts and calls
'''Tk_CreateNamedFont()''' appropriately.  This needs to be called during
font package initialization.  The fonts are obtained using the Win32
''SystemParameters'' API and the set of defined stock object identifiers
used with ''GetStockObject''.

The toplevel Windows message message handler function '''WmProc''' must
handle the WM_SETTINGCHANGE message by calling the
'''TkWinSetupSystemFonts()''' function.  This must call '''Tk_DeleteNamedFont'''
and then '''Tk_CreateNamedFont''' to properly re-define the font and to
propagate this change to all Tk widgets concerned. The Tk wigets will
properly handle the font update by calling their ''WorldChanged''
procedures.

~~ Cross-Platform Concerns

It seems likely to be useful to ensure that aliases are available for
each platform for the set of system fonts.  This is currently done for
the Tk cursors and helps to ensure that a script written for one
system will usefully operate on another platform.

Tk currently guarantees that "''Courier''", "''Times''" and "''Helvetica''" will
always be available and are mapped to something suitable. It has been
proposed that these should really be "''monospace''", "''serif''" and
"''sans-serif''". The CSS specification
[http://www.w3.org/TR/REC-CSS2/fonts.html#generic-font-families]
defines these plus "''cursive''"
and "''fantasy''" but there seems no good reason to include these two
names.

~~ System Defined Fonts

~~~ Windows

The current set of special font names that Tk defines under windows
are as follows, all with  -underline 0 -overstrike 0 -slant roman

|    ansi           -family {MS Sans Serif}  -size 8  -weight normal
|    ansifixed      -family {Courier New}    -size 10 -weight normal
|    defaultgui     -family {MS Shell Dlg}   -size 8  -weight normal
|    device         -family System           -size 10 -weight bold
|    fixed          -family {Courier New}    -size 10 -weight normal
|    oemfixed       -family Terminal         -size 9  -weight normal
|    system         -family System           -size 10 -weight bold
|    systemfixed    -family Fixedsys         -size 9  -weight normal

These are: ansi, windows variable pitch system font; ansifixed, a
monospace version of ansi; defaultgui, default GDI font for menus and
dialog boxes; system, used for system.....

We can additionally provide from Windows system settings

|    TkCaptionFont      -family {Trebuchet MS} -size 10 -weight bold
|    TkIconFont         -family Tahoma         -size 8  -weight normal
|    TkMenuFont         -family Tahoma         -size 8  -weight normal
|    TkMessageFont      -family Tahoma         -size 8  -weight normal
|    TkSmallCaptionFont -family Tahoma         -size 8  -weight bold
|    TkStatusFont       -family Tahoma         -size 8  -weight normal

These are fairly obvious. The caption font appears in the window title
bar, the icon font for desktop icons, message font for message boxes,
menu font, small caption font is for toolbox-type dialogs with very
thin title bars. Finally status font is the font used for tooltips and
status bars. All these Tk* fonts can be changed via the Windows
Desktop properties dialog.

~~~ Motif

|    XmNbuttonFontList		(for pushbuttons in dialogs)
|    XmNlabelFontList		(for labels)
|    XmNtextFontList		(for text entry fields)
|    XmNdefaultFontList		(for everything else)

~~~ GNOME

Gnome or GTK+ documentation, but the Gnome 2.2 "Font Preferences"
dialog lets you specify:

|    Application font
|    Desktop font
|    Window title font
|    Terminal font

It appears that all GTK+ UI controls use the same "Application" font.

~~~ KDE

KDE's font preferences dialog lists:

|    General
|    Fixed Width
|    Toolbar
|    Menu
|    Window Title
|    Taskbar

~~~ Aqua

Aqua defines the following
[http://developer.apple.com/documentation/UserExperience/Conceptual/AquaHIGuidelines/AHIGFonts/index.html]:

|     System font
|     Emphasized system font
|     Small system font
|     Emphasized small system font
|     Application font
|     Label font
|     Mini system font

 > The system font is used for text in menus, modeless dialogs, and
   titles of document windows [...]  The small system font is used for
   informative text in alerts [...]. It is also the default font for
   headings in lists, for help tags, and for text in the small
   versions of many controls.  If your application creates text
   documents, use the application font as the default for user-created
   content.  The label font is used for labels with controls such as
   sliders and icon bevel buttons.  If necessary, the mini system font
   can be used for utility window labels and text.  Use emphasized
   system fonts sparingly.

An alternative reference [http://developer.apple.com/documentation/Carbon/Reference/Appearance_Manager/appearance_manager/constant_15.html] lists:

|    kThemeSystemFont
|    kThemeSmallSystemFont
|    kThemeSmallEmphasizedSystemFont
|    kThemeViewsFont
|    kThemeEmphasizedSystemFont
|    kThemeApplicationFont
|    kThemeLabelFont
|    kThemeMenuTitleFont
|    kThemeMenuItemFont
|    kThemeMenuItemMarkFont
|    kThemeMenuItemCmdKeyFont
|    kThemeWindowTitleFont
|    kThemePushButtonFont
|    kThemeUtilityWindowTitleFont
|    kThemeAlertHeaderFont
|    kThemeSystemFontDetail
|    kThemeSystemFontDetailEmphasized
|    kThemeToolbarFont

~ Suggested Tk Font Aliases

From all the above this TIP suggests that the following names be provided
for all platforms and where possible these map to system defined fonts.

 TkDefaultFont: the default for all GUI items not otherwise specified.

 TkFixedFont: standard fixed width font

 TkMenuFont: used for menu items

 TkCaptionFont: used for window and dialog caption bars

 TkSmallCaptionFont: used for captions on contained windows or tool
   dialogs.

 TkIconFont: font in use for icon captions

 TkTooltipFont: a font to use for tooltip windows (transient
   information windows)

~ Implementation

http://sf.net/tracker/?func=detail&aid=780617&group_id=12997&atid=312997

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|







|
|

|
|


|


|

|

|
|

|

|

|

|

|
|

|
|
|
|

|


|






|

|
|
|
|
|


|

|




|
|
|
|
|
|
|
|







|
|
|
|
|
|





|


|

|
|
|
|

|

|


|
|
|
|

|

|



|
|
|
|
|
|

|


|

|
|
|
|
|
|
|












|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|

















|
|

|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217

# TIP 145: Enhanced Tk Font Handling

	Author:         Pat Thoyts <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        31-Jul-2003
	Post-History:   
	Obsoletes:      64
	Tcl-Version:    8.5
-----

# Abstract

[[64]](64.md) suggests some improvements to font handling under windows.
However, not all of this TIP appears to have been implemented and I
believe this can be done better using the Tk named fonts mechanism.

# Rationale

Windows, and no doubt MacOS as well, provide a number of system
defined fonts.  These are fonts that may be configured by the end user
and that all applications are expected to use.  The list includes the
menu font, the caption font, the tooltip font and others.  Some of the
special fonts have been given symbolic names but these are not
available to dynamic inspection.  This TIP proposes to make these
fonts available using the named font mechanism as used by the **font
create** command.  This has some significant advantages.  The set of
special font names becomes available to the programmer using the
**font names** command.  The font configuration is available using the
**font configure** command.  Also there is already a scheme in place
to update all widgets using a named font when that fonts configuration
changes.  It is now a simple matter of re-defining the system fonts on
receipt of the WM\_SETTINGCHANGE message to have Tk properly reflect
changes to the system-wide font selection.

# Proposed Changes

## Generic changes

The named font creation routine **CreateNamedFont\(\)** is to be exposed
on the public API as **Tk\_CreateNamedFont\(\)**.  Also, the code used to
delete a named font should be factored out into an API function,
**Tk\_DeleteNamedFont\(\)**.

## Windows Platform-Specific Changes

A **TkWinSetupSystemFonts\(\)** function is to be created which obtains
the font description for the system fonts and calls
**Tk\_CreateNamedFont\(\)** appropriately.  This needs to be called during
font package initialization.  The fonts are obtained using the Win32
_SystemParameters_ API and the set of defined stock object identifiers
used with _GetStockObject_.

The toplevel Windows message message handler function **WmProc** must
handle the WM\_SETTINGCHANGE message by calling the
**TkWinSetupSystemFonts\(\)** function.  This must call **Tk\_DeleteNamedFont**
and then **Tk\_CreateNamedFont** to properly re-define the font and to
propagate this change to all Tk widgets concerned. The Tk wigets will
properly handle the font update by calling their _WorldChanged_
procedures.

## Cross-Platform Concerns

It seems likely to be useful to ensure that aliases are available for
each platform for the set of system fonts.  This is currently done for
the Tk cursors and helps to ensure that a script written for one
system will usefully operate on another platform.

Tk currently guarantees that "_Courier_", "_Times_" and "_Helvetica_" will
always be available and are mapped to something suitable. It has been
proposed that these should really be "_monospace_", "_serif_" and
"_sans-serif_". The CSS specification
<http://www.w3.org/TR/REC-CSS2/fonts.html#generic-font-families> 
defines these plus "_cursive_"
and "_fantasy_" but there seems no good reason to include these two
names.

## System Defined Fonts

### Windows

The current set of special font names that Tk defines under windows
are as follows, all with  -underline 0 -overstrike 0 -slant roman

	    ansi           -family {MS Sans Serif}  -size 8  -weight normal
	    ansifixed      -family {Courier New}    -size 10 -weight normal
	    defaultgui     -family {MS Shell Dlg}   -size 8  -weight normal
	    device         -family System           -size 10 -weight bold
	    fixed          -family {Courier New}    -size 10 -weight normal
	    oemfixed       -family Terminal         -size 9  -weight normal
	    system         -family System           -size 10 -weight bold
	    systemfixed    -family Fixedsys         -size 9  -weight normal

These are: ansi, windows variable pitch system font; ansifixed, a
monospace version of ansi; defaultgui, default GDI font for menus and
dialog boxes; system, used for system.....

We can additionally provide from Windows system settings

	    TkCaptionFont      -family {Trebuchet MS} -size 10 -weight bold
	    TkIconFont         -family Tahoma         -size 8  -weight normal
	    TkMenuFont         -family Tahoma         -size 8  -weight normal
	    TkMessageFont      -family Tahoma         -size 8  -weight normal
	    TkSmallCaptionFont -family Tahoma         -size 8  -weight bold
	    TkStatusFont       -family Tahoma         -size 8  -weight normal

These are fairly obvious. The caption font appears in the window title
bar, the icon font for desktop icons, message font for message boxes,
menu font, small caption font is for toolbox-type dialogs with very
thin title bars. Finally status font is the font used for tooltips and
status bars. All these Tk\* fonts can be changed via the Windows
Desktop properties dialog.

### Motif

	    XmNbuttonFontList		(for pushbuttons in dialogs)
	    XmNlabelFontList		(for labels)
	    XmNtextFontList		(for text entry fields)
	    XmNdefaultFontList		(for everything else)

### GNOME

Gnome or GTK\+ documentation, but the Gnome 2.2 "Font Preferences"
dialog lets you specify:

	    Application font
	    Desktop font
	    Window title font
	    Terminal font

It appears that all GTK\+ UI controls use the same "Application" font.

### KDE

KDE's font preferences dialog lists:

	    General
	    Fixed Width
	    Toolbar
	    Menu
	    Window Title
	    Taskbar

### Aqua

Aqua defines the following
<http://developer.apple.com/documentation/UserExperience/Conceptual/AquaHIGuidelines/AHIGFonts/index.html> :

	     System font
	     Emphasized system font
	     Small system font
	     Emphasized small system font
	     Application font
	     Label font
	     Mini system font

 > The system font is used for text in menus, modeless dialogs, and
   titles of document windows [...]  The small system font is used for
   informative text in alerts [...]. It is also the default font for
   headings in lists, for help tags, and for text in the small
   versions of many controls.  If your application creates text
   documents, use the application font as the default for user-created
   content.  The label font is used for labels with controls such as
   sliders and icon bevel buttons.  If necessary, the mini system font
   can be used for utility window labels and text.  Use emphasized
   system fonts sparingly.

An alternative reference <http://developer.apple.com/documentation/Carbon/Reference/Appearance_Manager/appearance_manager/constant_15.html>  lists:

	    kThemeSystemFont
	    kThemeSmallSystemFont
	    kThemeSmallEmphasizedSystemFont
	    kThemeViewsFont
	    kThemeEmphasizedSystemFont
	    kThemeApplicationFont
	    kThemeLabelFont
	    kThemeMenuTitleFont
	    kThemeMenuItemFont
	    kThemeMenuItemMarkFont
	    kThemeMenuItemCmdKeyFont
	    kThemeWindowTitleFont
	    kThemePushButtonFont
	    kThemeUtilityWindowTitleFont
	    kThemeAlertHeaderFont
	    kThemeSystemFontDetail
	    kThemeSystemFontDetailEmphasized
	    kThemeToolbarFont

# Suggested Tk Font Aliases

From all the above this TIP suggests that the following names be provided
for all platforms and where possible these map to system defined fonts.

 TkDefaultFont: the default for all GUI items not otherwise specified.

 TkFixedFont: standard fixed width font

 TkMenuFont: used for menu items

 TkCaptionFont: used for window and dialog caption bars

 TkSmallCaptionFont: used for captions on contained windows or tool
   dialogs.

 TkIconFont: font in use for icon captions

 TkTooltipFont: a font to use for tooltip windows \(transient
   information windows\)

# Implementation

<http://sf.net/tracker/?func=detail&aid=780617&group\_id=12997&atid=312997>

# Copyright

This document is placed in the public domain.

Name change from tip/146.tip to tip/146.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

TIP:            146
Title:          Add Overall Anchoring to the Grid Geometry Manager
Version:        $Revision: 1.16 $
Author:         Peter Spjuth <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        05-Aug-2003
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes to add an anchor option to grid managers to control
the behaviour of a grid where all weights are zero.

~ Rationale

Have you ever found yourself adding "-weight" to an unused row or
column in a grid?  That is usually the workaround to use when you have
no "-weight" on any column but you don't want things to sit in the
middle of the grid when the window is grown.

By adding an anchor option it lets the code directly reflect the
intention of the programmer and it makes the code more maintainable
since you can add and remove columns without having to update the
dummy weight.

~ Shrinking a Grid

When growing a grid, the behaviour is rather simple.  Follow the
weights and when 0, follow the anchor.

When shrinking a grid without weight things get more interesting.

The previous behaviour of the grid is a bit inconsistent in that when
grown it centers the slaves (as in anchor "center") and when shrunk it
shows the upper left part (as in anchor "nw").

Thus, following the new anchor will not be backwardly compatible, even
though I doubt it can be common for people to rely on that behaviour.

For shrinking a grid without weight there are three options.

 1. Always clip the bottom/right.  i.e. behave as now.

 2. Clip according to anchor.

 3. Try to shrink all columns/rows, and only clip when minsize stops
    further shrinking.  (Clip according to anchor)

I think 2. makes more sense than 1., but it does mean a minor
compatiblity breach.  Also, with 2., behaviour 1. and 3. can be emulated
but the other way around is harder.

With 2, there are also two choises how to break compatibility depending
on the default anchor.

 2. a  With default anchor ''center''.  Anyone relying on the
bottom/left clipping will find things clip all around.  Potentially an
important widget in the nw corner can end up outside.

 2. b  With default anchor ''nw''.  Anyone relying on the centering will
find things ending up in the nw corner.  Probably just a visual
difference.

I can't see that any of those two are significantly worse than the other.

Finally, the question "what would you do if backwards compatiblity was
not an aspect?" clearly answers "2b",
leading to the specification in this TIP.

~ Specification

A new subcommand ''grid anchor'' is added.  It is similar to ''grid
propagate'' in that it configures an aspect of a grid manager.

The syntax is ''grid anchor master ?value?'' where ''value'' is a
standard anchor value with ''nw'' as default.

Whenever there is extra space in the grid manager and all weights
are zero, the layout is placed within its master according to the
master's anchor value.

Whenever there is too little space in the grid manager and all weights
are zero or all columns have reached their minimumn size, the layout is
clipped according to the master's anchor value.

~ Shrink example

To clarify the shrinking options here is an example.

a: Current behaviour or, "1" with anchor "center".

b: "2" with anchor "center"

c: "2" with anchor "nw"

d: "3" with anchor "nw"

|foreach top {.a .b .c .d} {
|    toplevel $top
|    frame $top.f
|    for {set row 0} {$row < 2} {incr row} {
|        for {set col 0} {$col < 4} {incr col} {
|            set w $top.f.b${row}x$col
|            button $w -text HejHopp
|            grid $w -row $row -column $col
|        }                       
|    }                           
|}                               



|
|# Current behaviour
|pack .a.f -fill both -expand 1
|# Anchor "center" with clipping
|place .b.f -relx 0.5 -rely 0.5 -anchor center
|wm geometry .b 150x50
|# Anchor "nw" with clipping
|pack .c.f -side top -anchor w
|# Anchor "nw" with shrinking
|pack .d.f -side top -anchor w
|grid rowconfigure .d.f {0 1} -weight 1
|grid columnconfigure .d.f {0 1 2 3} -weight 1

~ Reference Implementation

Not implemented yet.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|




|











|







|
|











|








|



|









|

|
|

|
|









|











|
|
|
|
|
|
|
|
<
<
<
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|

|



|


>

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

# TIP 146: Add Overall Anchoring to the Grid Geometry Manager

	Author:         Peter Spjuth <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        05-Aug-2003
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to add an anchor option to grid managers to control
the behaviour of a grid where all weights are zero.

# Rationale

Have you ever found yourself adding "-weight" to an unused row or
column in a grid?  That is usually the workaround to use when you have
no "-weight" on any column but you don't want things to sit in the
middle of the grid when the window is grown.

By adding an anchor option it lets the code directly reflect the
intention of the programmer and it makes the code more maintainable
since you can add and remove columns without having to update the
dummy weight.

# Shrinking a Grid

When growing a grid, the behaviour is rather simple.  Follow the
weights and when 0, follow the anchor.

When shrinking a grid without weight things get more interesting.

The previous behaviour of the grid is a bit inconsistent in that when
grown it centers the slaves \(as in anchor "center"\) and when shrunk it
shows the upper left part \(as in anchor "nw"\).

Thus, following the new anchor will not be backwardly compatible, even
though I doubt it can be common for people to rely on that behaviour.

For shrinking a grid without weight there are three options.

 1. Always clip the bottom/right.  i.e. behave as now.

 2. Clip according to anchor.

 3. Try to shrink all columns/rows, and only clip when minsize stops
    further shrinking.  \(Clip according to anchor\)

I think 2. makes more sense than 1., but it does mean a minor
compatiblity breach.  Also, with 2., behaviour 1. and 3. can be emulated
but the other way around is harder.

With 2, there are also two choises how to break compatibility depending
on the default anchor.

 2. a  With default anchor _center_.  Anyone relying on the
bottom/left clipping will find things clip all around.  Potentially an
important widget in the nw corner can end up outside.

 2. b  With default anchor _nw_.  Anyone relying on the centering will
find things ending up in the nw corner.  Probably just a visual
difference.

I can't see that any of those two are significantly worse than the other.

Finally, the question "what would you do if backwards compatiblity was
not an aspect?" clearly answers "2b",
leading to the specification in this TIP.

# Specification

A new subcommand _grid anchor_ is added.  It is similar to _grid
propagate_ in that it configures an aspect of a grid manager.

The syntax is _grid anchor master ?value?_ where _value_ is a
standard anchor value with _nw_ as default.

Whenever there is extra space in the grid manager and all weights
are zero, the layout is placed within its master according to the
master's anchor value.

Whenever there is too little space in the grid manager and all weights
are zero or all columns have reached their minimumn size, the layout is
clipped according to the master's anchor value.

# Shrink example

To clarify the shrinking options here is an example.

a: Current behaviour or, "1" with anchor "center".

b: "2" with anchor "center"

c: "2" with anchor "nw"

d: "3" with anchor "nw"

	foreach top {.a .b .c .d} {
	    toplevel $top
	    frame $top.f
	    for {set row 0} {$row < 2} {incr row} {
	        for {set col 0} {$col < 4} {incr col} {
	            set w $top.f.b${row}x$col
	            button $w -text HejHopp
	            grid $w -row $row -column $col



	        }                       
	    }                           
	}                               
	
	# Current behaviour
	pack .a.f -fill both -expand 1
	# Anchor "center" with clipping
	place .b.f -relx 0.5 -rely 0.5 -anchor center
	wm geometry .b 150x50
	# Anchor "nw" with clipping
	pack .c.f -side top -anchor w
	# Anchor "nw" with shrinking
	pack .d.f -side top -anchor w
	grid rowconfigure .d.f {0 1} -weight 1
	grid columnconfigure .d.f {0 1 2 3} -weight 1

# Reference Implementation

Not implemented yet.

# Copyright

This document has been placed in the public domain.

Name change from tip/147.tip to tip/147.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

TIP:            147
Title:          Make Grid's Column/Row Configure Easier
Version:        $Revision: 1.5 $
Author:         Peter Spjuth <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        05-Aug-2003
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes to add an alternative way to state which
columns/rows in a grid are affected by an column/rowconfigure command.

~ Rationale

Usually when doing a grid layout I tend to think in terms of what I
want to do with a particular widget.  For example a canvas or a frame
that I want to expand within a resized window.  Currently I need to
translate that intention into a column and a row number to pass to
column/rowconfigure.  A more direct approach would be to pass the
widget name directly to column/rowconfigure.

Another situation is when all columns should be affected.  Here I
currently need to list them all {0 1 2 3 4 5}.  Allowing an "all"
keyword makes it easier and the code becomes more maintainable since
you can add/remove columns without updating the list.

What should be done when columnspan is greater than 1?

There are three obvious possibilities: affect all, affect the first
and affect the last.  Any of these may be wanted by a programmer at
one time or another so whatever is chosen, someone will be annoyed
with it.  Affecting all seems most logical.

See also
http://sf.net/tracker/?func=detail&aid=659218&group_id=12997&atid=362997

~ Specification

Anywhere ''column'' is used below, the same applies to ''row'' too.

In the ''index'' argument to ''grid columnconfigure'', widget names
and the keyword "all" is recognised besides the normal integers.

When a widget name is used, it must be currently managed by the given
''master''.  The columns currently occupied by the widget are affected
by the command.

When the keyword "all" is used, all columns currently occupied by
widgets in ''master'' are affected by the command.

''Note:'' "Currently occupied" means at the time of the invocation of
the ''grid columnconfigure'' command.  The grid does not try to trace
if a widget is moved in the grid or if more widgets are added.

~ Examples

|canvas .c
|scrollbar .sbx -orient horizontal
|scrollbar .sby -orient vertical
|grid .c .sby -sticky news
|grid .sbx    -sticky we
|grid columnconfigure . .c -weight 1
|grid rowconfigure    . .c -weight 1
|
|button .b1 -text a
|button .b2 -text b
|button .b3 -text example
|button .b4 -text xyzzy
|grid .b1 .b2 .b3 .b4 -sticky news
|grid columnconfigure . all -uniform a -weight 1

~ Other Possibilities

One possibility that is not proposed in this TIP is to also recognise
the end-style indexing that indices in Tcl support (through
''TclGetIntForIndex()''.)

Comment: "Personally, I think that end-index handling will be quite
tricky since it would require knowing what the *user* thinks is the
last column."

~ Reference Implementation

Not implemented yet.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|




|









|











|

|

|

|



|



|

|
|


|

|
|
|
|
|
|
|
|
|
|
|
|
|
|

|


|
|


|


|



|


>

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

# TIP 147: Make Grid's Column/Row Configure Easier

	Author:         Peter Spjuth <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        05-Aug-2003
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to add an alternative way to state which
columns/rows in a grid are affected by an column/rowconfigure command.

# Rationale

Usually when doing a grid layout I tend to think in terms of what I
want to do with a particular widget.  For example a canvas or a frame
that I want to expand within a resized window.  Currently I need to
translate that intention into a column and a row number to pass to
column/rowconfigure.  A more direct approach would be to pass the
widget name directly to column/rowconfigure.

Another situation is when all columns should be affected.  Here I
currently need to list them all \{0 1 2 3 4 5\}.  Allowing an "all"
keyword makes it easier and the code becomes more maintainable since
you can add/remove columns without updating the list.

What should be done when columnspan is greater than 1?

There are three obvious possibilities: affect all, affect the first
and affect the last.  Any of these may be wanted by a programmer at
one time or another so whatever is chosen, someone will be annoyed
with it.  Affecting all seems most logical.

See also
<http://sf.net/tracker/?func=detail&aid=659218&group\_id=12997&atid=362997>

# Specification

Anywhere _column_ is used below, the same applies to _row_ too.

In the _index_ argument to _grid columnconfigure_, widget names
and the keyword "all" is recognised besides the normal integers.

When a widget name is used, it must be currently managed by the given
_master_.  The columns currently occupied by the widget are affected
by the command.

When the keyword "all" is used, all columns currently occupied by
widgets in _master_ are affected by the command.

_Note:_ "Currently occupied" means at the time of the invocation of
the _grid columnconfigure_ command.  The grid does not try to trace
if a widget is moved in the grid or if more widgets are added.

# Examples

	canvas .c
	scrollbar .sbx -orient horizontal
	scrollbar .sby -orient vertical
	grid .c .sby -sticky news
	grid .sbx    -sticky we
	grid columnconfigure . .c -weight 1
	grid rowconfigure    . .c -weight 1
	
	button .b1 -text a
	button .b2 -text b
	button .b3 -text example
	button .b4 -text xyzzy
	grid .b1 .b2 .b3 .b4 -sticky news
	grid columnconfigure . all -uniform a -weight 1

# Other Possibilities

One possibility that is not proposed in this TIP is to also recognise
the end-style indexing that indices in Tcl support \(through
_TclGetIntForIndex\(\)_.\)

Comment: "Personally, I think that end-index handling will be quite
tricky since it would require knowing what the \*user\* thinks is the
last column."

# Reference Implementation

Not implemented yet.

# Copyright

This document has been placed in the public domain.

Name change from tip/148.tip to tip/148.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

TIP:		148
Title:		Correct [list]-Quoting of the '#' Character
Version:	$Revision: 1.5 $
Author:		Don Porter <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	08-Aug-2003
Post-History:	
Tcl-Version:	8.5


~ Abstract

This TIP proposes the correction of a long-standing bug in the
[[list]]-quoting of the ''#'' character.

~ Background

Tcl has a bug in its [[list]]-quoting function.  The bug is recorded
as Tcl Bug 489537
(http://sf.net/tracker/?func=detail&aid=489537&group_id=10894&atid=110894).

Briefly, one of the documented functions of [[list]] is quoting of
arguments so the result can be passed to [[eval]] with each list
element becoming exactly one word of the command to be evaluated.
Consider the example script:

| # FILE: demo.tcl
| set cmdName [lindex $argv 0]
| proc $cmdName {} {puts Success!}
| set command [list $cmdName]
| puts "Evaluating \[$command]..."
| eval $command

This script expects one argument on the command line, and should write
''Success!'' to stdout.  This script works correctly for most input:

| $ tclsh demo.tcl foo
| Evaluating [foo]...
| Success!
| $ tclsh demo.tcl "with space"
| Evaluating [{with space}]...
| Success!

But it fails for any argument beginning with the ''#'' character:

| $ tclsh demo.tcl #bar
| Evaluating [#bar]...

This is because, contrary to the documentation, [[list]] does not
quote the leading ''#'' in a manner to make the list safe for passing
to [[eval]].  The Tcl parser sees the unquoted ''#'' as the start of a
comment.

Starting in Tcl 8.3, optimizations for evaluation of ''pure lists''
were added, making inconsistency due to ''Tcl_ObjType'' shimmering a
new symptom of this bug.  If we adapt the example script to remove the
[[puts]] (so that a ''pure list'' is maintained):

| # FILE: demo2.tcl
| set cmdName [lindex $argv 0]
| proc $cmdName {} {puts Success!}
| set command [list $cmdName]
| eval $command

We get a script that actually works with the troublesome input:

| $ tclsh demo2.tcl #bar
| Success!

This bug in [[list]]-quoting is present in all released versions of
Tcl since and including Tcl 7.4.  It may go back further.

There is no question that Tcl's behavior disagrees with its
documentation on this point.  I believe the documentation to be
correct.  From that viewpoint, this is a bug, not requiring a TIP for
fixing.  Because the bug has been around for so long, though, it seems
prudent to make the TIP proposal, if only as fair warning to those who
might have bug-dependent scripts to fix.  The particular fix proposed
also adds a single ''#define'' to Tcl's public header file.

A large number of tests have been added to the Tcl test suite in the
HEAD, demonstrating this bug in several ways.

~ Proposal

''Tcl_ConvertCountedElement()'' is modified to have the default
behavior of quoting any leading ''#'' character in a list element.
With this default quoting, any string representation of a list
generated by Tcl will not begin with the ''#'' character, so cannot be
mis-parsed as a comment.

''Tcl_ConvertCountedElement()'' is also modified to recognize a new
bit flag value in its ''flags'' argument, ''TCL_DONT_QUOTE_HASH'',
which is defined in Tcl's public header file so that it may be used by
extensions.  When the ''TCL_DONT_QUOTE_HASH'' bit is set in the
''flags'' argument, ''Tcl_ConvertCountedElement()'' will not quote the
leading ''#'' character.  Quoting of the leading ''#'' character is
only necessary for the first element of a list.  Those callers of
''Tcl_ConvertCountedElement()'' that can be sure they are not
generating the first element of a list can pass in the
''TCL_DONT_QUOTE_HASH'' bit to produce the simplest quoting required.
The behavior of the ''TCL_DONT_QUOTE_HASH'' bit flag is added to the
documentation.  The ''Tcl_ConvertElement()'' routine is similarly
modified (trivially, since it is just a wrapper).

All callers of ''Tcl_ConvertCountedElement()'' in the Tcl source code
are modified to use the ''TCL_DONT_QUOTE_HASH'' flag as appropriate,
so that Tcl continues to generate as simple string representations of
lists as possible that do not suffer from Bug 489537.

~ Prototype

A patch implementing this proposal is attached to Tcl Bug 489537 at
SourceForge.

~ Compatibility

After acceptance of this patch, the string representation of some
lists will change, though as little as possible while still fixing the
bug.  Scripts that perform string comparisons on lists may see
different results.  Notably, a test in a test suite that has a test
body that generates a list, and then has an expected result as a
string may see new test failures.  The minimal quoting changes should
keep this incompatibility to a minimum, but it may happen.

Notably there are no such compatibility problems in either the Tcl or
Tk test suites.  Any such incompatibility in other test suites can be
easily remedied by using [[list]] to generate the expected result.

~ Scope

It has been observed by some Tcl users that [[list]] is used for two
conceptually distinct purposes.  First, adding quoting to list
elements as required, so that element boundaries can be re-discovered
from the string representation.  Second, adding quoting so that the
string representation can be passed to [[eval]] with the original
element boundaries becoming the argument boundaries in the evaluation.
One can imagine a Tcl where these two functions were separated.
However, this TIP does not propose such a separation, and further
arguments on that point are out of scope, and should be considered in
another TIP, if at all.

~ Acknowledgements

The author acknowledges the discovery of this bug by Joe English,
analysis by Donal Fellows, and a first draft patch from Miguel Sofer.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|

|

|

|

|
|



|
|
|
|
|
|


|

|
|
|
|
|
|

|

|
|

|
|
|


|
|

|

|
|
|
|
|



|
|

|








|




|

|
|

|


|
|

|
|
|

|

|
|
|
|

|
|



|




|











|

|

|



|






|




|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

# TIP 148: Correct [list]-Quoting of the '#' Character

	Author:		Don Porter <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	08-Aug-2003
	Post-History:	
	Tcl-Version:	8.5
-----

# Abstract

This TIP proposes the correction of a long-standing bug in the
[list]-quoting of the _\#_ character.

# Background

Tcl has a bug in its [list]-quoting function.  The bug is recorded
as Tcl Bug 489537
\(<http://sf.net/tracker/?func=detail&aid=489537&group\_id=10894&atid=110894\).>

Briefly, one of the documented functions of [list] is quoting of
arguments so the result can be passed to [eval] with each list
element becoming exactly one word of the command to be evaluated.
Consider the example script:

	 # FILE: demo.tcl
	 set cmdName [lindex $argv 0]
	 proc $cmdName {} {puts Success!}
	 set command [list $cmdName]
	 puts "Evaluating \[$command]..."
	 eval $command

This script expects one argument on the command line, and should write
_Success!_ to stdout.  This script works correctly for most input:

	 $ tclsh demo.tcl foo
	 Evaluating [foo]...
	 Success!
	 $ tclsh demo.tcl "with space"
	 Evaluating [{with space}]...
	 Success!

But it fails for any argument beginning with the _\#_ character:

	 $ tclsh demo.tcl #bar
	 Evaluating [#bar]...

This is because, contrary to the documentation, [list] does not
quote the leading _\#_ in a manner to make the list safe for passing
to [eval].  The Tcl parser sees the unquoted _\#_ as the start of a
comment.

Starting in Tcl 8.3, optimizations for evaluation of _pure lists_
were added, making inconsistency due to _Tcl\_ObjType_ shimmering a
new symptom of this bug.  If we adapt the example script to remove the
[puts] \(so that a _pure list_ is maintained\):

	 # FILE: demo2.tcl
	 set cmdName [lindex $argv 0]
	 proc $cmdName {} {puts Success!}
	 set command [list $cmdName]
	 eval $command

We get a script that actually works with the troublesome input:

	 $ tclsh demo2.tcl #bar
	 Success!

This bug in [list]-quoting is present in all released versions of
Tcl since and including Tcl 7.4.  It may go back further.

There is no question that Tcl's behavior disagrees with its
documentation on this point.  I believe the documentation to be
correct.  From that viewpoint, this is a bug, not requiring a TIP for
fixing.  Because the bug has been around for so long, though, it seems
prudent to make the TIP proposal, if only as fair warning to those who
might have bug-dependent scripts to fix.  The particular fix proposed
also adds a single _\#define_ to Tcl's public header file.

A large number of tests have been added to the Tcl test suite in the
HEAD, demonstrating this bug in several ways.

# Proposal

_Tcl\_ConvertCountedElement\(\)_ is modified to have the default
behavior of quoting any leading _\#_ character in a list element.
With this default quoting, any string representation of a list
generated by Tcl will not begin with the _\#_ character, so cannot be
mis-parsed as a comment.

_Tcl\_ConvertCountedElement\(\)_ is also modified to recognize a new
bit flag value in its _flags_ argument, _TCL\_DONT\_QUOTE\_HASH_,
which is defined in Tcl's public header file so that it may be used by
extensions.  When the _TCL\_DONT\_QUOTE\_HASH_ bit is set in the
_flags_ argument, _Tcl\_ConvertCountedElement\(\)_ will not quote the
leading _\#_ character.  Quoting of the leading _\#_ character is
only necessary for the first element of a list.  Those callers of
_Tcl\_ConvertCountedElement\(\)_ that can be sure they are not
generating the first element of a list can pass in the
_TCL\_DONT\_QUOTE\_HASH_ bit to produce the simplest quoting required.
The behavior of the _TCL\_DONT\_QUOTE\_HASH_ bit flag is added to the
documentation.  The _Tcl\_ConvertElement\(\)_ routine is similarly
modified \(trivially, since it is just a wrapper\).

All callers of _Tcl\_ConvertCountedElement\(\)_ in the Tcl source code
are modified to use the _TCL\_DONT\_QUOTE\_HASH_ flag as appropriate,
so that Tcl continues to generate as simple string representations of
lists as possible that do not suffer from Bug 489537.

# Prototype

A patch implementing this proposal is attached to Tcl Bug 489537 at
SourceForge.

# Compatibility

After acceptance of this patch, the string representation of some
lists will change, though as little as possible while still fixing the
bug.  Scripts that perform string comparisons on lists may see
different results.  Notably, a test in a test suite that has a test
body that generates a list, and then has an expected result as a
string may see new test failures.  The minimal quoting changes should
keep this incompatibility to a minimum, but it may happen.

Notably there are no such compatibility problems in either the Tcl or
Tk test suites.  Any such incompatibility in other test suites can be
easily remedied by using [list] to generate the expected result.

# Scope

It has been observed by some Tcl users that [list] is used for two
conceptually distinct purposes.  First, adding quoting to list
elements as required, so that element boundaries can be re-discovered
from the string representation.  Second, adding quoting so that the
string representation can be passed to [eval] with the original
element boundaries becoming the argument boundaries in the evaluation.
One can imagine a Tcl where these two functions were separated.
However, this TIP does not propose such a separation, and further
arguments on that point are out of scope, and should be considered in
another TIP, if at all.

# Acknowledgements

The author acknowledges the discovery of this bug by Joe English,
analysis by Donal Fellows, and a first draft patch from Miguel Sofer.

# Copyright

This document has been placed in the public domain.

Name change from tip/149.tip to tip/149.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

TIP:		149
Title:		Allow "enabled" as Synonym for "normal" in -state Option
Author:		Michael A. Cleverly <[email protected]>
State:		Withdrawn
Type:		Project
Vote:		Pending
Created:	13-Aug-2003
Tcl-Version:	8.5
Version:	$Revision: 1.2 $
Post-History:	


~ Abstract

This TIP allows Tk widgets which have a configurable ''-state'' option
to accept ''enabled'' as a synonym for ''normal''.

~ Rationale

Tk widgets which have a configurable ''-state'' option have (at a
minimum) ''normal'' and ''disabled'' states.  In common usage,
however, the antonym of ''disabled'' is ''enabled'', not ''normal''.

Even experienced Tcl/Tk programmers sometimes forget, though they
usually won't come out and admit it explicitly.  (Cf.
http://groups.google.com/groups?th=66e286d7efc3bbb6)

~ Proposed Changes

Modify all Tk widgets which have a configurable ''-state'' option to
accept ''enabled'' as a synonym for ''normal''.  The value returned by
a widget's ''cget'' method would continue to be ''normal''.  The
appropriate man pages and test suite will be updated to document and
test the use of ''enabled'' as a synonym.

|% $w configure -state enabled
|% puts [$w cget -state]
|normal

~ Implementation

A reference implementation will be provided shortly.

~ Copyright

This document is placed in the public domain.

<
|
|
|
|
|
|
|
<
|
>

|

|
|

|

|
|
|


|
|

|

|
|
|

|

|
|
|

|



|


>

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

# TIP 149: Allow "enabled" as Synonym for "normal" in -state Option
	Author:		Michael A. Cleverly <[email protected]>
	State:		Withdrawn
	Type:		Project
	Vote:		Pending
	Created:	13-Aug-2003
	Tcl-Version:	8.5

	Post-History:	
-----

# Abstract

This TIP allows Tk widgets which have a configurable _-state_ option
to accept _enabled_ as a synonym for _normal_.

# Rationale

Tk widgets which have a configurable _-state_ option have \(at a
minimum\) _normal_ and _disabled_ states.  In common usage,
however, the antonym of _disabled_ is _enabled_, not _normal_.

Even experienced Tcl/Tk programmers sometimes forget, though they
usually won't come out and admit it explicitly.  \(Cf.
<http://groups.google.com/groups?th=66e286d7efc3bbb6\)>

# Proposed Changes

Modify all Tk widgets which have a configurable _-state_ option to
accept _enabled_ as a synonym for _normal_.  The value returned by
a widget's _cget_ method would continue to be _normal_.  The
appropriate man pages and test suite will be updated to document and
test the use of _enabled_ as a synonym.

	% $w configure -state enabled
	% puts [$w cget -state]
	normal

# Implementation

A reference implementation will be provided shortly.

# Copyright

This document is placed in the public domain.

Name change from tip/15.tip to tip/15.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

TIP:            15
Title:          Functions to List and Detail Math Functions
Version:        $Revision: 1.8 $
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        22-Nov-2000
Post-History:   
Keywords:       Tcl,expr,function,introspection
Tcl-Version:    8.4.0


~ Abstract

Provides a way for the list of all math functions defined in the
current interpreter to be discovered, and for discovering what
arguments might be passed to an existing math function.  This may be
useful in tests as well as more general use.

~ Rationale

Although it is quite easy to define a new function for use in
expressions, there is no public way of performing introspection on
this information.  Having a way to extract the arguments from an
existing math function was requested by
http://sourceforge.net/bugs/?func=detailbug&bug_id=119304&group_id=10894
and once you have one, it becomes trivial to also ask for a second
function to list what functions are defined.

I propose the creation of two functions that fulfil this r�le;
''Tcl_GetMathFuncInfo'' and ''Tcl_ListMathFuncs''.  These functions
will be documented on the same manual page as ''Tcl_CreateMathFunc''
and implemented in the same file.

Furthermore, I also propose that the ''info'' command in the Tcl
interpreter be extended to include a new subcommand, ''functions'',
which will allow Tcl scripts to discover the list of installed
functions (by acting as a thin veneer over ''Tcl_ListMathFuncs''.)
Note that this is an extension of the ''info'' command because it
allows for introspection of a system that affects the behaviour of
several commands that form the core part of the command-set: ''expr'',
''for'', ''if'' and ''while''.

~ Tcl_GetMathFuncInfo

This function will take an interpreter reference, a function name (as
a string) and pointers to variables capable of taking each of the last
four arguments to ''Tcl_CreateMathFunc'', and will return a standard
Tcl result (either ''TCL_OK'' or ''TCL_ERROR'', depending on whether a
function with the given name exists within the given interpreter, with
an error message being left in the interpreter's result in the
''TCL_ERROR'' case.)  The array of argument types whose reference is
placed into the variable pointed to by ''argTypesPtr'' will be
allocated by Tcl, and should be freed with ''Tcl_Free''.

|int Tcl_GetMathFuncInfo(Tcl_Interp *interp, CONST char *name,
|                        int *numArgsPtr, Tcl_ValueType **argTypesPtr,
|                        Tcl_MathProc **procPtr,
|                        ClientData *clientDataPtr);

The parameter names are chosen by analogy with ''Tcl_CreateMathFunc''.

In the case where a math function is defined internally by the bytecode
engine and has no standard implementation (all the builtin functions in
8.4a2 are like this) the value placed in the variable indicated by the
''procPtr'' argument will be NULL.

~ Tcl_ListMathFuncs

This function will take an interpreter reference and an optional
string that describes a glob-like pattern that restricts the set of
math functions that the caller is interested in receiving (with a
''NULL'' indicating that no filtering is desired.)  The function will
return a pointer to a newly-allocated ''Tcl_Obj'' list of the names of
all the math functions defined within that interpreter, or ''NULL'' in
the case of an error (in which case a suitable message will be left in
the interpreter.)  The list will not be required to be sorted.

|Tcl_Obj *Tcl_ListMathFuncs(Tcl_Interp *interp, CONST char *pattern);

The alternative is to pass in the addresses of variables that will be
updated to contain the number of functions and an array of function
names.  But I prefer the ''Tcl_Obj'' approach as it is expressing the
fact that the list of function names is really a single thing being
returned (albeit one that is not a simple value.)  It is not
anticipated that the performance of this function will need to be
crucial to too many applications.

~ info functions

This new subcommand will provide access from Tcl scripts to the
functionality of ''Tcl_ListMathFuncs''.  It will take a single optional
argument consisting of a pattern to pass on as the ''pattern'' argument
(with the absence of the argument indicating that NULL is to be passed
instead.)

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|






|





|



|
|
|


|
|

|
|

|
|

|

|
|
|
|


|
|
|

|
|
|
|

|


|
|
|

|



|
|
|
|
|
|

|



|

|



|


|
|
|
|

|


>

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

# TIP 15: Functions to List and Detail Math Functions

	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        22-Nov-2000
	Post-History:   
	Keywords:       Tcl,expr,function,introspection
	Tcl-Version:    8.4.0
-----

# Abstract

Provides a way for the list of all math functions defined in the
current interpreter to be discovered, and for discovering what
arguments might be passed to an existing math function.  This may be
useful in tests as well as more general use.

# Rationale

Although it is quite easy to define a new function for use in
expressions, there is no public way of performing introspection on
this information.  Having a way to extract the arguments from an
existing math function was requested by
<http://sourceforge.net/bugs/?func=detailbug&bug\_id=119304&group\_id=10894>
and once you have one, it becomes trivial to also ask for a second
function to list what functions are defined.

I propose the creation of two functions that fulfil this rôle;
_Tcl\_GetMathFuncInfo_ and _Tcl\_ListMathFuncs_.  These functions
will be documented on the same manual page as _Tcl\_CreateMathFunc_
and implemented in the same file.

Furthermore, I also propose that the _info_ command in the Tcl
interpreter be extended to include a new subcommand, _functions_,
which will allow Tcl scripts to discover the list of installed
functions \(by acting as a thin veneer over _Tcl\_ListMathFuncs_.\)
Note that this is an extension of the _info_ command because it
allows for introspection of a system that affects the behaviour of
several commands that form the core part of the command-set: _expr_,
_for_, _if_ and _while_.

# Tcl\_GetMathFuncInfo

This function will take an interpreter reference, a function name \(as
a string\) and pointers to variables capable of taking each of the last
four arguments to _Tcl\_CreateMathFunc_, and will return a standard
Tcl result \(either _TCL\_OK_ or _TCL\_ERROR_, depending on whether a
function with the given name exists within the given interpreter, with
an error message being left in the interpreter's result in the
_TCL\_ERROR_ case.\)  The array of argument types whose reference is
placed into the variable pointed to by _argTypesPtr_ will be
allocated by Tcl, and should be freed with _Tcl\_Free_.

	int Tcl_GetMathFuncInfo(Tcl_Interp *interp, CONST char *name,
	                        int *numArgsPtr, Tcl_ValueType **argTypesPtr,
	                        Tcl_MathProc **procPtr,
	                        ClientData *clientDataPtr);

The parameter names are chosen by analogy with _Tcl\_CreateMathFunc_.

In the case where a math function is defined internally by the bytecode
engine and has no standard implementation \(all the builtin functions in
8.4a2 are like this\) the value placed in the variable indicated by the
_procPtr_ argument will be NULL.

# Tcl\_ListMathFuncs

This function will take an interpreter reference and an optional
string that describes a glob-like pattern that restricts the set of
math functions that the caller is interested in receiving \(with a
_NULL_ indicating that no filtering is desired.\)  The function will
return a pointer to a newly-allocated _Tcl\_Obj_ list of the names of
all the math functions defined within that interpreter, or _NULL_ in
the case of an error \(in which case a suitable message will be left in
the interpreter.\)  The list will not be required to be sorted.

	Tcl_Obj *Tcl_ListMathFuncs(Tcl_Interp *interp, CONST char *pattern);

The alternative is to pass in the addresses of variables that will be
updated to contain the number of functions and an array of function
names.  But I prefer the _Tcl\_Obj_ approach as it is expressing the
fact that the list of function names is really a single thing being
returned \(albeit one that is not a simple value.\)  It is not
anticipated that the performance of this function will need to be
crucial to too many applications.

# info functions

This new subcommand will provide access from Tcl scripts to the
functionality of _Tcl\_ListMathFuncs_.  It will take a single optional
argument consisting of a pattern to pass on as the _pattern_ argument
\(with the absence of the argument indicating that NULL is to be passed
instead.\)

# Copyright

This document is placed in the public domain.

Name change from tip/150.tip to tip/150.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

TIP:		150
Title:          Implement the Tk send Command for Windows
Author:         Pat Thoyts <[email protected]>
Type:           Project
State:		Deferred
Vote:		Done
Tcl-Version:    8.5
Version:	$Revision: 1.6 $
Keywords:       tk, send
Created:        25-Jul-2003
Post-History:	


~ Abstract

This TIP proposes to provide an implementation of the send mechanism
for Tk under Windows.

~ Rationale

The Tk send command is used to provide an X server based mechanism for
transmitting information between Tk applications. This provides the
basis for remote introspection (tkinspect) and remote control (tkcon).
This subsystem has never been implemented under Windows although there
are means to emulate this using Tcl's dde package or the comm library.
By providing a win32 implementation we help to standardise the Tk
command set across platforms and will make it simpler to use this
feature from Perl/Tk and Python Tkinter.

~ Reference Implementation

This implementation is based upon an integrated version of the winsend
package currently at http://tclsoap.sf.net/winsend/. This uses the
Windows Running Object Table to maintain interpreter registration
information. This is a global system COM object that is provided as
part of the Windows COM automation framework. Its purpose is to
provide a single registry for maintaining references to active COM
components.

When ''tk appname'' is called a COM component is created which
contains a reference to the Tcl interpreter. This is then registered
with the Running Object Table with the registration name containing
the Tk app-name. To find available interpreters we use the ''winfo
interps'' command. This iterates over all the registered objects
looking for Tk registered names and can then return a list of
registered interpreters.

The Tk ''send'' command is then provided as a COM method call. To
perform a send, the client interpreter (or indeed any automation
capable COM client) obtains the interpreter reference from the running
object table and calls the ''Send'' method on this object, passing in
the command as a string. For the synchronous version this is
sufficient.  The result is returned using the standard COM method
calling and error information can be returned the same way.

Support for the asynchronous send is currently underway but will be
modelled closely on the X-based asynchronous send.

There are some advantages in using COM over DDE for the transport
mechanism.  DDEML has a tendency to use broadcast window messages.  If
there are any toplevel windows that are not processing their message
queues, then DDE gets hung.  While a fix has been applied to the Tcl
dde package, there remain problems.  In contrast the COM-based system
never broadcasts. We initiate a conversation with the Running Object
Table first and then with the specific application requested.  If this
application fails to process its message queue then we will get stuck
- but no other poorly behaved application can affect our
communication.

A second advantage is than non-Tcl automation capable clients can also
call our method.  This means that Windows Scripting code (vbscript or
jscript) can make use of the send command.

Finally, given a suitable DCOM environment it should also be possible
to implement the -displayof feature via Distributed COM. However, I
don't see much call for this - network sockets are a lot simpler to
use than DCOM.

~ Copyright

This document is placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|




|



|






|


|






|


|
|



|
|
|
|



















|
|






|


>

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

# TIP 150: Implement the Tk send Command for Windows
	Author:         Pat Thoyts <[email protected]>
	Type:           Project
	State:		Deferred
	Vote:		Done
	Tcl-Version:    8.5

	Keywords:       tk, send
	Created:        25-Jul-2003
	Post-History:	
-----

# Abstract

This TIP proposes to provide an implementation of the send mechanism
for Tk under Windows.

# Rationale

The Tk send command is used to provide an X server based mechanism for
transmitting information between Tk applications. This provides the
basis for remote introspection \(tkinspect\) and remote control \(tkcon\).
This subsystem has never been implemented under Windows although there
are means to emulate this using Tcl's dde package or the comm library.
By providing a win32 implementation we help to standardise the Tk
command set across platforms and will make it simpler to use this
feature from Perl/Tk and Python Tkinter.

# Reference Implementation

This implementation is based upon an integrated version of the winsend
package currently at <http://tclsoap.sf.net/winsend/.> This uses the
Windows Running Object Table to maintain interpreter registration
information. This is a global system COM object that is provided as
part of the Windows COM automation framework. Its purpose is to
provide a single registry for maintaining references to active COM
components.

When _tk appname_ is called a COM component is created which
contains a reference to the Tcl interpreter. This is then registered
with the Running Object Table with the registration name containing
the Tk app-name. To find available interpreters we use the _winfo
interps_ command. This iterates over all the registered objects
looking for Tk registered names and can then return a list of
registered interpreters.

The Tk _send_ command is then provided as a COM method call. To
perform a send, the client interpreter \(or indeed any automation
capable COM client\) obtains the interpreter reference from the running
object table and calls the _Send_ method on this object, passing in
the command as a string. For the synchronous version this is
sufficient.  The result is returned using the standard COM method
calling and error information can be returned the same way.

Support for the asynchronous send is currently underway but will be
modelled closely on the X-based asynchronous send.

There are some advantages in using COM over DDE for the transport
mechanism.  DDEML has a tendency to use broadcast window messages.  If
there are any toplevel windows that are not processing their message
queues, then DDE gets hung.  While a fix has been applied to the Tcl
dde package, there remain problems.  In contrast the COM-based system
never broadcasts. We initiate a conversation with the Running Object
Table first and then with the specific application requested.  If this
application fails to process its message queue then we will get stuck
- but no other poorly behaved application can affect our
communication.

A second advantage is than non-Tcl automation capable clients can also
call our method.  This means that Windows Scripting code \(vbscript or
jscript\) can make use of the send command.

Finally, given a suitable DCOM environment it should also be possible
to implement the -displayof feature via Distributed COM. However, I
don't see much call for this - network sockets are a lot simpler to
use than DCOM.

# Copyright

This document is placed in the public domain.

Name change from tip/151.tip to tip/151.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

TIP:            151
Title:          Remove -e: Command Line Option from tclsh and wish
Version:        $Revision: 1.7 $
Author:         Don Porter <[email protected]>
Author:         Don Porter <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        22-Aug-2003
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes removal of the -e: command line option to
tclsh and wish that was Accepted as part of [137].

~ Background

[137] was Accepted today.  However, there were a few NO votes
objecting to the new ''-e:'' form of the ''-encoding'' command
line option for specifying the encoding of a startup script to tclsh
and wish.  Those voting NO only objected to that part of [137]
while supporting the rest as a solid proposal that will improve
Tcl.  Among those voting YES, no one explicitly embraced the
''-e:'' command line option as something they required.  Some
voting YES opined that the ''-e:'' option was a wart that
could be fixed later.

Based on those comments, [137] would have been better had the
''-e:'' form of the command line option not been part of the
proposal.  This TIP proposes nothing more than removing
Acceptance of the ''-e:'' form of the ''-encoding'' command
line option.

Without the controversial ''-e:'' proposal, I believe [137]
would have had unanimous approval.

~ Rationale

The use of ''-e:'' as a command line option to tclsh or wish
suffers when compared with the perl program.  The ''perl -e''
option for evaluation of a Perl script provided on the command
line is very well known, and it's a mistake to add something
to tclsh that looks similar, but is in fact very different.

[137] proposed both ''-encoding'' and the ''-e:'' form.  There's
really no need to add multiple ways to do the same thing.

The Rationale in [137] for the ''-e:'' form is solely to support
the 32-character limit in some Unices for their ''#!'' lines.
However, the ''-e:'' form does not really solve that problem.
For example:

| #!/usr/local/bin/tclsh8.5 -e:iso8859-15 
| 12345678901234567890123456789012

Here we see that we still run afoul of the 32-character limit
when tclsh is installed in the default location.  Even longer
encoding names exist which magnify the problem, and altering the
installation location will not necessarily help:

| #!/usr/bin/tclsh8.5 -e:iso8859-15 
| 12345678901234567890123456789012

(This is actually an insidious failure mode in that it leads to the
script being sourced with a valid but incorrect encoding.)

Conversely, we already have an effective general workaround
for the 32-character limit problem:

| #!/bin/sh
| # \
| exec tclsh -encoding iso8859-15 "$0" ${1+"$@"}

So, ''-e:'' doesn't solve a problem we don't really have, and
it's controverisal.  We should remove it.

~ Proposal

Remove (Acceptance of) the ''-e:'' set of command line options
to the programs ''tclsh'' and ''wish''.

~ Compatibility

Since no version of Tcl or Tk has been released supporting
the ''-e:'' command line option, there are no compatibility
issues to resolve.

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|


|

|

|
|

|


|
|


|
|

|


|


|

|
|




|


|
|
|


|
|






|
|

|
|




|
|
|

|


|

|
|

|


|


|


>

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

# TIP 151: Remove -e: Command Line Option from tclsh and wish

	Author:         Don Porter <[email protected]>
	Author:         Don Porter <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        22-Aug-2003
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes removal of the -e: command line option to
tclsh and wish that was Accepted as part of [[137]](137.md).

# Background

[[137]](137.md) was Accepted today.  However, there were a few NO votes
objecting to the new _-e:_ form of the _-encoding_ command
line option for specifying the encoding of a startup script to tclsh
and wish.  Those voting NO only objected to that part of [[137]](137.md)
while supporting the rest as a solid proposal that will improve
Tcl.  Among those voting YES, no one explicitly embraced the
_-e:_ command line option as something they required.  Some
voting YES opined that the _-e:_ option was a wart that
could be fixed later.

Based on those comments, [[137]](137.md) would have been better had the
_-e:_ form of the command line option not been part of the
proposal.  This TIP proposes nothing more than removing
Acceptance of the _-e:_ form of the _-encoding_ command
line option.

Without the controversial _-e:_ proposal, I believe [[137]](137.md)
would have had unanimous approval.

# Rationale

The use of _-e:_ as a command line option to tclsh or wish
suffers when compared with the perl program.  The _perl -e_
option for evaluation of a Perl script provided on the command
line is very well known, and it's a mistake to add something
to tclsh that looks similar, but is in fact very different.

[[137]](137.md) proposed both _-encoding_ and the _-e:_ form.  There's
really no need to add multiple ways to do the same thing.

The Rationale in [[137]](137.md) for the _-e:_ form is solely to support
the 32-character limit in some Unices for their _\#!_ lines.
However, the _-e:_ form does not really solve that problem.
For example:

	 #!/usr/local/bin/tclsh8.5 -e:iso8859-15 
	 12345678901234567890123456789012

Here we see that we still run afoul of the 32-character limit
when tclsh is installed in the default location.  Even longer
encoding names exist which magnify the problem, and altering the
installation location will not necessarily help:

	 #!/usr/bin/tclsh8.5 -e:iso8859-15 
	 12345678901234567890123456789012

\(This is actually an insidious failure mode in that it leads to the
script being sourced with a valid but incorrect encoding.\)

Conversely, we already have an effective general workaround
for the 32-character limit problem:

	 #!/bin/sh
	 # \
	 exec tclsh -encoding iso8859-15 "$0" ${1+"$@"}

So, _-e:_ doesn't solve a problem we don't really have, and
it's controverisal.  We should remove it.

# Proposal

Remove \(Acceptance of\) the _-e:_ set of command line options
to the programs _tclsh_ and _wish_.

# Compatibility

Since no version of Tcl or Tk has been released supporting
the _-e:_ command line option, there are no compatibility
issues to resolve.

# Copyright

This document is placed in the public domain.

Name change from tip/152.tip to tip/152.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

TIP:		152
Title:		New -detail Option for tk_messageBox
Version:	$Revision: 1.7 $
Author:		Mats Bengtsson <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Created: 	26-Aug-2003
Obsoletes:	25
Post-History:	
Keywords:	Tk


~ Abstract

This TIP proposes a new option for the '''tk_messageBox''' for text
that is less significant than the '''-message''' text.

~ Rationale

Several platforms have a native feature of alert dialogs that includes
messages with both a bold or large font, and a text in fine print,
which gives more detail to the actual message.  Both Mac OS 8/9 and
Mac OS X include such a feature.  This TIP suggests that this should
be intruduced on all platforms, with the text to be displayed in that
format specified using a new option '''-detail'''.  In those cases where
it is not straightforward to distinguish between the '''-message''' and
'''-detail''' option contents, they should be combined into a single piece
of text in a way that makes sense on the platform.

~ Reference Implementation

The proposed change is now implemented as a loadable extension (in C)
on Mac OS X
[http://hem.fyristorg.com/matben/download/MovableAlerts.dmg].

The following images show the present (8.4.4) message box on AquaTk,
and the proposed one.

#image:152before	This is the present tk_messageBox.

#image:152after		This is the native tk_messageBox.

~ Copyright

This document has been placed in the public domain

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|
|

|






|
|
|


|

|

|

|


|

|

|


>

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

# TIP 152: New -detail Option for tk_messageBox

	Author:		Mats Bengtsson <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Created: 	26-Aug-2003
	Obsoletes:	25
	Post-History:	
	Keywords:	Tk
-----

# Abstract

This TIP proposes a new option for the **tk\_messageBox** for text
that is less significant than the **-message** text.

# Rationale

Several platforms have a native feature of alert dialogs that includes
messages with both a bold or large font, and a text in fine print,
which gives more detail to the actual message.  Both Mac OS 8/9 and
Mac OS X include such a feature.  This TIP suggests that this should
be intruduced on all platforms, with the text to be displayed in that
format specified using a new option **-detail**.  In those cases where
it is not straightforward to distinguish between the **-message** and
**-detail** option contents, they should be combined into a single piece
of text in a way that makes sense on the platform.

# Reference Implementation

The proposed change is now implemented as a loadable extension \(in C\)
on Mac OS X
<http://hem.fyristorg.com/matben/download/MovableAlerts.dmg> .

The following images show the present \(8.4.4\) message box on AquaTk,
and the proposed one.

![This is the present tk_messageBox.](../assets/152before.gif)

![{} This is the native tk_messageBox.](../assets/152after.gif)

# Copyright

This document has been placed in the public domain

Name change from tip/153.tip to tip/153.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

TIP:            153
Title:          Enhancing the [winfo toplevel] Command
Version:        $Revision: 1.8 $
Author:         Neil McKay <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        26-Aug-2003
Post-History:   
Tcl-Version:    8.5


~ Abstract

The [[winfo toplevel]] command returns the Tk toplevel window that
encloses the window that's passed as an argument.  However, Tk
extensions may allow the creation of windows which reside at the top
of a window hierarchy, but are not Tk toplevel widgets.  If a
subwindow of one of these top-of-hierarchy widgets is passed to
[[winfo toplevel]], it returns an empty string, making it impossible
to determine what hierarchy the window resides in.  This TIP proposes
enhancing the [[winfo toplevel]] command so that it will return the top
window in the hierarchy regardless of what type of widget it is.

~Rationale

Focus control does not work properly for top-of-hierarchy Tk windows
other than toplevel widgets.  This is an artifact of Tk's inability to
determine the top of a window hierarchy for such windows.  Prior to Tk
8.4, top-of-hierarchy windows other than toplevels were not possible,
so the changes proposed in this TIP would be moot.  However, they are
now possible due to the incorporation into the Tk core of the changes
proposed in [47].

As an example, consider the rootwin extension
[http://www.eecs.umich.edu/~mckay/computer/rootwin0.4.tar.gz].
This extension adds a [[rootwin]] widget creation command,
which turns an X display's root window into a Tk widget. The rootwin
widget is a top-of-hierarchy widget, but is not an ordinary Tk toplevel.
The command sequence

| rootwin .r
| entry .r.e
| place .r.e -x 100 -y 100

will create an entry widget near the upper left corner of the screen.
However, it is impossible to type anything into the entry widget,
because Tk's focus code does not work properly with rootwin widgets.
The problem can be traced back to the fact that the command
[[winfo toplevel .r.e]] returns the empty string. With the proposed
extension, this command would return ".r", and the focus code
would work properly.

~Compatibility

The proposed behavior for [[winfo toplevel]] is different from the
current behavior, although only in the presence of Tk extensions
that create top-of-hierarchy widgets that are not toplevels.
The rootwin package is the only such extension known to this TIP's
author, so the difference in behavior is unlikely to be noticed
by anyone else. It should also be noted that the behavior
(prior to this TIP) of [[winfo toplevel]] for
top-of-hierarchy widgets that are not toplevels is not specified,
so relying on its current behavior in such cicumstances is
a questionable practice.

~Implementation

The core of the proposed change to [[winfo toplevel]] requires
only a single-line change in file ''generic/tkWindow.c''; however, the patch
described below also changes the name of a function and changes
some comments, to better describe the code's behavior. It also
documents the new behavior in the [[winfo]] man page.

~Patches

A patch (against Tk 8.4.5) that implements the changes described above
may be found at
http://www.eecs.umich.edu/~mckay/computer/winfotop.patch

~Copyright

This document is in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|




|

|


|







|


|
|




|
|
|





|



|

|





|




|

|
|


|

|

|

|

|


>

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

# TIP 153: Enhancing the [winfo toplevel] Command

	Author:         Neil McKay <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        26-Aug-2003
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

The [winfo toplevel] command returns the Tk toplevel window that
encloses the window that's passed as an argument.  However, Tk
extensions may allow the creation of windows which reside at the top
of a window hierarchy, but are not Tk toplevel widgets.  If a
subwindow of one of these top-of-hierarchy widgets is passed to
[winfo toplevel], it returns an empty string, making it impossible
to determine what hierarchy the window resides in.  This TIP proposes
enhancing the [winfo toplevel] command so that it will return the top
window in the hierarchy regardless of what type of widget it is.

# Rationale

Focus control does not work properly for top-of-hierarchy Tk windows
other than toplevel widgets.  This is an artifact of Tk's inability to
determine the top of a window hierarchy for such windows.  Prior to Tk
8.4, top-of-hierarchy windows other than toplevels were not possible,
so the changes proposed in this TIP would be moot.  However, they are
now possible due to the incorporation into the Tk core of the changes
proposed in [[47]](47.md).

As an example, consider the rootwin extension
<http://www.eecs.umich.edu/~mckay/computer/rootwin0.4.tar.gz> .
This extension adds a [rootwin] widget creation command,
which turns an X display's root window into a Tk widget. The rootwin
widget is a top-of-hierarchy widget, but is not an ordinary Tk toplevel.
The command sequence

	 rootwin .r
	 entry .r.e
	 place .r.e -x 100 -y 100

will create an entry widget near the upper left corner of the screen.
However, it is impossible to type anything into the entry widget,
because Tk's focus code does not work properly with rootwin widgets.
The problem can be traced back to the fact that the command
[winfo toplevel .r.e] returns the empty string. With the proposed
extension, this command would return ".r", and the focus code
would work properly.

# Compatibility

The proposed behavior for [winfo toplevel] is different from the
current behavior, although only in the presence of Tk extensions
that create top-of-hierarchy widgets that are not toplevels.
The rootwin package is the only such extension known to this TIP's
author, so the difference in behavior is unlikely to be noticed
by anyone else. It should also be noted that the behavior
\(prior to this TIP\) of [winfo toplevel] for
top-of-hierarchy widgets that are not toplevels is not specified,
so relying on its current behavior in such cicumstances is
a questionable practice.

# Implementation

The core of the proposed change to [winfo toplevel] requires
only a single-line change in file _generic/tkWindow.c_; however, the patch
described below also changes the name of a function and changes
some comments, to better describe the code's behavior. It also
documents the new behavior in the [winfo] man page.

# Patches

A patch \(against Tk 8.4.5\) that implements the changes described above
may be found at
<http://www.eecs.umich.edu/~mckay/computer/winfotop.patch>

# Copyright

This document is in the public domain.

Name change from tip/154.tip to tip/154.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

TIP:            154
Title:          Add Named Colors to Tk
Version:        $Revision: 1.26 $
Author:         Damon Courtney <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        03-Sep-2003
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes the addition of a '''color''' command at the Tk level to
allow developers to create named colors as they can already do with both fonts
and images.

~ Rationale

Named fonts and images go a long way toward making Tk able to modify a lot of
options on a global scale simply by adjusting a single item. Tk already
simulates some version of named colors on Windows with the use of values like
''SystemButtonFace'' and ''SystemWindowFrame''. These color names map to
values pre-defined in Windows. On UNIX, we have to kind of fake these things
around.

With the addition of named colors, we can simply define default colors in UNIX
that correspond to existing named colors on Windows. So, we could create
''SystemButtonFace'' as a named color on UNIX, and any Windows program using
those color names would port to UNIX without a change.

~ Implementation

I propose the introduction of a new command, '''color''':

 > '''color''' ''option'' ?''arg ...''?

This will have six subcommands.

The '''create''' subcommand creates a new named color.

 > '''color create''' ''colorName'' ?''option ...''?

Supported options (see below for full description) are:

 -color: The main color associated with this named color.

 -dark1: The low-light color associated with this named color.

 -light1: The high-light color associated with this named color.

The '''cget''' subcommand retrieves an option associated with a named color

 > '''color cget''' ''colorName option''

The '''configure''' subcommand sets an option (or options) associted with a
named color, or retrieves information about all the options associated with
that named color (following the standard Tk pattern for cget/configure.)

 > '''color configure''' ''colorName'' ?''option ...''?

The '''exists''' subcommand determines if a named color exists.

 > '''color exists''' ''colorName''

The '''names''' subcommand returns a list of all named colors, including those
created by Tk. The optional glob-style ''pattern'' allows only some colors to
be returned.

 > '''color names''' ?''pattern''?

The '''delete''' subcommand deletes a named color.

 > '''color delete''' ''colorName''

~~Options

The '''-color''' option specifies any acceptable color in Tk as the color to
use. The '''-light1''' and '''-dark1''' options specify the border shadings to
use for this color when it is used as a border. They are named with a 1
because I think in the future we will end up with more levels of shading.
Windows already has two levels, we just ignore the second one.

Beyond the color command, we need to implement a default set of standard
colors that will exist across all platforms. As proposed by some, I think
these should be named Tk*. The current list (reflected in the Windows color
list) would be:

|TkButtonFace
|TkButtonText
|TkDisabledText
|TkHighlight
|TkHighlightText
|TkMenu
|TkMenuText
|TkScrollbar
|TkWindow
|TkWindowFrame
|TkWindowText

If there are others, I'm not sure what they are. This list can easily be
expanded over time as most of them will be created at the Tcl-level.

As part of this TIP, the core widgets should also be modified to use the new
Tk* named colors as their defaults for all platforms. The named colors will
still be created from system defaults on each system. The UNIX colors will
most likely come from whatever comes out of [172].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|



|




|





|


|

|

|



|

|

|







|

|

|

|

|

|

|

|
|


|

|

|

|

|
|






|
|

|
|
|
|
|
|
|
|
|
|
|





|

|

|


>

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

# TIP 154: Add Named Colors to Tk

	Author:         Damon Courtney <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        03-Sep-2003
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes the addition of a **color** command at the Tk level to
allow developers to create named colors as they can already do with both fonts
and images.

# Rationale

Named fonts and images go a long way toward making Tk able to modify a lot of
options on a global scale simply by adjusting a single item. Tk already
simulates some version of named colors on Windows with the use of values like
_SystemButtonFace_ and _SystemWindowFrame_. These color names map to
values pre-defined in Windows. On UNIX, we have to kind of fake these things
around.

With the addition of named colors, we can simply define default colors in UNIX
that correspond to existing named colors on Windows. So, we could create
_SystemButtonFace_ as a named color on UNIX, and any Windows program using
those color names would port to UNIX without a change.

# Implementation

I propose the introduction of a new command, **color**:

 > **color** _option_ ?_arg ..._?

This will have six subcommands.

The **create** subcommand creates a new named color.

 > **color create** _colorName_ ?_option ..._?

Supported options \(see below for full description\) are:

 -color: The main color associated with this named color.

 -dark1: The low-light color associated with this named color.

 -light1: The high-light color associated with this named color.

The **cget** subcommand retrieves an option associated with a named color

 > **color cget** _colorName option_

The **configure** subcommand sets an option \(or options\) associted with a
named color, or retrieves information about all the options associated with
that named color \(following the standard Tk pattern for cget/configure.\)

 > **color configure** _colorName_ ?_option ..._?

The **exists** subcommand determines if a named color exists.

 > **color exists** _colorName_

The **names** subcommand returns a list of all named colors, including those
created by Tk. The optional glob-style _pattern_ allows only some colors to
be returned.

 > **color names** ?_pattern_?

The **delete** subcommand deletes a named color.

 > **color delete** _colorName_

## Options

The **-color** option specifies any acceptable color in Tk as the color to
use. The **-light1** and **-dark1** options specify the border shadings to
use for this color when it is used as a border. They are named with a 1
because I think in the future we will end up with more levels of shading.
Windows already has two levels, we just ignore the second one.

Beyond the color command, we need to implement a default set of standard
colors that will exist across all platforms. As proposed by some, I think
these should be named Tk\*. The current list \(reflected in the Windows color
list\) would be:

	TkButtonFace
	TkButtonText
	TkDisabledText
	TkHighlight
	TkHighlightText
	TkMenu
	TkMenuText
	TkScrollbar
	TkWindow
	TkWindowFrame
	TkWindowText

If there are others, I'm not sure what they are. This list can easily be
expanded over time as most of them will be created at the Tcl-level.

As part of this TIP, the core widgets should also be modified to use the new
Tk\* named colors as their defaults for all platforms. The named colors will
still be created from system defaults on each system. The UNIX colors will
most likely come from whatever comes out of [[172]](172.md).

# Copyright

This document has been placed in the public domain.

Name change from tip/155.tip to tip/155.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216


217
218
219
220
221
222
223


224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389

TIP:            155
Title:          Fix Some of the Text Widget's Limitations
Version:        $Revision: 1.23 $
Author:         Vince Darley <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        08-Sep-2003
Post-History:   
Tcl-Version:    8.5


~ Abstract

Tk's text widget is very powerful, but has a number of known
limitations.   In particular the entire handling of wrapped lines and 'display/visual entities' versus 'logical entities' is quite limited.  The most obvious side-effect of these inadequacies is the 'scrollbar problem' (in which, particularly
when there are long wrapped lines in the widget, the vertical
scrollbar slider changes in size depending on the number of logical
lines currently displayed, see http://mini.net/tcl/896 for example).  This TIP overhauls the widget to provide consistent, complete support for 'display lines', 'display indices' and as a consequence smooth, pixel-based scrolling.  A few other small bugs/issues have also been resolved.

~ Proposal

The text widget has a number of limitations:

  1. The aforementioned scrollbar interaction is flawed

  1. To count the number of characters between index positions $idx1
     and $idx2, one can only really do ''string length [.text get
     $idx1 $idx2]''.  There is no easy way to determine the number of
     visible (non-elided) characters between these two index
     positions, nor the number of valid index positions between them
     (remember that embedded windows or images always take up one unit
     of index position, but don't correspond to any characters).  A similar difficulty exists in counting the number of display lines between two index positions, and in counting the number of pixels between two index positions (or in the entire widget).

  1. Performing a correct text "replace" operation (as used by a text
     editor, for example) is difficult, because combinations of
     insert/delete tend to make the window scroll and/or leave the
     insertion cursor in an unnatural place.

  1. There is no way to configure the widget to get an acceptable
     block-cursor.

  1. When long lines are wrapped there is no easy way to get the
     beginning or end of a possible display line, or move up or down
     by display lines, unless the line is actually currently displayed
     (and even then the code is rather complex).

  1. Even though 'search' can operate optionally on all text or just non-elided text, there is no easy way to retrieve the actual string which matched in the latter case, if the match spans characters on either side of an elided range.

  1. ''.text search -backwards -all'' returns subsets of indices in forwards rather than backwards order; with simple multi-line greedy searches (like ''-nolinestop -- .*'') it fails to match multiple lines; it can return backwards matches which fully enclose each other, etc.

This TIP is, therefore, to fix these limitations, as follows:

  1. Make internal changes to the text widget so it keeps track of the
     number of vertical display pixels in each logical line, and uses
     that information to calculate scrollbar interactions, to provide
     a better user experience, including smooth scrolling.  This requires an extension to the text widget's yview command to do smooth scrolling: ''.text yview scroll N pixels''

  1. Add a ''count'' widget subcommand, which calculates the number of
     characters or index positions or non-elided characters/index
     positions or lines or displaylines or x/y-pixels between two given indices.  Similar extend ''+N chars'' to allow index calculations by chars, indices and elided or not.

  1. Add a ''replace'' widget subcommand, which performs a combined
     delete/insert operation while ensuring that the insertion
     position, vertical display position, and undo/redo information is
     correctly set.

  1. Add a ''-blockcursor'' configuration option which makes the
     widget use a rectangular flashing "block" rather than a thin beam
     for the insertion point.

  1. Add ''displaylinestart'' and ''displaylineend'' and ''+/- N
     displaylines'' index offsets which work like ''linestart'',
     ''lineend'', ''+/- N lines'' but with display lines, and which
     work whether the relevant indices are currently displayed or not.  And make ''tk::TextUpDownLine'' operate in terms of display lines.

  1. Add an option ''-displaychars'' to ''get'' which, if given, restricts the returned characters to be just those which are not elided.

  1. Fix 'search -all -backwards' so that it returns the matches in the correct backwards sequence, even within each individual line.  Also add the options '-overlap' (to allow matches which overlap each other to be returned) and '-strictlimits' to prevent matches which would extend beyond the strict [[pos,limit]] range.  Fix code for correct greedy forwards and backwards searches using correct non-overlapping matching unless explicitly requested.

Each of these proposals is discussed and presented in full detail
below.

In addition, the current implementation provides for a bit more text
widget objectification and fixes the "very slow deletion of lots of
text with lots of tags" bug (there was a non-linear slowdown which has
been removed).  One crashing bug in the text widget has also been
fixed, and a bug in searches with '-all'.

~ Scrollbar Interaction

This is the most complex of the proposed changes, even though solving
it results in very limited changes to the actual text-widget's public Tcl or C
interfaces.  The following example illustrates the problem:

| pack [scrollbar .s -command {.t yview}] -side right -fill y
| pack [text .t -yscrollcommand {.s set}] -side left
|
| for {set i 0} {$i < 300} {incr i} {
|   .t insert insert $i
| }

|
| for {set i 0} {$i < 20} {incr i} {
|   .t insert insert "$i\n"
| }

|
| for {set i 0} {$i < 300} {incr i} {
|   .t insert insert $i
| }


Solving this problem perfectly must require the text widget to know
exactly how many vertical pixels each line contains.  However, for a
widget which contains a great deal (megabytes) of text, images,
embedded windows and numerous tags (and on which certain tags could
have their font configuration changed on the fly), it is clearly
impractical to have the widget calculate every line's pixel-height
requirements whenever anything changes (for bad cases the
response-time would be unacceptable).

The solution proposed is an asynchronous update mechanism where the
structure representing each logical line caches the last known pixel
height and an epoch counter.  As changes (global or local) are made,
individual logical lines recalculate their height either immediately
(for small, local changes such as inserting a few characters) or are
scheduled for recalculation (for larger changes such as resizing the
window or changing size-influencing tag settings).  When blocks of
lines (or, indeed, all lines) are scheduled for recalculation, each
asynchronous callback should only recalculate the pixel heights of a
relatively small number of lines, so that user-responsiveness is
maintained.

As line pixel-height calculations are updated, a second asynchronous
mechanism is triggered, this one to update any scrollbar attached to
the text widget (i.e. call the ''-yscrollcommand'' callback).  Again
it is undesirable to call this every single time a single line's
height is updated, so this is called with a timer mechanism so it is
updated every 200ms.

Both of these asynchronous mechanisms should be designed so they do
not need to be run if nothing relevant has changed in the widget.

It may require some experimentation to determine the most appropriate
usage patterns of these asynchronous callbacks.  In particular, the
current implementation uses timer callbacks (idle callbacks cannot be
used because idle callbacks are not allowed to reschedule themselves).
A thread-based implementation may have some advantages (although it
certainly has disadvantages too).

Given the pixel calculations are available, they have been used to provide for smooth scrolling of the text widget.  This means even with large images (possibly even larger than the height of the widget itself), smooth scrolling off top and bottom of the widget are automatic.  In order for smooth scrolling to be used by Tk's Tcl library, the ''pixels'' unit has been added to the ''.text yview scroll'' command.  This is used to ensure mouse-wheel and scan-drag scrolling are smooth.  It is important that the existing ''pages'' and ''units'' (the latter being display lines) do not change in meaning so that, for example, clicking on a scrollbar's arrow still scrolls the widget by 1 display line.

~ Count Subcommand

A new subcommand ''.text count ?options? startIndex endIndex'' is
added for all text widgets.  Valid options (any combination of which can be specified) are ''-chars'',
''-indices'', ''-displaychars'', ''-displayindices'', ''-lines'', ''-displaylines'', ''-xpixels'', ''-ypixels''.  The default
value, if no option is specified, is ''-indices''.  In addition ''-update'' can be specified.  If given this option ensures all subsequent options operate on a range of indices for which all metric calculations (e.g. line pixel heights) are up to date.  This option is of particular importance to the ''-ypixels'' option.

The subcommand counts the number of relevant things between the two
indices.  If startIndex is after endIndex, the result will be a
negative number.  The actual items which are counted depend on the
option given, as follows:

 -indices: count all characters and embedded windows or images (i.e.
    everything which counts in text-widget index space), whether they
    are elided or not.

 -chars: count all characters, whether elided or not.  Do not count
    embedded windows or images.

 -displaychars: count all non-elided characters.

 -displayindices: count all non-elided characters, windows and images.

 -lines: count all logical lines (this option is only included for completeness since it can be achieved pretty easily in Tk already)

 -displaylines: count all displaylines.

 -xpixels: count the number of horizontal pixels between the two indices.

 -ypixels: count the number of vertical pixels between the two indices. 

If more than one of these counting options is given, the result is a list with one entry for each such option given (''-update'' does not contribute to this result, of course).

Similar, the index modifiers are extended so the following are now valid: "+N display chars", "+N indices", "+N display indices", "+N any indices", "+N any chars".  The "display" and "any" can be abbreviated if they are followed by whitespace.

In particular, this means that:

| string length [.text get $i1 $i2] == [.text count -chars $i1 $i2]

provided $i1 is not after $i2 in the widget.  It also means that

| .text compare "$i1 + [.text count -indices $i1 $i2]indices" == $i2

and

| .text compare "$i1 + [.text count -displayindices $i1 $i2] display indices" == $i2

is true under all circumstances.

Lastly, for those who wish to know the required number of vertical pixels a text widget needs, ''.text count -update -ypixels 1.0 end'' will give this (once any borderwidth, highlightthickness and ypad have been added on).  For example, the following procedure will give the
smallest possible size in pixels which a given text widget would desire to have no scrollbars:

|proc textDetermineDimensions {text} {
|    set border [$text cget -highlightthickness]
|    incr border [$text cget -borderwidth]
|    set y [expr {2* ($border + [$text cget -pady])}]
|    set x [expr {2* ($border + [$text cget -padx])}]
|    
|    incr y [$text count -update -ypixels 1.0 end]
|    if {[$text cget -wrap] eq "none"} {
|	set max_x 0
|	for {set i 0} {$i < int([$text index end])} {incr i} {
|	    set xpix [$text count -xpixels ${i}.0 "${i}.0 linend"]
|	    if {$xpix > $max_x} {
|		set max_x $xpix
|	    }
|	}


|	incr max_x $x
|	return [list $x $y]
|    } else {
|	return [list [winfo reqwidth $text] $y]
|    }
|}



~ Replace Subcommand

A new subcommand

| .text replace index1 index2 chars ?tagList chars tagList ...?

is added for all text widgets.  This subcommand is approximately
equivalent to a combined:

| .text delete index1 index2
| .text insert index1 chars ?tagList chars tagList ...?

but also ensures that the current window display position (e.g. what
line is currently displayed at the top left corner of the text widget),
the current insertion position and the undo/redo stack are all correctly
set up.  This subcommand could be implemented in pure Tcl, but is quite
complex to get right.  The C-level implementation shares most of the
code with insert/delete/count and can also be made more efficient in
its handling of window-scrolling issues.

~ Block Cursor

A new text widget configuration option ''-blockcursor <boolean>'' is
added.  If set to any true value, instead of a thin flashing vertical
bar being used for the insertion cursor, a full rectangular block is
used instead.

~ Display-Line Handling

Currently one can discover the beginning or end of a given logical line
and move between logical lines with:

| .text index "$idx linestart"
| .text index "$idx lineend"
| .text index "$idx +1lines"
| .text index "$idx -5lines"

However, when a given logical line may be wrapped over numerous
display lines it is not so simple to find the beginning or end of a
display line, or move up or down by display lines.  (In fact is is
currently possible with the ''@'' syntax if the logical line and the
$idx are both currently displayed on screen, but is not possible(*) if
the logical line is not currently displayed).  Therefore a new index
manipulation set are added:

| .text index "$idx display linestart"
| .text index "$idx display lineend"
| .text index "$idx +1display lines"
| .text index "$idx -5display lines"

These work whether or not $idx is currently displayed (when it is not
displayed, the index is calculated by laying out the geometry of the line
behind the scenes so this operation is certainly more time-consuming than
determining the logical line start or end).  The "display" in these items can be abbreviated if it is followed by whitespace (if it is not abbreviated then the whitespace is optional).

In addition the single Tcl proc ''tk::TextUpDownLine'' (in text.tcl) has been updated to operate in terms of display lines and thereby to retain the current x position as accurately as possible across multiple up/down arrow keypresses.

(*) Perhaps it would be possible, if horribly cumbersome, by copying the
relevant contents into another text widget which is unmapped and making
sure the desired lines are visible in that widget, and finally
performing the desired operations on the copy before deleting it all!

~ Get -displaychars

This is a simple new option to the ''get'' subcommand, which now has the syntax ''.text get ?-displaychars? ?--? index1 ?index2....?''.  This means the following code now makes sense:

| set found [.text search -elide -count num $pattern $pos]
| set match [.text get -displaychars $found "$found + $num chars"]

Previously, achieving something like the second line was quite complex.

~ Search subcommand

In Tk8.5a0 at present ''search -all -backwards ...'' returns the list of indices backwards from line to line, but forwards within each line (a side-effect of backwards matching being implemented as repeated forward searches).  Large backwards or forwards regexp searches for, say, ''-nolinestop -- .*'' would only match a single line.  Various other overlap vs non-overlap problems too.  All of these glitches (my own code ;-) have been fixed and the test suite for ''search'' hugely extended.

~ Backward Compatibility

All of the above changes simply extend the functionality of the text
widget in new ways, and therefore have no significant backward
compatibility problems.  It is possible that some existing Tk code may notice some minor behavioural differences:

Since the interaction between text widget and vertical scrollbar is now
slightly different, any code which assumed that a particular scrollbar
position (e.g. 0.5) corresponds to a particular line of text will find
that that line of text may now be different (and will of course depend on
the actual line heights).  This change is considered a bug fix, not an
incompatibility!  In particular, however, any code which performs a
calculation like:

| set num_lines [lindex [split [.text index end] .] 0]
| set last_visible [expr {int($num_lines *[lindex [.text yview] 1])}]

(under the assumption that the scrollbar's units are effectively
measured in logical lines) will now get a different answer (since the
scrollbar operates with pixels), and that different answer will not
correspond to the last visible line.  Of course the code should
always have used:

| set last_visible
|   [expr {int([.text index "@[winfo width .text],[winfo height .text]"])}]

which works correctly no matter how the scrollbar operates.

In addition, with the new ''pixels'' unit for the scrollbar, the command ''.text yview scroll 1 p'' is now ambiguous and will throw an error.  This incompatibility is similar to those which have previously been introduced in, e.g., Tk 8.4 (with -padx, -pady).

Lastly, "+N chars" is a synonym for "+N indices" for backwards compatibility reasons.  This may be different to "+N any chars".

~ Implementation

A complete implementation is available at:

http://sf.net/tracker/?func=detail&aid=791292&group_id=12997&atid=312997

This passes all Tk text widget tests (on Windows XP, at least), including
a significant number of new tests.  The memory requirements of the text
widget have increased marginally to support the correct vertical
scrolling behaviour: two new integers must be stored for each logical
line of text.

~ Out of Scope

A number of other text widget enhancements might be nice.  Some of
these are listed here for completeness:

  * Printing support (at least to postscript like the canvas widget -- in fact I'm sure 95% of the canvas printing code could be re-used for this, with the only new stuff being handling of multiple pages.  It might be preferable to support pdf instead, however)

  * Cloning (e.g. reading in the result of ''.text -dump'', although
    handling of tag definitions and tag-bindings would also be nice)

  * Synchronizing/backing the widget contents with a Tcl variable
    (actually not too hard to implement quite efficiently now, given
    the ''count'' functionality).  This can be done without too much trouble with pure Tcl.

  * Loading data into the widget asynchronously from a channel (easy
    to implement with Tcl procedures, although core support might make
    for better scrollbar handling and thereby make such a feature
    almost invisible to the user).

  * Modifications to the horizontal scrollbar.  The horizontal
    scrollbar's position/status depends only on the
    ''currently-displayed contents'' of the text widget.  This means
    as one scrolls the widget vertically, the horizontal scrollbar
    changes.  No attempt has been made to fix this problem in this
    TIP.

  * A shorthand (''display start'', ''display end''?)  for the
    rather less obvious ''.text index "@0,0"'' and ''.text index
    "@[winfo width .text],[winfo height .text]"''

  * The attachment of user-defined data to each logical line in the
    widget (e.g. a code parser's current internal state), which might
    make true parsing for syntax colouring significantly easier.

  * The pre-existing behaviour of ''+/- N lines'' uses byte-indices instead of x-pixel calculations (thereby having the cursor bobbling around when there are multi-byte characters or even worse when there are images, proportional fonts, tabs, etc).  Further, the behaviour is quite strange when wrapping is enabled in the widget.  This TIP does not propose any changes in this area other than to suggest that Tcl coders make use of 'displaylines' instead, for more consistent behaviour (as has been done to text.tcl).

  * To do word-matching with ''search'' requires the use of a regexp pattern and something like ''.text search -regexp -- "\\m[[quote::Regfind $string]]\\M" $pos''.  It might be nice to add a flag to control word-matching without the need for such manipulations.

None of these is included in the current TIP or current
implementation.  If interested members of the community wish to extend
this TIP or submit further TIPs to handle any of these enhancements,
they are very welcome (and the author is happy to help coordinate
where possible).

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|


|

|






|
|
|

|
|

|
|









|



|






|

|

|

|




|



|
|
|
|

|

|






|
|


|





|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
<
|
>


|
|
|

|
|



|

|
|
|
|






|









|
|
|
|

|

|

|
|
|
|






|
|









|







|

|



|



|



|



|


|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
<
<
|
>
>
|



|




|
|

|
|






|

|




|




|
|
|
|



|
|
|
|


|
|
|
|

|


|

|

|




|

|

|
|



|

|

|







|
|
|



|
|

|
|
|



|
|



|

|

|



|

|





|




|

|
|


|
|

|


|



|




|
|
|


|


|

|




|
|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213


214
215
216
217
218
219


220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389

# TIP 155: Fix Some of the Text Widget's Limitations

	Author:         Vince Darley <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        08-Sep-2003
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

Tk's text widget is very powerful, but has a number of known
limitations.   In particular the entire handling of wrapped lines and 'display/visual entities' versus 'logical entities' is quite limited.  The most obvious side-effect of these inadequacies is the 'scrollbar problem' \(in which, particularly
when there are long wrapped lines in the widget, the vertical
scrollbar slider changes in size depending on the number of logical
lines currently displayed, see <http://mini.net/tcl/896> for example\).  This TIP overhauls the widget to provide consistent, complete support for 'display lines', 'display indices' and as a consequence smooth, pixel-based scrolling.  A few other small bugs/issues have also been resolved.

# Proposal

The text widget has a number of limitations:

  1. The aforementioned scrollbar interaction is flawed

  1. To count the number of characters between index positions $idx1
     and $idx2, one can only really do _string length [.text get
     $idx1 $idx2]_.  There is no easy way to determine the number of
     visible \(non-elided\) characters between these two index
     positions, nor the number of valid index positions between them
     \(remember that embedded windows or images always take up one unit
     of index position, but don't correspond to any characters\).  A similar difficulty exists in counting the number of display lines between two index positions, and in counting the number of pixels between two index positions \(or in the entire widget\).

  1. Performing a correct text "replace" operation \(as used by a text
     editor, for example\) is difficult, because combinations of
     insert/delete tend to make the window scroll and/or leave the
     insertion cursor in an unnatural place.

  1. There is no way to configure the widget to get an acceptable
     block-cursor.

  1. When long lines are wrapped there is no easy way to get the
     beginning or end of a possible display line, or move up or down
     by display lines, unless the line is actually currently displayed
     \(and even then the code is rather complex\).

  1. Even though 'search' can operate optionally on all text or just non-elided text, there is no easy way to retrieve the actual string which matched in the latter case, if the match spans characters on either side of an elided range.

  1. _.text search -backwards -all_ returns subsets of indices in forwards rather than backwards order; with simple multi-line greedy searches \(like _-nolinestop -- .\*_\) it fails to match multiple lines; it can return backwards matches which fully enclose each other, etc.

This TIP is, therefore, to fix these limitations, as follows:

  1. Make internal changes to the text widget so it keeps track of the
     number of vertical display pixels in each logical line, and uses
     that information to calculate scrollbar interactions, to provide
     a better user experience, including smooth scrolling.  This requires an extension to the text widget's yview command to do smooth scrolling: _.text yview scroll N pixels_

  1. Add a _count_ widget subcommand, which calculates the number of
     characters or index positions or non-elided characters/index
     positions or lines or displaylines or x/y-pixels between two given indices.  Similar extend _\+N chars_ to allow index calculations by chars, indices and elided or not.

  1. Add a _replace_ widget subcommand, which performs a combined
     delete/insert operation while ensuring that the insertion
     position, vertical display position, and undo/redo information is
     correctly set.

  1. Add a _-blockcursor_ configuration option which makes the
     widget use a rectangular flashing "block" rather than a thin beam
     for the insertion point.

  1. Add _displaylinestart_ and _displaylineend_ and _\+/- N
     displaylines_ index offsets which work like _linestart_,
     _lineend_, _\+/- N lines_ but with display lines, and which
     work whether the relevant indices are currently displayed or not.  And make _tk::TextUpDownLine_ operate in terms of display lines.

  1. Add an option _-displaychars_ to _get_ which, if given, restricts the returned characters to be just those which are not elided.

  1. Fix 'search -all -backwards' so that it returns the matches in the correct backwards sequence, even within each individual line.  Also add the options '-overlap' \(to allow matches which overlap each other to be returned\) and '-strictlimits' to prevent matches which would extend beyond the strict [pos,limit] range.  Fix code for correct greedy forwards and backwards searches using correct non-overlapping matching unless explicitly requested.

Each of these proposals is discussed and presented in full detail
below.

In addition, the current implementation provides for a bit more text
widget objectification and fixes the "very slow deletion of lots of
text with lots of tags" bug \(there was a non-linear slowdown which has
been removed\).  One crashing bug in the text widget has also been
fixed, and a bug in searches with '-all'.

# Scrollbar Interaction

This is the most complex of the proposed changes, even though solving
it results in very limited changes to the actual text-widget's public Tcl or C
interfaces.  The following example illustrates the problem:

	 pack [scrollbar .s -command {.t yview}] -side right -fill y
	 pack [text .t -yscrollcommand {.s set}] -side left
	
	 for {set i 0} {$i < 300} {incr i} {
	   .t insert insert $i

	 }
	
	 for {set i 0} {$i < 20} {incr i} {
	   .t insert insert "$i\n"

	 }
	
	 for {set i 0} {$i < 300} {incr i} {
	   .t insert insert $i

	 }

Solving this problem perfectly must require the text widget to know
exactly how many vertical pixels each line contains.  However, for a
widget which contains a great deal \(megabytes\) of text, images,
embedded windows and numerous tags \(and on which certain tags could
have their font configuration changed on the fly\), it is clearly
impractical to have the widget calculate every line's pixel-height
requirements whenever anything changes \(for bad cases the
response-time would be unacceptable\).

The solution proposed is an asynchronous update mechanism where the
structure representing each logical line caches the last known pixel
height and an epoch counter.  As changes \(global or local\) are made,
individual logical lines recalculate their height either immediately
\(for small, local changes such as inserting a few characters\) or are
scheduled for recalculation \(for larger changes such as resizing the
window or changing size-influencing tag settings\).  When blocks of
lines \(or, indeed, all lines\) are scheduled for recalculation, each
asynchronous callback should only recalculate the pixel heights of a
relatively small number of lines, so that user-responsiveness is
maintained.

As line pixel-height calculations are updated, a second asynchronous
mechanism is triggered, this one to update any scrollbar attached to
the text widget \(i.e. call the _-yscrollcommand_ callback\).  Again
it is undesirable to call this every single time a single line's
height is updated, so this is called with a timer mechanism so it is
updated every 200ms.

Both of these asynchronous mechanisms should be designed so they do
not need to be run if nothing relevant has changed in the widget.

It may require some experimentation to determine the most appropriate
usage patterns of these asynchronous callbacks.  In particular, the
current implementation uses timer callbacks \(idle callbacks cannot be
used because idle callbacks are not allowed to reschedule themselves\).
A thread-based implementation may have some advantages \(although it
certainly has disadvantages too\).

Given the pixel calculations are available, they have been used to provide for smooth scrolling of the text widget.  This means even with large images \(possibly even larger than the height of the widget itself\), smooth scrolling off top and bottom of the widget are automatic.  In order for smooth scrolling to be used by Tk's Tcl library, the _pixels_ unit has been added to the _.text yview scroll_ command.  This is used to ensure mouse-wheel and scan-drag scrolling are smooth.  It is important that the existing _pages_ and _units_ \(the latter being display lines\) do not change in meaning so that, for example, clicking on a scrollbar's arrow still scrolls the widget by 1 display line.

# Count Subcommand

A new subcommand _.text count ?options? startIndex endIndex_ is
added for all text widgets.  Valid options \(any combination of which can be specified\) are _-chars_,
_-indices_, _-displaychars_, _-displayindices_, _-lines_, _-displaylines_, _-xpixels_, _-ypixels_.  The default
value, if no option is specified, is _-indices_.  In addition _-update_ can be specified.  If given this option ensures all subsequent options operate on a range of indices for which all metric calculations \(e.g. line pixel heights\) are up to date.  This option is of particular importance to the _-ypixels_ option.

The subcommand counts the number of relevant things between the two
indices.  If startIndex is after endIndex, the result will be a
negative number.  The actual items which are counted depend on the
option given, as follows:

 -indices: count all characters and embedded windows or images \(i.e.
    everything which counts in text-widget index space\), whether they
    are elided or not.

 -chars: count all characters, whether elided or not.  Do not count
    embedded windows or images.

 -displaychars: count all non-elided characters.

 -displayindices: count all non-elided characters, windows and images.

 -lines: count all logical lines \(this option is only included for completeness since it can be achieved pretty easily in Tk already\)

 -displaylines: count all displaylines.

 -xpixels: count the number of horizontal pixels between the two indices.

 -ypixels: count the number of vertical pixels between the two indices. 

If more than one of these counting options is given, the result is a list with one entry for each such option given \(_-update_ does not contribute to this result, of course\).

Similar, the index modifiers are extended so the following are now valid: "\+N display chars", "\+N indices", "\+N display indices", "\+N any indices", "\+N any chars".  The "display" and "any" can be abbreviated if they are followed by whitespace.

In particular, this means that:

	 string length [.text get $i1 $i2] == [.text count -chars $i1 $i2]

provided $i1 is not after $i2 in the widget.  It also means that

	 .text compare "$i1 + [.text count -indices $i1 $i2]indices" == $i2

and

	 .text compare "$i1 + [.text count -displayindices $i1 $i2] display indices" == $i2

is true under all circumstances.

Lastly, for those who wish to know the required number of vertical pixels a text widget needs, _.text count -update -ypixels 1.0 end_ will give this \(once any borderwidth, highlightthickness and ypad have been added on\).  For example, the following procedure will give the
smallest possible size in pixels which a given text widget would desire to have no scrollbars:

	proc textDetermineDimensions {text} {
	    set border [$text cget -highlightthickness]
	    incr border [$text cget -borderwidth]
	    set y [expr {2* ($border + [$text cget -pady])}]
	    set x [expr {2* ($border + [$text cget -padx])}]
	    
	    incr y [$text count -update -ypixels 1.0 end]
	    if {[$text cget -wrap] eq "none"} {
		set max_x 0
		for {set i 0} {$i < int([$text index end])} {incr i} {
		    set xpix [$text count -xpixels ${i}.0 "${i}.0 linend"]
		    if {$xpix > $max_x} {
			set max_x $xpix


		    }
		}
		incr max_x $x
		return [list $x $y]
	    } else {
		return [list [winfo reqwidth $text] $y]


	    }
	}

# Replace Subcommand

A new subcommand

	 .text replace index1 index2 chars ?tagList chars tagList ...?

is added for all text widgets.  This subcommand is approximately
equivalent to a combined:

	 .text delete index1 index2
	 .text insert index1 chars ?tagList chars tagList ...?

but also ensures that the current window display position \(e.g. what
line is currently displayed at the top left corner of the text widget\),
the current insertion position and the undo/redo stack are all correctly
set up.  This subcommand could be implemented in pure Tcl, but is quite
complex to get right.  The C-level implementation shares most of the
code with insert/delete/count and can also be made more efficient in
its handling of window-scrolling issues.

# Block Cursor

A new text widget configuration option _-blockcursor <boolean>_ is
added.  If set to any true value, instead of a thin flashing vertical
bar being used for the insertion cursor, a full rectangular block is
used instead.

# Display-Line Handling

Currently one can discover the beginning or end of a given logical line
and move between logical lines with:

	 .text index "$idx linestart"
	 .text index "$idx lineend"
	 .text index "$idx +1lines"
	 .text index "$idx -5lines"

However, when a given logical line may be wrapped over numerous
display lines it is not so simple to find the beginning or end of a
display line, or move up or down by display lines.  \(In fact is is
currently possible with the _@_ syntax if the logical line and the
$idx are both currently displayed on screen, but is not possible\(\*\) if
the logical line is not currently displayed\).  Therefore a new index
manipulation set are added:

	 .text index "$idx display linestart"
	 .text index "$idx display lineend"
	 .text index "$idx +1display lines"
	 .text index "$idx -5display lines"

These work whether or not $idx is currently displayed \(when it is not
displayed, the index is calculated by laying out the geometry of the line
behind the scenes so this operation is certainly more time-consuming than
determining the logical line start or end\).  The "display" in these items can be abbreviated if it is followed by whitespace \(if it is not abbreviated then the whitespace is optional\).

In addition the single Tcl proc _tk::TextUpDownLine_ \(in text.tcl\) has been updated to operate in terms of display lines and thereby to retain the current x position as accurately as possible across multiple up/down arrow keypresses.

\(\*\) Perhaps it would be possible, if horribly cumbersome, by copying the
relevant contents into another text widget which is unmapped and making
sure the desired lines are visible in that widget, and finally
performing the desired operations on the copy before deleting it all!

# Get -displaychars

This is a simple new option to the _get_ subcommand, which now has the syntax _.text get ?-displaychars? ?--? index1 ?index2....?_.  This means the following code now makes sense:

	 set found [.text search -elide -count num $pattern $pos]
	 set match [.text get -displaychars $found "$found + $num chars"]

Previously, achieving something like the second line was quite complex.

# Search subcommand

In Tk8.5a0 at present _search -all -backwards ..._ returns the list of indices backwards from line to line, but forwards within each line \(a side-effect of backwards matching being implemented as repeated forward searches\).  Large backwards or forwards regexp searches for, say, _-nolinestop -- .\*_ would only match a single line.  Various other overlap vs non-overlap problems too.  All of these glitches \(my own code ;-\) have been fixed and the test suite for _search_ hugely extended.

# Backward Compatibility

All of the above changes simply extend the functionality of the text
widget in new ways, and therefore have no significant backward
compatibility problems.  It is possible that some existing Tk code may notice some minor behavioural differences:

Since the interaction between text widget and vertical scrollbar is now
slightly different, any code which assumed that a particular scrollbar
position \(e.g. 0.5\) corresponds to a particular line of text will find
that that line of text may now be different \(and will of course depend on
the actual line heights\).  This change is considered a bug fix, not an
incompatibility!  In particular, however, any code which performs a
calculation like:

	 set num_lines [lindex [split [.text index end] .] 0]
	 set last_visible [expr {int($num_lines *[lindex [.text yview] 1])}]

\(under the assumption that the scrollbar's units are effectively
measured in logical lines\) will now get a different answer \(since the
scrollbar operates with pixels\), and that different answer will not
correspond to the last visible line.  Of course the code should
always have used:

	 set last_visible
	   [expr {int([.text index "@[winfo width .text],[winfo height .text]"])}]

which works correctly no matter how the scrollbar operates.

In addition, with the new _pixels_ unit for the scrollbar, the command _.text yview scroll 1 p_ is now ambiguous and will throw an error.  This incompatibility is similar to those which have previously been introduced in, e.g., Tk 8.4 \(with -padx, -pady\).

Lastly, "\+N chars" is a synonym for "\+N indices" for backwards compatibility reasons.  This may be different to "\+N any chars".

# Implementation

A complete implementation is available at:

<http://sf.net/tracker/?func=detail&aid=791292&group\_id=12997&atid=312997>

This passes all Tk text widget tests \(on Windows XP, at least\), including
a significant number of new tests.  The memory requirements of the text
widget have increased marginally to support the correct vertical
scrolling behaviour: two new integers must be stored for each logical
line of text.

# Out of Scope

A number of other text widget enhancements might be nice.  Some of
these are listed here for completeness:

  * Printing support \(at least to postscript like the canvas widget -- in fact I'm sure 95% of the canvas printing code could be re-used for this, with the only new stuff being handling of multiple pages.  It might be preferable to support pdf instead, however\)

  * Cloning \(e.g. reading in the result of _.text -dump_, although
    handling of tag definitions and tag-bindings would also be nice\)

  * Synchronizing/backing the widget contents with a Tcl variable
    \(actually not too hard to implement quite efficiently now, given
    the _count_ functionality\).  This can be done without too much trouble with pure Tcl.

  * Loading data into the widget asynchronously from a channel \(easy
    to implement with Tcl procedures, although core support might make
    for better scrollbar handling and thereby make such a feature
    almost invisible to the user\).

  * Modifications to the horizontal scrollbar.  The horizontal
    scrollbar's position/status depends only on the
    _currently-displayed contents_ of the text widget.  This means
    as one scrolls the widget vertically, the horizontal scrollbar
    changes.  No attempt has been made to fix this problem in this
    TIP.

  * A shorthand \(_display start_, _display end_?\)  for the
    rather less obvious _.text index "@0,0"_ and _.text index
    "@[winfo width .text],[winfo height .text]"_

  * The attachment of user-defined data to each logical line in the
    widget \(e.g. a code parser's current internal state\), which might
    make true parsing for syntax colouring significantly easier.

  * The pre-existing behaviour of _\+/- N lines_ uses byte-indices instead of x-pixel calculations \(thereby having the cursor bobbling around when there are multi-byte characters or even worse when there are images, proportional fonts, tabs, etc\).  Further, the behaviour is quite strange when wrapping is enabled in the widget.  This TIP does not propose any changes in this area other than to suggest that Tcl coders make use of 'displaylines' instead, for more consistent behaviour \(as has been done to text.tcl\).

  * To do word-matching with _search_ requires the use of a regexp pattern and something like _.text search -regexp -- "\\\\m[quote::Regfind $string]\\\\M" $pos_.  It might be nice to add a flag to control word-matching without the need for such manipulations.

None of these is included in the current TIP or current
implementation.  If interested members of the community wish to extend
this TIP or submit further TIPs to handle any of these enhancements,
they are very welcome \(and the author is happy to help coordinate
where possible\).

# Copyright

This document has been placed in the public domain.

Name change from tip/156.tip to tip/156.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

TIP:		156
Title:		Language-Neutral Root Locale for Msgcat
Version:	$Revision: 1.4 $
Author:		Kevin Kenny <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	20-Sep-2003
Tcl-Version:	8.5
Discussions-To:	news:comp.lang.tcl
Post-History:	


~ Abstract

This TIP proposes to extend Tcl's message catalog mechanism by adding
a "root locale" (whose name is the empty string) that is searched after
searches in all the language-dependent locales have failed.

~ Rationale

In the current message catalog system, the search key for localized
strings is a version of the string itself, expressed in either a
language-neutral form or in the natural language of the programmer.
This scheme has the advantage that when a program searches for a
localized message, the search will always succeed; if a translation of
the message cannot be found in any of the message catalog preferences,
at least a language-neutral string (or a string in an inappropriate
language) will be available.

The drawback to the scheme as it stands comes when ambiguities enter
into the picture.  For instance, the English word, 'file,' might,
depending on context, appear in French as the word 'fichier,' or the
word, 'r�pe.'  An application implementing a catalog of hand tools
might well encounter such an ambiguity.

A more specific example that I have encountered deals with date and
time formatting.  Consider the [[clock format]] command.  It accepts a
format group, %x, that formats the current date in the default format
for the current locale.  It also accepts a group, %D, that formats the
current date in the specific format %m/%d/%Y.  In both the 'C' locale
and the 'en_US' locale, these two format groups generate identical strings.
If the message catalog is used to store them, there has to be a way to
have distinct keys look up the same string in the language-neutral
default locale.

~ Specification

The solution that both Java and ICU use for managing the problem of
ambiguity in the default locale is to implement a "root locale" that
is searched after the searches in the current language-dependent locales
have failed.  If a translation is found in the "root locale", it is
used just as if it was found in a language-dependent locale.

This TIP proposes the same for Tcl.  Specifically, it proposes that.

   1. The ''msgcat::mcpreferences'' command will be modified to add
      the empty string as a list element after the elements corresponding
      to the current locale.  If the current locale, for instance, is
      ''en_US_funky'', the result of [[mcpreferences]] will be
      ''{en_US_funky en_US en {}}'', and if the current locale is
      ''de_CH_schwyzertuetsch'', the four locales to be searched will
      be:

   > * ''de_CH_schwyzertuetsch''

   > * ''de_CH''

   > * ''de''

   > * {} (the empty locale)

   2. The ''msgcat::mcload'' command will be modified so that if it
      encounters the empty string as a locale name, it will replace it
      with ROOT.  This modification is made so that the empty locale
      will correspond to a file named, "ROOT.msg" rather than just
      ".msg", and hence yield a file whose name does not begin with
      a period.  Files whose names begin with periods are treated
      specially on certain filesystems (for instance, on Unix, they
      become files hidden from the ''ls'' command), and avoiding such
      names seems wise.  The implementors of both Java and ICU have
      made the same decision.

~ Reference Implementation

The changes require to implement this proposal are minimal and can be
obtained from SourceForge as Tcl Patch #809825.

~ Copyright

Copyright � 2003 by Kevin B. Kenny.  All rights reserved.

Permission to use this document in accordance with the terms of Open
Publication License (http://www.opencontent.org/openpub/) is herewith
granted.

<
|
<
|
|
|
|
|
|
|
|
>

|


|


|







|
|




|



|



|




|









|


|
|
|


|

|

|

|

|





|
|



|


|

|

|


|

>

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

# TIP 156: Language-Neutral Root Locale for Msgcat

	Author:		Kevin Kenny <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	20-Sep-2003
	Tcl-Version:	8.5
	Discussions-To:	news:comp.lang.tcl
	Post-History:	
-----

# Abstract

This TIP proposes to extend Tcl's message catalog mechanism by adding
a "root locale" \(whose name is the empty string\) that is searched after
searches in all the language-dependent locales have failed.

# Rationale

In the current message catalog system, the search key for localized
strings is a version of the string itself, expressed in either a
language-neutral form or in the natural language of the programmer.
This scheme has the advantage that when a program searches for a
localized message, the search will always succeed; if a translation of
the message cannot be found in any of the message catalog preferences,
at least a language-neutral string \(or a string in an inappropriate
language\) will be available.

The drawback to the scheme as it stands comes when ambiguities enter
into the picture.  For instance, the English word, 'file,' might,
depending on context, appear in French as the word 'fichier,' or the
word, 'râpe.'  An application implementing a catalog of hand tools
might well encounter such an ambiguity.

A more specific example that I have encountered deals with date and
time formatting.  Consider the [clock format] command.  It accepts a
format group, %x, that formats the current date in the default format
for the current locale.  It also accepts a group, %D, that formats the
current date in the specific format %m/%d/%Y.  In both the 'C' locale
and the 'en\_US' locale, these two format groups generate identical strings.
If the message catalog is used to store them, there has to be a way to
have distinct keys look up the same string in the language-neutral
default locale.

# Specification

The solution that both Java and ICU use for managing the problem of
ambiguity in the default locale is to implement a "root locale" that
is searched after the searches in the current language-dependent locales
have failed.  If a translation is found in the "root locale", it is
used just as if it was found in a language-dependent locale.

This TIP proposes the same for Tcl.  Specifically, it proposes that.

   1. The _msgcat::mcpreferences_ command will be modified to add
      the empty string as a list element after the elements corresponding
      to the current locale.  If the current locale, for instance, is
      _en\_US\_funky_, the result of [mcpreferences] will be
      _\{en\_US\_funky en\_US en \{\}\}_, and if the current locale is
      _de\_CH\_schwyzertuetsch_, the four locales to be searched will
      be:

	   > \* _de\_CH\_schwyzertuetsch_

	   > \* _de\_CH_

	   > \* _de_

	   > \* \{\} \(the empty locale\)

   2. The _msgcat::mcload_ command will be modified so that if it
      encounters the empty string as a locale name, it will replace it
      with ROOT.  This modification is made so that the empty locale
      will correspond to a file named, "ROOT.msg" rather than just
      ".msg", and hence yield a file whose name does not begin with
      a period.  Files whose names begin with periods are treated
      specially on certain filesystems \(for instance, on Unix, they
      become files hidden from the _ls_ command\), and avoiding such
      names seems wise.  The implementors of both Java and ICU have
      made the same decision.

# Reference Implementation

The changes require to implement this proposal are minimal and can be
obtained from SourceForge as Tcl Patch \#809825.

# Copyright

Copyright © 2003 by Kevin B. Kenny.  All rights reserved.

Permission to use this document in accordance with the terms of Open
Publication License \(<http://www.opencontent.org/openpub/\)> is herewith
granted.

Name change from tip/157.tip to tip/157.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
136
137


138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

TIP:		157
Title:		Argument Expansion with Leading {expand}
Version:	$Revision: 1.7 $
Author:		Kevin B. Kenny <[email protected]>
Author:		Peter Spjuth <[email protected]>
Author:		Donal K. Fellows <[email protected]>
Author:		Don Porter <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	20-Sep-2003
Post-History:	
Obsoletes:	144
Tcl-Version:	8.5


~ Abstract

This TIP proposes to add syntax in Tcl to 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
something specialised in doing this would be better.

~ Background

See also [103] and [144].  Please also see a summary of a poll of
TCLCORE readers taken after [103] was rejected.
http://wiki.tcl.tk/9462

~ Rationale

For examples three statements are used.  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 syntax they become:

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

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.

~ Specification

If a word starts with the string, "{expand}", and is followed by a non
whitespace character it signifies argument expansion.  The leading
"{expand}" is removed and the rest of the word is parsed and
substituted as any other word.  The character after the removed
"{expand}" 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 must begin with {expand} to trigger expansion
which means that words like these are not expanded:

|cmd "{expand}$temp" \{expand}[something]

''Note 2:'' Expansion is typically most useful with words like:

|cmd {expand}$var {expand}[somecmd $arg] {expand}$arr([cmd $arg])

But things like this are also legal:

|cmd {expand}word {expand}$x,$y {expand}[foo]xy[apa] {expand}{apa bepa}

~ Motivating Examples

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:

|exec prog1 {expand}$optlist1 | prog2 {expand}$optlist2 | prog3 -staticOption

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:

|set id [$canv create polygon {expand}$coords -fill {} \
|                             {expand}$opts -tags {foo bar}]

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:

|namespace eval my {
|   variable defaults {
|      -bg white
|      -fg black
|   }

|   proc entry {path args} {
|      variable defaults
|      ::entry $path {expand}$defaults \
|                    {expand}[platformOpts $::tcl_platform(platform)] \
|                    {expand}$args
|   }
|}



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:

|$text delete {expand}[$text tag ranges $tagToCleanUp]

In this case, the obvious alternative:

|foreach {s e} [$text tag ranges $theTag] { $text delete $s $e }

is wrong, because the positions of the tags move with each deletion
(by contrast, the [[$text delete]] operation is careful in this
regard.)

~ Reference Implementation

Not done yet.

~ Summary of Discussions

This TIP has had a long history; a great many alternatives have been
proposed - two ([103] and [144]) formally.

In a poll of TCT members conducted by one of the authors, this version
appeared to be the most preferred.  Much of the discussion is
summarized at
http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/1805934 and
http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/1791605 (much
of the mailing list traffic between those two messages is devoted to
discussion of this issue.)

An open issue remains as to which Tcl release is suitable for the
implementation of this feature.  The question will be resolved by
voting on this TIP twice: once for 8.5 and once for 9.0

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
>

|




|






|





|

|
|
|

|



|
|
|





|



|
|
|





|

|

|

|

|






|


|

|

|



|

|


|





|








|
|


|

|








|
|
|
|
<
>
|
|
|
|
|
<
<
|
>
>
|




|
|


|



|


|
|

|



|


|




|
|

|





|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

# TIP 157: Argument Expansion with Leading {expand}

	Author:		Kevin B. Kenny <[email protected]>
	Author:		Peter Spjuth <[email protected]>
	Author:		Donal K. Fellows <[email protected]>
	Author:		Don Porter <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	20-Sep-2003
	Post-History:	
	Obsoletes:	144
	Tcl-Version:	8.5
-----

# Abstract

This TIP proposes to add syntax in Tcl to 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
something specialised in doing this would be better.

# Background

See also [[103]](103.md) and [[144]](144.md).  Please also see a summary of a poll of
TCLCORE readers taken after [[103]](103.md) was rejected.
<http://wiki.tcl.tk/9462>

# Rationale

For examples three statements are used.  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 syntax they become:

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

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.

# Specification

If a word starts with the string, "\{expand\}", and is followed by a non
whitespace character it signifies argument expansion.  The leading
"\{expand\}" is removed and the rest of the word is parsed and
substituted as any other word.  The character after the removed
"\{expand\}" 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 must begin with \{expand\} to trigger expansion
which means that words like these are not expanded:

	cmd "{expand}$temp" \{expand}[something]

_Note 2:_ Expansion is typically most useful with words like:

	cmd {expand}$var {expand}[somecmd $arg] {expand}$arr([cmd $arg])

But things like this are also legal:

	cmd {expand}word {expand}$x,$y {expand}[foo]xy[apa] {expand}{apa bepa}

# Motivating Examples

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:

	exec prog1 {expand}$optlist1 | prog2 {expand}$optlist2 | prog3 -staticOption

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:

	set id [$canv create polygon {expand}$coords -fill {} \
	                             {expand}$opts -tags {foo bar}]

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:

	namespace eval my {
	   variable defaults {
	      -bg white
	      -fg black

	   }
	   proc entry {path args} {
	      variable defaults
	      ::entry $path {expand}$defaults \
	                    {expand}[platformOpts $::tcl_platform(platform)] \
	                    {expand}$args


	   }
	}

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:

	$text delete {expand}[$text tag ranges $tagToCleanUp]

In this case, the obvious alternative:

	foreach {s e} [$text tag ranges $theTag] { $text delete $s $e }

is wrong, because the positions of the tags move with each deletion
\(by contrast, the [$text delete] operation is careful in this
regard.\)

# Reference Implementation

Not done yet.

# Summary of Discussions

This TIP has had a long history; a great many alternatives have been
proposed - two \([[103]](103.md) and [[144]](144.md)\) formally.

In a poll of TCT members conducted by one of the authors, this version
appeared to be the most preferred.  Much of the discussion is
summarized at
<http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/1805934> and
<http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/1791605> \(much
of the mailing list traffic between those two messages is devoted to
discussion of this issue.\)

An open issue remains as to which Tcl release is suitable for the
implementation of this feature.  The question will be resolved by
voting on this TIP twice: once for 8.5 and once for 9.0

# Copyright

This document has been placed in the public domain.

Name change from tip/158.tip to tip/158.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
136
137
138
139
140
141
142
143
144
145
146
147
148

TIP:            158
Title:          Distinguish the two 'Enter' keys on Windows
Version:        $Revision: 1.9 $
Author:         Wolfgang Gro�bauer <[email protected]>
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        20-Sep-2003
Post-History:   
Discussions-To: news:comp.lang.tcl
Tcl-Version:    8.5


~ Abstract

This TIP proposes that the "extended keys" on a Windows keyboard be
labeled with <Mod4> so that they can be distinguished from their
counterparts on the main keyboard.

~ Rationale

Most US keyboards on Windows systems have two keys bearing the label,
'Enter'.  The Tk system generates the events, ''<KeyPress-Return>''
and ''<KeyRelease-Return>'' for both of them; the two keys are
indistinguishable.  While this behavior is in keeping with the
"Microsoft Windows User Experience Guidelines," which explicitly state
that the two keys should command identical functionality, it is
inconvenient for developers who wish to port Unix applications that
already have different actions bound to the ''<KeyPress-Return>'' and
''<KeyPress-KP_Enter>'' events.

~ Specification

The solution that has been chosen supports the greatest possible
backward compatibility.  What is proposed is that 'tkWinX.c' will
examine the ''KF_EXTENDED'' bit in the keyboard state (passed as
''lParam'' to the ''GetState'' function) and map it as modifier
4. (Modifiers 1 through 3, respectively, refer to the ''Num Lock'',
''Alt'', and ''Scroll Lock'' keys.)  An alias shall be added so
that ''Extended'' may be used in place of ''Mod4''.

This change has little if any impact on existing Windows code, since
modifier 4 is not generated on Windows today.  A binding to
''<Return>'' will continue to fire for the numeric ''Enter'' key,
unless there is also a binding to ''<Extended-Return>'' which will then
take precedence.

Existing Unix code that binds ''<Return>'' and ''<KP_Enter>''
to identical functionality (and does not bind ''<Mod4-Return>'') will
also not need to change.  Again, the existing ''<Return>'' binding
will fire for the ''Enter'' keys on both the main keyboard and the
numeric pad.

Unix code that has distinct bindings for ''<Return>'' and
''<KP_Enter>'' does not function correctly on Windows today - and
cannot be made to do so without changing its specification.  To port
such code to Windows once this change is in place, a developer will
have to add bindings to ''<Extended-Return>'' that mirror those for
''<KP_Enter>''. Once the developer has done this, the application will
distinguish the two keys and fire the appropriate binding for each.

Although the immediate purpose of the change is to deal with the
numeric ''Enter'' key, the effect of the change will be to deal with
the rest of the numeric pad the same way; rather than generating
events such as ''<KeyPress-KP_0>'' or ''<Keypress-KP_Multiply>'',
the system will generate events representing the corresponding
keys on the main keyboard, with modifier 4 set to distinguish
them.  These events are less likely to need to be rebound, since
they correspond to printing characters and seldom if ever have
different bindings between the numeric pad and the main keyboard.

~ Reference Implementation

The changes require to implement an earlier version of this
proposal can be obtained from SourceForge as Tk Patch #797404.

~ Summary of Discussion

This change has been discussed extensively on the tcl-core mailing
list ([http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/1791694]
and several following threads) and the comp.lang.tcl newsgroup
[http://groups.google.com/[email protected]].

The chief proposed alternative to the use of modifier 4 was to modify
''tkWinX.c'' so that the ''Enter'' key on the numeric pad would
generate the same ''<KP_Enter>'' event that it does on Unix.  The
drawback to this proposal, making it unacceptable to the authors of
this TIP, is that existing user code on Windows that establishes
bindings to ''<Return>'' but not ''<KP_Enter>'' would no longer
recognize the numeric ''Enter'' key.  This problem was seen as a far
greater drawback than the need for those porting Unix applications
(and wishing to continue to operate inconsistently with the Microsoft
guidelines) to add an additional binding, particularly in light of the
fact that those applications today can't implement the desired
functionality on Windows at all.

One proposed workaround was to have a default ''all'' binding for
''<KP_*>'' events on Windows fire the corresponding binding for
a non-''KP'' keysym.  Unfortunately, this solution introduces even
worse surprising behavior.  A conventional binding to the KP_*
keysym will have to include a '''break''' or '''return -code break'''
in order to avoid having this ''all'' binding fire - and making
it appear as if both keys had been pressed or released.

The open issue of what to do about the problem on the Macintosh
platform remains.  The authors of this TIP are too ignorant of
Macintosh programming to address it.

This proposal has engendered a fair amount of controversy, as
may be seen in the two threads of messages beginning from
[http://aspn.activestate.com/ASPN/Mail/Message/1811543] and
[http://aspn.activestate.com/ASPN/Mail/Message/1820298].

More recent additional discussion is archived at
[http://aspn.activestate.com/ASPN/Mail/Message/2032516].
Vince Darley summarizes it:

For example, there is
Benny's suggestion to your ''all'' counterexample that the counterexample
really contains a bug, since any key-binding ought to have ''';break''' to
prevent exactly that problem.  Do we guarantee backwards compatibility
even with buggy code?

Second there is the suggestion that if you really don't want the ''all''
binding to fire if another binding has triggered, you could actually check
for that manually (scan the bindtags list, etc).  This would reduce the
backwards incompatibility of an overall cleaner solution to effectively
nothing.

Third, the TIP contains no mention of what the result of this TIP is on
the x-platform Tk developer.  That they must now have this:

| bind ... <Return>  "pressReturn"
| bind ... <KP_Enter>  "pressEnter" ; # only useful on Unix
| bind ... <Extended-Return>  "pressEnter" ; # only useful on Windows

i.e. rather than making their life easier, it has been made more complex!
(In fact the TIP as a whole seems to have a bias against anyone even
considering writing the same application on multiple platforms, which
seems v. odd for Tk)

~ Copyright

Copyright � 2003, 2004 by Kevin B. Kenny.  All rights reserved.

Permission to use this document in accordance with the terms of Open
Publication License [http://www.opencontent.org/openpub/] is herewith
granted.

<
|
<
|
|
|
|
|
|
|
|
|
>

|





|


|
|




|
|

|



|
|
|
|
|



|
|


|
|
|
|


|
|


|
|



|

|






|


|

|


|
|
|


|
|


|
|

|
|



|
|
|
|
|
|








|
|


|



|
|



|

|






|
|
|


|

|

|

|


|

>

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
136
137
138
139
140
141
142
143
144
145
146
147
148

# TIP 158: Distinguish the two 'Enter' keys on Windows

	Author:         Wolfgang Großbauer <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        20-Sep-2003
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes that the "extended keys" on a Windows keyboard be
labeled with <Mod4> so that they can be distinguished from their
counterparts on the main keyboard.

# Rationale

Most US keyboards on Windows systems have two keys bearing the label,
'Enter'.  The Tk system generates the events, _<KeyPress-Return>_
and _<KeyRelease-Return>_ for both of them; the two keys are
indistinguishable.  While this behavior is in keeping with the
"Microsoft Windows User Experience Guidelines," which explicitly state
that the two keys should command identical functionality, it is
inconvenient for developers who wish to port Unix applications that
already have different actions bound to the _<KeyPress-Return>_ and
_<KeyPress-KP\_Enter>_ events.

# Specification

The solution that has been chosen supports the greatest possible
backward compatibility.  What is proposed is that 'tkWinX.c' will
examine the _KF\_EXTENDED_ bit in the keyboard state \(passed as
_lParam_ to the _GetState_ function\) and map it as modifier
4. \(Modifiers 1 through 3, respectively, refer to the _Num Lock_,
_Alt_, and _Scroll Lock_ keys.\)  An alias shall be added so
that _Extended_ may be used in place of _Mod4_.

This change has little if any impact on existing Windows code, since
modifier 4 is not generated on Windows today.  A binding to
_<Return>_ will continue to fire for the numeric _Enter_ key,
unless there is also a binding to _<Extended-Return>_ which will then
take precedence.

Existing Unix code that binds _<Return>_ and _<KP\_Enter>_
to identical functionality \(and does not bind _<Mod4-Return>_\) will
also not need to change.  Again, the existing _<Return>_ binding
will fire for the _Enter_ keys on both the main keyboard and the
numeric pad.

Unix code that has distinct bindings for _<Return>_ and
_<KP\_Enter>_ does not function correctly on Windows today - and
cannot be made to do so without changing its specification.  To port
such code to Windows once this change is in place, a developer will
have to add bindings to _<Extended-Return>_ that mirror those for
_<KP\_Enter>_. Once the developer has done this, the application will
distinguish the two keys and fire the appropriate binding for each.

Although the immediate purpose of the change is to deal with the
numeric _Enter_ key, the effect of the change will be to deal with
the rest of the numeric pad the same way; rather than generating
events such as _<KeyPress-KP\_0>_ or _<Keypress-KP\_Multiply>_,
the system will generate events representing the corresponding
keys on the main keyboard, with modifier 4 set to distinguish
them.  These events are less likely to need to be rebound, since
they correspond to printing characters and seldom if ever have
different bindings between the numeric pad and the main keyboard.

# Reference Implementation

The changes require to implement an earlier version of this
proposal can be obtained from SourceForge as Tk Patch \#797404.

# Summary of Discussion

This change has been discussed extensively on the tcl-core mailing
list \(<http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/1791694> 
and several following threads\) and the comp.lang.tcl newsgroup
<http://groups.google.com/[email protected]> .

The chief proposed alternative to the use of modifier 4 was to modify
_tkWinX.c_ so that the _Enter_ key on the numeric pad would
generate the same _<KP\_Enter>_ event that it does on Unix.  The
drawback to this proposal, making it unacceptable to the authors of
this TIP, is that existing user code on Windows that establishes
bindings to _<Return>_ but not _<KP\_Enter>_ would no longer
recognize the numeric _Enter_ key.  This problem was seen as a far
greater drawback than the need for those porting Unix applications
\(and wishing to continue to operate inconsistently with the Microsoft
guidelines\) to add an additional binding, particularly in light of the
fact that those applications today can't implement the desired
functionality on Windows at all.

One proposed workaround was to have a default _all_ binding for
_<KP\_\*>_ events on Windows fire the corresponding binding for
a non-_KP_ keysym.  Unfortunately, this solution introduces even
worse surprising behavior.  A conventional binding to the KP\_\*
keysym will have to include a **break** or **return -code break**
in order to avoid having this _all_ binding fire - and making
it appear as if both keys had been pressed or released.

The open issue of what to do about the problem on the Macintosh
platform remains.  The authors of this TIP are too ignorant of
Macintosh programming to address it.

This proposal has engendered a fair amount of controversy, as
may be seen in the two threads of messages beginning from
<http://aspn.activestate.com/ASPN/Mail/Message/1811543>  and
<http://aspn.activestate.com/ASPN/Mail/Message/1820298> .

More recent additional discussion is archived at
<http://aspn.activestate.com/ASPN/Mail/Message/2032516> .
Vince Darley summarizes it:

For example, there is
Benny's suggestion to your _all_ counterexample that the counterexample
really contains a bug, since any key-binding ought to have **;break** to
prevent exactly that problem.  Do we guarantee backwards compatibility
even with buggy code?

Second there is the suggestion that if you really don't want the _all_
binding to fire if another binding has triggered, you could actually check
for that manually \(scan the bindtags list, etc\).  This would reduce the
backwards incompatibility of an overall cleaner solution to effectively
nothing.

Third, the TIP contains no mention of what the result of this TIP is on
the x-platform Tk developer.  That they must now have this:

	 bind ... <Return>  "pressReturn"
	 bind ... <KP_Enter>  "pressEnter" ; # only useful on Unix
	 bind ... <Extended-Return>  "pressEnter" ; # only useful on Windows

i.e. rather than making their life easier, it has been made more complex!
\(In fact the TIP as a whole seems to have a bias against anyone even
considering writing the same application on multiple platforms, which
seems v. odd for Tk\)

# Copyright

Copyright © 2003, 2004 by Kevin B. Kenny.  All rights reserved.

Permission to use this document in accordance with the terms of Open
Publication License <http://www.opencontent.org/openpub/>  is herewith
granted.

Name change from tip/159.tip to tip/159.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

TIP:		159
Title:		Extending Tk 'wm' Command to Support Coloured Icons
Version:	$Revision: 1.7 $
Author:		Georgios Petasis <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Tcl-Version:	8.5
Created:	01-Oct-2003
Post-History:	


~ Abstract

Currently, Tk lacks a mechanism for allowing scripts to place colour
icons in the window manager decorations of a toplevel window.  Tk
supports only the placement of monochrome bitmaps through the ''wm
iconbitmap'' and ''wm iconmask'' commands.  This TIP proposes an
extension of the ''wm'' command with the ''iconphoto'' subcommand,
which will pass a set of photo images as possible window manager
icons.


~ Rationale

Almost all modern window managers or desktop environments offer
support for using colour icons in toplevel window decorations.  Tk has
made some steps in this direction by allowing ''wm iconbitmap''
command to also accept a Windows icon file, to be used as an icon for
a toplevel under windows.  This solution is quite incomplete, and of
course works only under windows.  No support for colour icons under
Unix is currently offered and I (think) the same is also true for Mac
OS.

This TIP proposes the introduction of a new subcommand to the ''wm''
command, the ''iconphoto'' subcommand.  (''iconimage'' was an
alternative that I rejected because bitmaps are also considered images
by Tk).  This subcommand will accept a Tk window name and a set of
photo image names.  These images will then passed to the window
manager as possible window icons.

The ''wm iconphoto'' subcommand will be available under all platforms.
However, at this stage of development I will focus mainly on Unix: I
don't know anything about Mac OS (so others must help in this
direction) and support for windows already exists.  The final goal
will be to support at least windows and Unix.  There is currently a
patch that implements the Unix port of ''wm iconphoto''.

Currently, two different approaches are used by Unix applications to
specify colour icons.  The first approach uses the same mechanism as
''wm iconbitmap'' to pass the icon: instead of passing a monochrome
pixmap (that is a bitmap), they pass a colour pixmap with 3 planes (no
transparency).  This approach works with many modern window managers
(including the ones used by KDE and GNOME).  However, as Joe English
noted this approach violates the ICCCM, despite the fact that it is
used by some applications (i.e. gvim).

The second approach (again pointed by Joe English) is the one proposed
by freedesktop.org: The application defines a window property that
holds a special encoding of the colour icons.  I don't know exactly
how many window managers follow this proposal, but the window managers
in two popular desktops (KDE and GNOME) support it.  My proposal is of
course to follow the second approach, as it does not violate the
ICCCM.

The window property that should be defined is "_NET_WM_ICON".  From
the specifications [http://www.freedesktop.org/]:

 > _NET_WM_ICON

 > _NET_WM_ICON CARDINAL[][2+n]/32

 > This is an array of possible icons for the client.  This
   specification does not stipulate what size these icons should be,
   but individual desktop environments or toolkits may do so.  The
   Window Manager MAY scale any of these icons to an appropriate size.

 > This is an array of 32bit packed CARDINAL ARGB with high byte being
   A, low byte being B.  The first two cardinals are width, height.
   Data is in rows, left to right and top to bottom.

 > Currently both KDE and GNOME window managers scale the provided
   icons to proper sizes.

~ Specification

This document proposes the following changes to the Tk core:

 1. The addition of a new subcommand (''iconphoto'') to the ''wm''
    command.  This subcommand will accept the following arguments:
     
 > window: the name of a Tk toplevel window.

 > photo_image ?photo_image2 ...?: a set of Tk photo image names, that
   will be send to the window manager as potential icons.

Currently, no other facilities are planned (like for example getting
back the image names that are currently used as icons).

Also, no facilities are provided to request the window manager what
icon sizes are preferred, although Xlib offers a relevant function.

~ Reference Implementation

A reference implementation (initially for just Unix) is available
[http://sf.net/tracker/?func=detail&aid=815751&group_id=12997&atid=312997].

Note that also I have a reference implementation of the first approach
(passing a colour pixmap instead of a bitmap), in case we decide to
follow this approach (or both simultaneously :-) ).

~ Notes

I don't know if I have handled the assignment of the four bytes inside
the long correctly.  Currently the code works fine under Linux.  It
would be great if somebody could re-write the assignment to use
bit-shift operations :-)

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|



|
|
|




|



|



|


|
|

|



|

|
|

|



|
|
|
|

|

|



|



|
|

|

|













|



|


|

|


|
|




|

|
|


|
|

|




|

|


>

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

# TIP 159: Extending Tk 'wm' Command to Support Coloured Icons

	Author:		Georgios Petasis <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Tcl-Version:	8.5
	Created:	01-Oct-2003
	Post-History:	
-----

# Abstract

Currently, Tk lacks a mechanism for allowing scripts to place colour
icons in the window manager decorations of a toplevel window.  Tk
supports only the placement of monochrome bitmaps through the _wm
iconbitmap_ and _wm iconmask_ commands.  This TIP proposes an
extension of the _wm_ command with the _iconphoto_ subcommand,
which will pass a set of photo images as possible window manager
icons.


# Rationale

Almost all modern window managers or desktop environments offer
support for using colour icons in toplevel window decorations.  Tk has
made some steps in this direction by allowing _wm iconbitmap_
command to also accept a Windows icon file, to be used as an icon for
a toplevel under windows.  This solution is quite incomplete, and of
course works only under windows.  No support for colour icons under
Unix is currently offered and I \(think\) the same is also true for Mac
OS.

This TIP proposes the introduction of a new subcommand to the _wm_
command, the _iconphoto_ subcommand.  \(_iconimage_ was an
alternative that I rejected because bitmaps are also considered images
by Tk\).  This subcommand will accept a Tk window name and a set of
photo image names.  These images will then passed to the window
manager as possible window icons.

The _wm iconphoto_ subcommand will be available under all platforms.
However, at this stage of development I will focus mainly on Unix: I
don't know anything about Mac OS \(so others must help in this
direction\) and support for windows already exists.  The final goal
will be to support at least windows and Unix.  There is currently a
patch that implements the Unix port of _wm iconphoto_.

Currently, two different approaches are used by Unix applications to
specify colour icons.  The first approach uses the same mechanism as
_wm iconbitmap_ to pass the icon: instead of passing a monochrome
pixmap \(that is a bitmap\), they pass a colour pixmap with 3 planes \(no
transparency\).  This approach works with many modern window managers
\(including the ones used by KDE and GNOME\).  However, as Joe English
noted this approach violates the ICCCM, despite the fact that it is
used by some applications \(i.e. gvim\).

The second approach \(again pointed by Joe English\) is the one proposed
by freedesktop.org: The application defines a window property that
holds a special encoding of the colour icons.  I don't know exactly
how many window managers follow this proposal, but the window managers
in two popular desktops \(KDE and GNOME\) support it.  My proposal is of
course to follow the second approach, as it does not violate the
ICCCM.

The window property that should be defined is "\_NET\_WM\_ICON".  From
the specifications <http://www.freedesktop.org/> :

 > \_NET\_WM\_ICON

 > \_NET\_WM\_ICON CARDINAL[][2+n]/32

 > This is an array of possible icons for the client.  This
   specification does not stipulate what size these icons should be,
   but individual desktop environments or toolkits may do so.  The
   Window Manager MAY scale any of these icons to an appropriate size.

 > This is an array of 32bit packed CARDINAL ARGB with high byte being
   A, low byte being B.  The first two cardinals are width, height.
   Data is in rows, left to right and top to bottom.

 > Currently both KDE and GNOME window managers scale the provided
   icons to proper sizes.

# Specification

This document proposes the following changes to the Tk core:

 1. The addition of a new subcommand \(_iconphoto_\) to the _wm_
    command.  This subcommand will accept the following arguments:
     
	 > window: the name of a Tk toplevel window.

	 > photo\_image ?photo\_image2 ...?: a set of Tk photo image names, that
   will be send to the window manager as potential icons.

Currently, no other facilities are planned \(like for example getting
back the image names that are currently used as icons\).

Also, no facilities are provided to request the window manager what
icon sizes are preferred, although Xlib offers a relevant function.

# Reference Implementation

A reference implementation \(initially for just Unix\) is available
<http://sf.net/tracker/?func=detail&aid=815751&group_id=12997&atid=312997> .

Note that also I have a reference implementation of the first approach
\(passing a colour pixmap instead of a bitmap\), in case we decide to
follow this approach \(or both simultaneously :-\) \).

# Notes

I don't know if I have handled the assignment of the four bytes inside
the long correctly.  Currently the code works fine under Linux.  It
would be great if somebody could re-write the assignment to use
bit-shift operations :-\)

# Copyright

This document has been placed in the public domain.

Name change from tip/16.tip to tip/16.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
TIP:            16
Title:          Tcl Functional Areas for Maintainer Assignments
Version:        $Revision: 1.48 $
Author:         Don Porter <[email protected]>
Author:         Daniel Steffen <[email protected]>
State:          Accepted
Type:           Process
Vote:           Done
Created:        21-Nov-2000
Post-History:   


~ Abstract

This document proposes a division of Tcl's source code into
functional areas so that each area may be assigned to one or
more maintainers.

~ Background

TCT procedures (see [0]) call for each ''maintainer'' to be
responsible for a portion of Tcl's source code.  Certain
portions of Tcl's source code are naturally associated with
certain other portions.  (For example, the implementation of
a command is intimately related to the documentation for that
command.)  Establishing a ''natural'' division of Tcl's source
code into units needing maintainers is a useful preliminary
effort toward a public call for volunteer maintainers.

See [24] for the mapping of these functional areas to maintainers.

~ Rationale

When someone reports a bug, or offers a patch, he will want to
be able to determine what maintainers have oversight over his
report.  This implies that we seek a simple mapping from something
he knows about his bug or patch to the set of maintainers.

For a patch, the submitter certainly knows what file(s) she is 
patching.  For a bug report, the reporter is likely to know what
command or C function he believes to be buggy.  Fortunately, every
C function or Tcl command (combined with the platform) can be associated
with exactly one source code file, the file providing the definition
of the C function, or the command procedure of the Tcl command.
Thus, a mapping from source code file to maintainer is sufficient
to complete the determination.

The source code file should not be the largest unit, however.
Certain sets of files should each be gathered into a larger unit,
all files in that unit with the same maintainer(s).  Tcl's man pages
already gather related routines and commands into one page of
documentation.  Using the modules implied by the man pages, and by
the location of routines in particular source code files, a ''natural''
division of Tcl into minimal maintainer units follows in the Proposal
section below.

It may be that some of these minimal units can be joined together
into still larger related units.  That is not necessary, though.
We can just have the same maintainer(s) assigned to all the related
minimal units.

~ Functional Areas

Tcl shall be divided into the following functional units, each to be
assigned one or more maintainers:

~~ Events

 1. '''Notifier''' - doc/CrtFileHdlr.3,
     doc/DoOneEvent.3,
     doc/Notifier.3,
     doc/Sleep.3,
     generic/tclNotify.c,
     macosx/tclMacOSXNotify.c,
     tests/notify.test,
     tests/unixNotfy.test,
     tests/winNotify.test,
     unix/tclUnixNotfy.c,
     unix/tclUnixEvent.c,
     win/tclWinNotify.c

 2. '''Event Loops''' - doc/bgerror.n,
     doc/update.n,
     doc/vwait.n,
     doc/BackgdErr.3,
     doc/Exit.3,
     generic/tclEvent.c,
     tests/event.test

 3. '''Timer Events''' - doc/after.n,
     doc/CrtTimerHdlr.3,
     doc/DoWhenIdle.3,
     generic/tclTimer.c,
     tests/timer.test

 4. '''Asynchronous Events''' - doc/Async.3,
     generic/tclAsync.c,
     tests/async.test

 5. '''Xt Based Notifier''' - unix/tclXtNotify.c,
     unix/tclXtTest.c

 6. '''Time Measurement''' - compat/gettod.c,
     compat/strftime.c,
     doc/clock.n,
     generic/tclClock.c,
     generic/tclGetDate.y,
     library/tzdata/*,
     tests/clock.test,
     tests/winTime.test,
     tools/loadICU.tcl,
     tools/makeTestCases.tcl,
     tools/tclZIC.tcl,
     unix/tclUnixTime.c,
     win/tclWinTime.c

~~ Variables

 7. '''Variable Commands and Interfaces''' - doc/append.n,
     doc/array.n,
     doc/global.n,
     doc/lappend.n,
     doc/lset.n,
     doc/set.n,
     doc/unset.n,
     doc/upvar.n,
     doc/variable.n,
     doc/SetVar.3,
     doc/UpVar.3,
     generic/tclVar.c,
     tests/append.test,
     tests/lset.test,
     tests/set.test,
     tests/set-old.test,
     tests/upvar.test,
     tests/var.test

 8. '''Environment Variables''' - doc/Environment.3,
     generic/tclEnv.c,
     tests/env.test

 9. '''Linked C Variables''' - doc/LinkVar.3,
     generic/tclLink.c,
     tests/link.test

~~ Objects

 10. '''Object System and Fundamental Object Types''' - doc/Backslash.3,
     doc/BoolObj.3,
     doc/Concat.3,
     doc/DoubleObj.3,
     doc/DString.3,
     doc/Encoding.3,
     doc/FindExec.3,
     doc/Hash.3,
     doc/IntObj.3,
     doc/Object.3,
     doc/ObjectType.3,
     doc/PrintDbl.3,
     doc/SplitList.3,
     doc/StringObj.3,
     doc/StrMatch.3,
     generic/tclEncoding.c,
     generic/tclHash.c,
     generic/tclObj.c,
     generic/tclStringObj.c,
     generic/tclUtil.c,
     library/encoding/*.enc,
     tools/encoding/*,
     tests/dstring.test,
     tests/encoding.test,
     tests/stringObj.test,
     tests/obj.test,
     tests/util.test

 11. '''Conversions From String''' - doc/GetInt.3,
     generic/tclGet.c,
     tests/get.test

 12. '''bytearray Object Type''' - doc/binary.n,
     doc/ByteArrObj.3,
     generic/tclBinary.c,
     tests/binary.test

 13. '''index Object Type''' - doc/GetIndex.3,
     doc/WrongNumArgs.3,
     generic/tclIndexObj.c,
     tests/indexObj.test

 14. '''list Object Type''' - doc/ListObj.3,
     generic/tclListObj.c,
     tests/listObj.test

 15. '''dict Object Type''' - doc/DictObj.3,
     doc/dict.n,
     generic/tclDictObj.c,
     tests/dict.test

~~ Fundamental Built-in Commands

 16. '''A - H''' - doc/break.n,
     doc/case.n,
     doc/catch.n,
     doc/cd.n,
     doc/concat.n,
     doc/continue.n,
     doc/encoding.n,
     doc/error.n,
<
|
<
|
|
|
|
|
|
|
>

|





|

|


|

|



|

|






|


|







|


|





|


|




|

|












|







|





|



|


|




|








|

|


















|



|



|

|



















|
|






|



|




|




|



|




|

|








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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206

# TIP 16: Tcl Functional Areas for Maintainer Assignments

	Author:         Don Porter <[email protected]>
	Author:         Daniel Steffen <[email protected]>
	State:          Accepted
	Type:           Process
	Vote:           Done
	Created:        21-Nov-2000
	Post-History:   
-----

# Abstract

This document proposes a division of Tcl's source code into
functional areas so that each area may be assigned to one or
more maintainers.

# Background

TCT procedures \(see [[0]](0.md)\) call for each _maintainer_ to be
responsible for a portion of Tcl's source code.  Certain
portions of Tcl's source code are naturally associated with
certain other portions.  \(For example, the implementation of
a command is intimately related to the documentation for that
command.\)  Establishing a _natural_ division of Tcl's source
code into units needing maintainers is a useful preliminary
effort toward a public call for volunteer maintainers.

See [[24]](24.md) for the mapping of these functional areas to maintainers.

# Rationale

When someone reports a bug, or offers a patch, he will want to
be able to determine what maintainers have oversight over his
report.  This implies that we seek a simple mapping from something
he knows about his bug or patch to the set of maintainers.

For a patch, the submitter certainly knows what file\(s\) she is 
patching.  For a bug report, the reporter is likely to know what
command or C function he believes to be buggy.  Fortunately, every
C function or Tcl command \(combined with the platform\) can be associated
with exactly one source code file, the file providing the definition
of the C function, or the command procedure of the Tcl command.
Thus, a mapping from source code file to maintainer is sufficient
to complete the determination.

The source code file should not be the largest unit, however.
Certain sets of files should each be gathered into a larger unit,
all files in that unit with the same maintainer\(s\).  Tcl's man pages
already gather related routines and commands into one page of
documentation.  Using the modules implied by the man pages, and by
the location of routines in particular source code files, a _natural_
division of Tcl into minimal maintainer units follows in the Proposal
section below.

It may be that some of these minimal units can be joined together
into still larger related units.  That is not necessary, though.
We can just have the same maintainer\(s\) assigned to all the related
minimal units.

# Functional Areas

Tcl shall be divided into the following functional units, each to be
assigned one or more maintainers:

## Events

 1. **Notifier** - doc/CrtFileHdlr.3,
     doc/DoOneEvent.3,
     doc/Notifier.3,
     doc/Sleep.3,
     generic/tclNotify.c,
     macosx/tclMacOSXNotify.c,
     tests/notify.test,
     tests/unixNotfy.test,
     tests/winNotify.test,
     unix/tclUnixNotfy.c,
     unix/tclUnixEvent.c,
     win/tclWinNotify.c

 2. **Event Loops** - doc/bgerror.n,
     doc/update.n,
     doc/vwait.n,
     doc/BackgdErr.3,
     doc/Exit.3,
     generic/tclEvent.c,
     tests/event.test

 3. **Timer Events** - doc/after.n,
     doc/CrtTimerHdlr.3,
     doc/DoWhenIdle.3,
     generic/tclTimer.c,
     tests/timer.test

 4. **Asynchronous Events** - doc/Async.3,
     generic/tclAsync.c,
     tests/async.test

 5. **Xt Based Notifier** - unix/tclXtNotify.c,
     unix/tclXtTest.c

 6. **Time Measurement** - compat/gettod.c,
     compat/strftime.c,
     doc/clock.n,
     generic/tclClock.c,
     generic/tclGetDate.y,
     library/tzdata/\*,
     tests/clock.test,
     tests/winTime.test,
     tools/loadICU.tcl,
     tools/makeTestCases.tcl,
     tools/tclZIC.tcl,
     unix/tclUnixTime.c,
     win/tclWinTime.c

## Variables

 7. **Variable Commands and Interfaces** - doc/append.n,
     doc/array.n,
     doc/global.n,
     doc/lappend.n,
     doc/lset.n,
     doc/set.n,
     doc/unset.n,
     doc/upvar.n,
     doc/variable.n,
     doc/SetVar.3,
     doc/UpVar.3,
     generic/tclVar.c,
     tests/append.test,
     tests/lset.test,
     tests/set.test,
     tests/set-old.test,
     tests/upvar.test,
     tests/var.test

 8. **Environment Variables** - doc/Environment.3,
     generic/tclEnv.c,
     tests/env.test

 9. **Linked C Variables** - doc/LinkVar.3,
     generic/tclLink.c,
     tests/link.test

## Objects

 10. **Object System and Fundamental Object Types** - doc/Backslash.3,
     doc/BoolObj.3,
     doc/Concat.3,
     doc/DoubleObj.3,
     doc/DString.3,
     doc/Encoding.3,
     doc/FindExec.3,
     doc/Hash.3,
     doc/IntObj.3,
     doc/Object.3,
     doc/ObjectType.3,
     doc/PrintDbl.3,
     doc/SplitList.3,
     doc/StringObj.3,
     doc/StrMatch.3,
     generic/tclEncoding.c,
     generic/tclHash.c,
     generic/tclObj.c,
     generic/tclStringObj.c,
     generic/tclUtil.c,
     library/encoding/\*.enc,
     tools/encoding/\*,
     tests/dstring.test,
     tests/encoding.test,
     tests/stringObj.test,
     tests/obj.test,
     tests/util.test

 11. **Conversions From String** - doc/GetInt.3,
     generic/tclGet.c,
     tests/get.test

 12. **bytearray Object Type** - doc/binary.n,
     doc/ByteArrObj.3,
     generic/tclBinary.c,
     tests/binary.test

 13. **index Object Type** - doc/GetIndex.3,
     doc/WrongNumArgs.3,
     generic/tclIndexObj.c,
     tests/indexObj.test

 14. **list Object Type** - doc/ListObj.3,
     generic/tclListObj.c,
     tests/listObj.test

 15. **dict Object Type** - doc/DictObj.3,
     doc/dict.n,
     generic/tclDictObj.c,
     tests/dict.test

## Fundamental Built-in Commands

 16. **A - H** - doc/break.n,
     doc/case.n,
     doc/catch.n,
     doc/cd.n,
     doc/concat.n,
     doc/continue.n,
     doc/encoding.n,
     doc/error.n,
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
     tests/concat.test,
     tests/error.test,
     tests/eval.test,
     tests/foreach.test,
     tests/format.test,
     tests/for-old.test

 17. '''I - L''' - doc/if.n,
     doc/incr.n,
     doc/info.n,
     doc/join.n,
     doc/lindex.n,
     doc/linsert.n,
     doc/list.n,
     doc/llength.n,







|







217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
     tests/concat.test,
     tests/error.test,
     tests/eval.test,
     tests/foreach.test,
     tests/format.test,
     tests/for-old.test

 17. **I - L** - doc/if.n,
     doc/incr.n,
     doc/info.n,
     doc/join.n,
     doc/lindex.n,
     doc/linsert.n,
     doc/list.n,
     doc/llength.n,
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
     tests/linsert.test,
     tests/list.test,
     tests/llength.test,
     tests/lrange.test,
     tests/lreplace.test,
     tests/lsearch.test

 18. '''M - Z''' - 
     doc/pwd.n,
     doc/regexp.n,
     doc/regsub.n,
     doc/rename.n,
     doc/return.n,
     doc/split.n,
     doc/string.n,







|







243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
     tests/linsert.test,
     tests/list.test,
     tests/llength.test,
     tests/lrange.test,
     tests/lreplace.test,
     tests/lsearch.test

 18. **M - Z** - 
     doc/pwd.n,
     doc/regexp.n,
     doc/regsub.n,
     doc/rename.n,
     doc/return.n,
     doc/split.n,
     doc/string.n,
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
     tests/rename.test,
     tests/split.test,
     tests/string.test,
     tests/subst.test,
     tests/switch.test,
     tests/while-old.test

 19. '''[[history]]''' - doc/history.n,
     doc/RecEvalObj.3,
     doc/RecordEval.3,
     generic/tclHistory.c,
     library/history.tcl,
     tests/history.test

 20. '''[[interp]]''' - doc/interp.n,
     doc/CrtSlave.3,
     doc/Limit.3,
     generic/tclInterp.c,
     tests/interp.test

 21. '''[[namespace]]''' -
     doc/Namespace.3,
     doc/namespace.n,
     generic/tclEnsemble.c,
     generic/tclNamesp.c,
     generic/tclResolve.c,
     tests/namespace.test,
     tests/namespace-old.test

 22. '''[[proc]]''' - doc/proc.n,
     doc/uplevel.n,
     generic/tclProc.c,
     generic/tclTestProcBodyObj.c,
     tests/proc.test,
     tests/proc-old.test,
     tests/uplevel.test

 23. '''[[scan]]''' - doc/scan.n,
     generic/tclScan.c,
     tests/scan.test

~~ Channels

 24. '''Channel Commands''' - doc/close.n,
     doc/eof.n,
     doc/exec.n,
     doc/fblocked.n,
     doc/fconfigure.n,
     doc/fcopy.n,
     doc/flush.n,
     doc/gets.n,
     doc/open.n,
     doc/puts.n,
     doc/read.n,
     doc/seek.n,
     doc/socket.n,
     doc/tell.n,
     generic/tclIOCmd.c,
     tests/exec.test,
     tests/ioCmd.test,
     tests/remote.tcl,
     tests/socket.test

 25. '''Channel System''' - doc/chan.n,
     doc/fileevent.n,
     doc/ChnlStack.3,
     doc/CrtChnlHdlr.3,
     doc/CrtCloseHdlr.3,
     doc/CrtChannel.3,
     doc/DetachPids.3,
     doc/GetStdChan.3,
     doc/OpenFileChnl.3,
     doc/StdChannels.3
     generic/tclIO.c,
     generic/tclIO.h,
     generic/tclPipe.c,
     tests/chan.test,
     tests/chanio.test,
     tests/io.test

 26. '''Channel Transformations''' - generic/tclIOGT.c,
     generic/tclIORTrans.c,
     tests/iogt.test,
     tests/ioTrans.test

 27. '''Built-in Channel Types''' - compat/waitpid.c,
     doc/GetHostName.3,
     doc/GetOpnFl.3,
     doc/OpenTcp.3,
     doc/pid.n,
     generic/tclIOSock.c,
     generic/tclIORChan.c,
     tests/pid.test,
     tests/winConsole.test,
     tests/winPipe.test,
     unix/tclUnixChan.c,
     unix/tclUnixPipe.c,
     unix/tclUnixSock.c,
     win/cat.c,
     win/stub16.c,
     win/tclWinChan.c,
     win/tclWinConsole.c,
     win/tclWinPipe.c,
     win/tclWinSerial.c,
     win/tclWinSock.c

~~ Packages

 28. '''dde Package''' - doc/dde.n,
     library/dde/pkgIndex.tcl,
     tests/winDde.test
     win/tclWinDde.c

 29. '''http Package''' - doc/http.n,
     library/http1.0/http.tcl,
     library/http1.0/pkgIndex.tcl,
     library/http/http.tcl,
     library/http/pkgIndex.tcl,
     tests/http.test,
     tests/httpd,
     tests/httpold.test

 30. '''msgcat Package''' - doc/msgcat.n,
     library/msgcat/msgcat.tcl,
     library/msgcat/pkgIndex.tcl,
     tests/msgcat.test

 31. '''opt Package''' - library/opt/optparse.tcl,
     library/opt/pkgIndex.tcl,
     tests/opt.test

 32. '''registry Package''' - doc/registry.n,
     library/reg/pkgIndex.tcl,
     win/tclWinReg.c,
     tests/registry.test

 33. '''Safe Base''' - doc/safe.n,
     library/safe.tcl,
     tests/safe.test

 34. '''tcltest Package''' - doc/tcltest.tcl,
     library/tcltest/tcltest.tcl,
     library/tcltest/pkgIndex.tcl,
     tests/tcltest.test

 35. '''TclOO Package''' (see [257]) -
     doc/Class.3,
     doc/Method.3,
     doc/class.n,
     doc/copy.n,
     doc/define.n,
     doc/my.n,
     doc/next.n,
     doc/object.n,
     doc/self.n,
     generic/tclOO.c,
     generic/tclOO.decls,
     generic/tclOO.h,
     generic/tclOOBasic.c,
     generic/tclOOCall.c,
     generic/tclOODefineCmds.c,
     generic/tclOOInfo.c,
     generic/tclOOInt.h,
     generic/tclOOMethod.c,
     tests/oo.test

~~ File System

 36. '''Pathname Management''' - doc/filename.n,
     doc/glob.n,
     doc/FileSystem.3,
     doc/SplitPath.3,
     doc/Translate.3,
     generic/tclFileName.c,
     tests/fileName.test,
     tests/unixFile.test,
     tests/winFile.test,
     unix/tclUnixFile.c,
     win/tclWinFile.c

 37. '''File System Access''' - doc/Access.3,
     doc/GetCwd.3,
     doc/SetErrno.3,
     doc/Signal.3,
     generic/tclFCmd.c,
     generic/tclIOUtil.c,
     generic/tclPathObj.c,
     generic/tclPosixStr.c,
     macosx/tclMacOSXFCmd.c,
     tests/fCmd.test,
     tests/ioUtil.test,
     tests/unixFCmd.test,
     tests/winFCmd.test,
     unix/tclUnixFCmd.c,
     win/tclWinError.c,
     win/tclWinFCmd.c

~~ Initialization, Script Library, and Autoloader

 38. doc/library.n,
     doc/tclvars.n,
     doc/unknown.n,
     doc/Init.3,
     doc/SourceRCFile.3,
     generic/tclInitScript.h,







|






|





|








|







|



|

|



















|
















|




|




















|

|




|








|




|



|




|



|




|




















|

|











|
















|







267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
     tests/rename.test,
     tests/split.test,
     tests/string.test,
     tests/subst.test,
     tests/switch.test,
     tests/while-old.test

 19. **[history]** - doc/history.n,
     doc/RecEvalObj.3,
     doc/RecordEval.3,
     generic/tclHistory.c,
     library/history.tcl,
     tests/history.test

 20. **[interp]** - doc/interp.n,
     doc/CrtSlave.3,
     doc/Limit.3,
     generic/tclInterp.c,
     tests/interp.test

 21. **[namespace]** -
     doc/Namespace.3,
     doc/namespace.n,
     generic/tclEnsemble.c,
     generic/tclNamesp.c,
     generic/tclResolve.c,
     tests/namespace.test,
     tests/namespace-old.test

 22. **[proc]** - doc/proc.n,
     doc/uplevel.n,
     generic/tclProc.c,
     generic/tclTestProcBodyObj.c,
     tests/proc.test,
     tests/proc-old.test,
     tests/uplevel.test

 23. **[scan]** - doc/scan.n,
     generic/tclScan.c,
     tests/scan.test

## Channels

 24. **Channel Commands** - doc/close.n,
     doc/eof.n,
     doc/exec.n,
     doc/fblocked.n,
     doc/fconfigure.n,
     doc/fcopy.n,
     doc/flush.n,
     doc/gets.n,
     doc/open.n,
     doc/puts.n,
     doc/read.n,
     doc/seek.n,
     doc/socket.n,
     doc/tell.n,
     generic/tclIOCmd.c,
     tests/exec.test,
     tests/ioCmd.test,
     tests/remote.tcl,
     tests/socket.test

 25. **Channel System** - doc/chan.n,
     doc/fileevent.n,
     doc/ChnlStack.3,
     doc/CrtChnlHdlr.3,
     doc/CrtCloseHdlr.3,
     doc/CrtChannel.3,
     doc/DetachPids.3,
     doc/GetStdChan.3,
     doc/OpenFileChnl.3,
     doc/StdChannels.3
     generic/tclIO.c,
     generic/tclIO.h,
     generic/tclPipe.c,
     tests/chan.test,
     tests/chanio.test,
     tests/io.test

 26. **Channel Transformations** - generic/tclIOGT.c,
     generic/tclIORTrans.c,
     tests/iogt.test,
     tests/ioTrans.test

 27. **Built-in Channel Types** - compat/waitpid.c,
     doc/GetHostName.3,
     doc/GetOpnFl.3,
     doc/OpenTcp.3,
     doc/pid.n,
     generic/tclIOSock.c,
     generic/tclIORChan.c,
     tests/pid.test,
     tests/winConsole.test,
     tests/winPipe.test,
     unix/tclUnixChan.c,
     unix/tclUnixPipe.c,
     unix/tclUnixSock.c,
     win/cat.c,
     win/stub16.c,
     win/tclWinChan.c,
     win/tclWinConsole.c,
     win/tclWinPipe.c,
     win/tclWinSerial.c,
     win/tclWinSock.c

## Packages

 28. **dde Package** - doc/dde.n,
     library/dde/pkgIndex.tcl,
     tests/winDde.test
     win/tclWinDde.c

 29. **http Package** - doc/http.n,
     library/http1.0/http.tcl,
     library/http1.0/pkgIndex.tcl,
     library/http/http.tcl,
     library/http/pkgIndex.tcl,
     tests/http.test,
     tests/httpd,
     tests/httpold.test

 30. **msgcat Package** - doc/msgcat.n,
     library/msgcat/msgcat.tcl,
     library/msgcat/pkgIndex.tcl,
     tests/msgcat.test

 31. **opt Package** - library/opt/optparse.tcl,
     library/opt/pkgIndex.tcl,
     tests/opt.test

 32. **registry Package** - doc/registry.n,
     library/reg/pkgIndex.tcl,
     win/tclWinReg.c,
     tests/registry.test

 33. **Safe Base** - doc/safe.n,
     library/safe.tcl,
     tests/safe.test

 34. **tcltest Package** - doc/tcltest.tcl,
     library/tcltest/tcltest.tcl,
     library/tcltest/pkgIndex.tcl,
     tests/tcltest.test

 35. **TclOO Package** \(see [[257]](257.md)\) -
     doc/Class.3,
     doc/Method.3,
     doc/class.n,
     doc/copy.n,
     doc/define.n,
     doc/my.n,
     doc/next.n,
     doc/object.n,
     doc/self.n,
     generic/tclOO.c,
     generic/tclOO.decls,
     generic/tclOO.h,
     generic/tclOOBasic.c,
     generic/tclOOCall.c,
     generic/tclOODefineCmds.c,
     generic/tclOOInfo.c,
     generic/tclOOInt.h,
     generic/tclOOMethod.c,
     tests/oo.test

## File System

 36. **Pathname Management** - doc/filename.n,
     doc/glob.n,
     doc/FileSystem.3,
     doc/SplitPath.3,
     doc/Translate.3,
     generic/tclFileName.c,
     tests/fileName.test,
     tests/unixFile.test,
     tests/winFile.test,
     unix/tclUnixFile.c,
     win/tclWinFile.c

 37. **File System Access** - doc/Access.3,
     doc/GetCwd.3,
     doc/SetErrno.3,
     doc/Signal.3,
     generic/tclFCmd.c,
     generic/tclIOUtil.c,
     generic/tclPathObj.c,
     generic/tclPosixStr.c,
     macosx/tclMacOSXFCmd.c,
     tests/fCmd.test,
     tests/ioUtil.test,
     tests/unixFCmd.test,
     tests/winFCmd.test,
     unix/tclUnixFCmd.c,
     win/tclWinError.c,
     win/tclWinFCmd.c

## Initialization, Script Library, and Autoloader

 38. doc/library.n,
     doc/tclvars.n,
     doc/unknown.n,
     doc/Init.3,
     doc/SourceRCFile.3,
     generic/tclInitScript.h,
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
     tests/platform.test,
     tests/security.test,
     tests/unixInit.test,
     tests/unknown.test,
     unix/tclUnixInit.c,
     win/tclWinInit.c

~~ Package Support

 39. '''Package Management''' - doc/InitStubs.3,
     doc/package.n,
     doc/packagens.n,
     doc/pkgMkIndex.n,
     doc/PkgRequire.3,
     doc/tm.n,
     generic/tclPkg.c,
     generic/tclStubLib.c,
     library/package.tcl,
     library/tm.tcl,
     tests/package.test,
     tests/pkg.test,
     tests/pkgMkIndex.test,
     tests/pkg/*.tcl,
     tests/tm.test

 40. '''Dynamic Loading''' - compat/dlfcn.h,
     doc/load.n,
     doc/StaticPkg.3,
     generic/tclLoad.c,
     generic/tclLoadNone.c,
     library/ldAout.tcl,
     tests/load.test,
     unix/dltest/*,
     unix/tclLoad*.c,
     win/tclWinLoad.c

~~ Memory Management

 41. '''Allocation''' - doc/memory.n,
     doc/Alloc.3,
     doc/TCL_MEM_DEBUG.3,
     doc/DumpActiveMemory.3,
     generic/tclAlloc.c,
     generic/tclCkalloc.c,
     generic/tclThreadAlloc.c

 42. '''Preservation''' - doc/Preserve.3,
     generic/tclPreserve.c

~~ Regular Expressions

 43. doc/re_syntax.n,
     doc/RegExp.3,
     generic/regc_color.c,
     generic/regc_cvec.c,
     generic/regc_lex.c,
     generic/regc_locale.c,
     generic/regc_nfa.c,
     generic/regcomp.c,
     generic/regcustom.h,
     generic/rege_dfa.c,
     generic/regerror.c,
     generic/regerrs.h,
     generic/regex.h,
     generic/regexec.c,
     generic/regfree.c,
     generic/regfronts.c,
     generic/regguts.h,
     generic/tclRegexp.c,
     generic/tclRegexp.h,
     tests/reg.test,
     tests/regexp.test,
     tools/uniClass.tcl

~~ UTF-8 String Management

 44. doc/ToUpper.3,
     doc/UniCharIsAlpha.3,
     doc/Utf.3,
     generic/tclUtf.c,
     tools/uniParse.tcl,
     tests/utf.test,
     win/tclWin32Dll.c

~~ Fundamentals

 45. '''Parsing and Evaluation''' - doc/AddErrInfo.3,
     doc/AllowExc.3,
     doc/AssocData.3,
     doc/CallDel.3,
     doc/CmdCmplt.3,
     doc/CrtCommand.3,
     doc/CrtObjCmd.3,
     doc/CrtInterp.3,







|

|












|


|






|
|


|

|

|





|


|

|

|
|
|
|
|


|













|









|

|







480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
     tests/platform.test,
     tests/security.test,
     tests/unixInit.test,
     tests/unknown.test,
     unix/tclUnixInit.c,
     win/tclWinInit.c

## Package Support

 39. **Package Management** - doc/InitStubs.3,
     doc/package.n,
     doc/packagens.n,
     doc/pkgMkIndex.n,
     doc/PkgRequire.3,
     doc/tm.n,
     generic/tclPkg.c,
     generic/tclStubLib.c,
     library/package.tcl,
     library/tm.tcl,
     tests/package.test,
     tests/pkg.test,
     tests/pkgMkIndex.test,
     tests/pkg/\*.tcl,
     tests/tm.test

 40. **Dynamic Loading** - compat/dlfcn.h,
     doc/load.n,
     doc/StaticPkg.3,
     generic/tclLoad.c,
     generic/tclLoadNone.c,
     library/ldAout.tcl,
     tests/load.test,
     unix/dltest/\*,
     unix/tclLoad\*.c,
     win/tclWinLoad.c

## Memory Management

 41. **Allocation** - doc/memory.n,
     doc/Alloc.3,
     doc/TCL\_MEM\_DEBUG.3,
     doc/DumpActiveMemory.3,
     generic/tclAlloc.c,
     generic/tclCkalloc.c,
     generic/tclThreadAlloc.c

 42. **Preservation** - doc/Preserve.3,
     generic/tclPreserve.c

## Regular Expressions

 43. doc/re\_syntax.n,
     doc/RegExp.3,
     generic/regc\_color.c,
     generic/regc\_cvec.c,
     generic/regc\_lex.c,
     generic/regc\_locale.c,
     generic/regc\_nfa.c,
     generic/regcomp.c,
     generic/regcustom.h,
     generic/rege\_dfa.c,
     generic/regerror.c,
     generic/regerrs.h,
     generic/regex.h,
     generic/regexec.c,
     generic/regfree.c,
     generic/regfronts.c,
     generic/regguts.h,
     generic/tclRegexp.c,
     generic/tclRegexp.h,
     tests/reg.test,
     tests/regexp.test,
     tools/uniClass.tcl

## UTF-8 String Management

 44. doc/ToUpper.3,
     doc/UniCharIsAlpha.3,
     doc/Utf.3,
     generic/tclUtf.c,
     tools/uniParse.tcl,
     tests/utf.test,
     win/tclWin32Dll.c

## Fundamentals

 45. **Parsing and Evaluation** - doc/AddErrInfo.3,
     doc/AllowExc.3,
     doc/AssocData.3,
     doc/CallDel.3,
     doc/CmdCmplt.3,
     doc/CrtCommand.3,
     doc/CrtObjCmd.3,
     doc/CrtInterp.3,
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
     tests/expr-old.test,
     tests/parse.test,
     tests/parseExpr.test,
     tests/parseOld.test,
     tests/result.test,
     tests/stack.test

 46. '''Traces''' -
     doc/TraceVar.3,
     doc/TraceCmd.3,
     doc/trace.n,
     doc/CrtTrace.3,
     generic/tclTrace.c,
     tests/trace.test

 47. '''Bytecode Compiler''' - compat/float.h,
     generic/tclAssembly.c,
     generic/tclCompCmds.c,
     generic/tclCompCmdsSZ.c,
     generic/tclCompExpr.c,
     generic/tclCompile.c,
     generic/tclCompile.h,
     generic/tclExecute.c,







|







|







594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
     tests/expr-old.test,
     tests/parse.test,
     tests/parseExpr.test,
     tests/parseOld.test,
     tests/result.test,
     tests/stack.test

 46. **Traces** -
     doc/TraceVar.3,
     doc/TraceCmd.3,
     doc/trace.n,
     doc/CrtTrace.3,
     generic/tclTrace.c,
     tests/trace.test

 47. **Bytecode Compiler** - compat/float.h,
     generic/tclAssembly.c,
     generic/tclCompCmds.c,
     generic/tclCompCmdsSZ.c,
     generic/tclCompExpr.c,
     generic/tclCompile.c,
     generic/tclCompile.h,
     generic/tclExecute.c,
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
     tests/if.test,
     tests/incr.test,
     tests/lsetComp.test,
     tests/regexpComp.test,
     tests/stringComp.test,
     tests/while.test

 48. '''Number Handling''' (see [237]) -
     generic/tclStrToD.c,
     generic/tclTomMath.h,
     generic/tclTomMathInterface.c,
     generic/tommath.h,
     libtommath/*

~~ Threads

 49. doc/Thread.3,
     generic/tclThread.c,
     generic/tclThreadJoin.c,
     generic/tclThreadStorage.c,
     generic/tclThreadTest.c,
     tests/thread.test,
     unix/tclUnixThrd.c,
     unix/tclUnixThrd.h,
     win/tclWinThrd.c,
     win/tclWinThrd.h

~~ Embedding Support

 50. doc/AppInit.3,
     doc/Tcl_Main.3,
     doc/Panic.3,
     doc/tclsh.1,
     generic/tclMain.c,
     generic/tclPanic.c,
     tests/main.test,
     unix/tclAppInit.c,
     win/tclAppInit.c

~~ Release Engineering

 51. '''Release Notes''' - README,
     changes,
     license.terms,
     */license.terms,
     compat/README,
     generic/README,
     macosx/README,
     tests/README,
     tests/pkg/license.terms,
     tools/README,
     unix/README,
     win/README

 52. '''Portability Support''' - compat/dirent.h,
     compat/dirent2.h,
     compat/limits.h,
     compat/fixstrtod.c,
     compat/memcmp.c,
     compat/opendir.c,
     compat/stdlib.h,
     compat/string.h,







|




|

|












|


|








|

|












|







627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
     tests/if.test,
     tests/incr.test,
     tests/lsetComp.test,
     tests/regexpComp.test,
     tests/stringComp.test,
     tests/while.test

 48. **Number Handling** \(see [[237]](237.md)\) -
     generic/tclStrToD.c,
     generic/tclTomMath.h,
     generic/tclTomMathInterface.c,
     generic/tommath.h,
     libtommath/\*

## Threads

 49. doc/Thread.3,
     generic/tclThread.c,
     generic/tclThreadJoin.c,
     generic/tclThreadStorage.c,
     generic/tclThreadTest.c,
     tests/thread.test,
     unix/tclUnixThrd.c,
     unix/tclUnixThrd.h,
     win/tclWinThrd.c,
     win/tclWinThrd.h

## Embedding Support

 50. doc/AppInit.3,
     doc/Tcl\_Main.3,
     doc/Panic.3,
     doc/tclsh.1,
     generic/tclMain.c,
     generic/tclPanic.c,
     tests/main.test,
     unix/tclAppInit.c,
     win/tclAppInit.c

## Release Engineering

 51. **Release Notes** - README,
     changes,
     license.terms,
     */license.terms,
     compat/README,
     generic/README,
     macosx/README,
     tests/README,
     tests/pkg/license.terms,
     tools/README,
     unix/README,
     win/README

 52. **Portability Support** - compat/dirent.h,
     compat/dirent2.h,
     compat/limits.h,
     compat/fixstrtod.c,
     compat/memcmp.c,
     compat/opendir.c,
     compat/stdlib.h,
     compat/string.h,
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
     generic/tclPort.h,
     unix/tclMtherr.c,
     unix/tclUnixPort.h,
     unix/tclUnixCompat.c,
     win/tclWinMtherr.c,
     win/tclWinPort.h

 53. '''Configuration and Build Tools''' - djgpp/Makefile,
     macosx/Makefile,
     macosx/Tcl.pbproj/project.pbxproj,
     tests/all.tcl,
     tools/configure.in,
     tools/eolFix.tcl,
     tools/genStubs.tcl,
     tools/index.tcl,







|







698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
     generic/tclPort.h,
     unix/tclMtherr.c,
     unix/tclUnixPort.h,
     unix/tclUnixCompat.c,
     win/tclWinMtherr.c,
     win/tclWinPort.h

 53. **Configuration and Build Tools** - djgpp/Makefile,
     macosx/Makefile,
     macosx/Tcl.pbproj/project.pbxproj,
     tests/all.tcl,
     tools/configure.in,
     tools/eolFix.tcl,
     tools/genStubs.tcl,
     tools/index.tcl,
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819

     win/tcl.hpj.in,
     win/tcl.m4,
     win/tcl.rc,
     win/tclConfig.sh.in,
     win/tclsh.ico,
     win/tclsh.rc

 54. '''Configuration Reporting''' (see [59]) -
     doc/RegConfig.3,
     generic/tclConfig.c,
     generic/tclPkgConfig.c,
     tests/config.test,
     win/tclWinPkgConfig.c

 55. '''Other Tools''' - tools/checkLibraryDoc.tcl,
     tools/findBadExternals.tcl,
     tools/genWinImage.tcl,
     tools/man2html.tcl,
     tools/man2html1.tcl,
     tools/man2html2.tcl,
     tools/regexpTestLib.tcl

  56. '''LibTomMath''' - libtommath/*

  57. '''zlib''' (see [234]) -
     doc/zlib.n,
     doc/TclZlib.3,
     generic/tclZlib.c,
     tests/zlib.c

~ Shared Files

The following files are shared by all of Tcl.  Any maintainer may
modify them as necessary to complete changes they are making to
their portion of Tcl.  Some of the following files define Tcl's
API and should be changed only in accordance with TCT approval.

   * ChangeLog,
     ChangeLog.*,
     doc/man.macros,
     generic/tcl.decls,
     generic/tcl.h,
     generic/tclInt.decls,
     generic/tclInt.h,
     generic/tclTest.c,
     generic/tclTestObj.c,
     tests/misc.test,
     unix/tclUnixTest.c,
     win/tclWinInt.h,
     win/tclWinTest.c

~ Generated Files

The following files are generated, so they don't need maintainers.

   * generic/tclDate.c,
     generic/tclUniData.c,
     generic/tclDecls.h,
     generic/tclIntDecls.h,
     generic/tclIntPlatDecls.h,
     generic/tclOODecls.h,
     generic/tclOOIntDecls.h,
     generic/tclOOStubInit.c,
     generic/tclOOStubLib.c,
     generic/tclPlatDecls.h,
     generic/tclStubInit.c,
     generic/tommath.h,
     library/tclIndex,
     unix/configure,
     win/configure

~ Copyright

This document has been placed in the public domain.








|






|







|

|





|







|












|



















|


>
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
     win/tcl.hpj.in,
     win/tcl.m4,
     win/tcl.rc,
     win/tclConfig.sh.in,
     win/tclsh.ico,
     win/tclsh.rc

 54. **Configuration Reporting** \(see [[59]](59.md)\) -
     doc/RegConfig.3,
     generic/tclConfig.c,
     generic/tclPkgConfig.c,
     tests/config.test,
     win/tclWinPkgConfig.c

 55. **Other Tools** - tools/checkLibraryDoc.tcl,
     tools/findBadExternals.tcl,
     tools/genWinImage.tcl,
     tools/man2html.tcl,
     tools/man2html1.tcl,
     tools/man2html2.tcl,
     tools/regexpTestLib.tcl

  56. **LibTomMath** - libtommath/\*

  57. **zlib** \(see [[234]](234.md)\) -
     doc/zlib.n,
     doc/TclZlib.3,
     generic/tclZlib.c,
     tests/zlib.c

# Shared Files

The following files are shared by all of Tcl.  Any maintainer may
modify them as necessary to complete changes they are making to
their portion of Tcl.  Some of the following files define Tcl's
API and should be changed only in accordance with TCT approval.

   * ChangeLog,
     ChangeLog.\*,
     doc/man.macros,
     generic/tcl.decls,
     generic/tcl.h,
     generic/tclInt.decls,
     generic/tclInt.h,
     generic/tclTest.c,
     generic/tclTestObj.c,
     tests/misc.test,
     unix/tclUnixTest.c,
     win/tclWinInt.h,
     win/tclWinTest.c

# Generated Files

The following files are generated, so they don't need maintainers.

   * generic/tclDate.c,
     generic/tclUniData.c,
     generic/tclDecls.h,
     generic/tclIntDecls.h,
     generic/tclIntPlatDecls.h,
     generic/tclOODecls.h,
     generic/tclOOIntDecls.h,
     generic/tclOOStubInit.c,
     generic/tclOOStubLib.c,
     generic/tclPlatDecls.h,
     generic/tclStubInit.c,
     generic/tommath.h,
     library/tclIndex,
     unix/configure,
     win/configure

# Copyright

This document has been placed in the public domain.

Name change from tip/160.tip to tip/160.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

TIP:		160
Title:		Improvements to Terminal and Serial Channel Handling
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Post-History:	
Version:	$Revision: 1.3 $
Author:		Donal K. Fellows <[email protected]>
Created:	17-Oct-2003


~ Abstract

Terminals and other kinds of serial lines have other capabilities and
requirements that are not currently controllable using Tcl.  This TIP
adds new options to [[fconfigure]] to allow these advanced
capabilities to be supported within Tcl in a straight-forward way.

~ Serial Line Discard Control

Serial lines are much slower devices than virtually anything else on a
modern computer, and it is quite possible for them to take a very long
time to read data.  Often, making sure all the data gets across is
important.  But this is not universally the case, and sometimes it is
more useful to discard the output bound for the serial line that is
pending in the operating system's own buffers.  This can't be enabled
by default in any configuration though, since there is no trivial way
to distinguish automatically between terminals that are having
debugging information written to them and serial lines that were
opened for data manipulation and where closing quickly is desirable
(you can't tell them apart even by device major/minor numbers due to
the way that /dev/tty is aliased inside the kernel on many Unixes.)
This was even the subject of a subtle bug (#525783) in [35].  But
since it is still useful, having it controllable by an explicit option
is useful.

I propose a new option for serial channels on all platforms:
''-closemode''.  This will have two legal values:

 drain: Closing the channel will result in a delay until the entire
 contents of the OS buffers are written.  This is the current default.

 discard: Closing the channel will result in any data in the OS
 buffers to be thrown away.  This can result in data that is being
 written by other processes being lost.

This option will be supported on all platforms where the underlying
serial API is sufficiently capable.  Where it is not supported, the
option will not be defined on serial channels.

~ Echo and Cooking Control

Terminals have a number of modes of operation.  Two of the most useful
things that can be set relate to echoing and cooking.

Echoing is fairly simple to understand.  If a terminal has echoing
turned on, every character read is written to the terminal
automatically without any action from the program reading from the
terminal.  Most of the time this is a good thing as people want to
see what they have typed, but sometimes it is not so good.  Examples
include where someone is typing in a password (when they also want
their lines cooked) and where an application is being controlled by
single key-presses (which is a case where neither echoing or cooking
are desirable, with echoing being a problem because the key press is
causing a different set of visible changes in the program's output.)

Cooking is also fairly simple.  A terminal is producing cooked input
when it is working in simply-editable line-at-a-time mode.  When the
terminal isn't in cooked mode, it delivers raw input directly and
immediately to the program.  Cooked input is the default and is useful
for a lot of purposes, but sometimes (when the application wants to
use single key-presses to control it) raw input is definitely
preferable.  Example uses of raw input include text editors (such as
vi or emacs) or terminal-based menu systems.

I propose supporting these operation modes within Tcl through a single
new option to the [[fconfigure]] command (to definitely be implemented
on Unix serial channels - because that is the type of stdin in a
normal interactive session - and suitably on other platforms if
possible): ''-inputmode''.  This will have three legal values:

 normal: This will turn on both echoing and cooking of input, and can
 be considered to be the default configuration for all terminals.

 password: This will turn off echoing but leave cooking turned on.

 raw: This will turn off both echoing and line-cooking.

I'm not aware off-hand of any use-cases for echoed raw mode.  While
there is theoretically a problem due to cross-talk between channels
(similar to that which was observed with the rationale for the
''-closemode'' option), it is practically unlikely to be one since
applications that take parsed input from several serial lines are very
rare.

Officially, the default value of the ''-inputmode'' option will be
system- and configuration-dependant, since users can use the ''stty''
program to configure their terminals prior to calling Tcl.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
>

|



|


|











|
|
|




|












|









|
|
|

|





|
|
|
|


|


|










|
|



|
|


|


>

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

# TIP 160: Improvements to Terminal and Serial Channel Handling
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	17-Oct-2003
-----

# Abstract

Terminals and other kinds of serial lines have other capabilities and
requirements that are not currently controllable using Tcl.  This TIP
adds new options to [fconfigure] to allow these advanced
capabilities to be supported within Tcl in a straight-forward way.

# Serial Line Discard Control

Serial lines are much slower devices than virtually anything else on a
modern computer, and it is quite possible for them to take a very long
time to read data.  Often, making sure all the data gets across is
important.  But this is not universally the case, and sometimes it is
more useful to discard the output bound for the serial line that is
pending in the operating system's own buffers.  This can't be enabled
by default in any configuration though, since there is no trivial way
to distinguish automatically between terminals that are having
debugging information written to them and serial lines that were
opened for data manipulation and where closing quickly is desirable
\(you can't tell them apart even by device major/minor numbers due to
the way that /dev/tty is aliased inside the kernel on many Unixes.\)
This was even the subject of a subtle bug \(\#525783\) in [[35]](35.md).  But
since it is still useful, having it controllable by an explicit option
is useful.

I propose a new option for serial channels on all platforms:
_-closemode_.  This will have two legal values:

 drain: Closing the channel will result in a delay until the entire
 contents of the OS buffers are written.  This is the current default.

 discard: Closing the channel will result in any data in the OS
 buffers to be thrown away.  This can result in data that is being
 written by other processes being lost.

This option will be supported on all platforms where the underlying
serial API is sufficiently capable.  Where it is not supported, the
option will not be defined on serial channels.

# Echo and Cooking Control

Terminals have a number of modes of operation.  Two of the most useful
things that can be set relate to echoing and cooking.

Echoing is fairly simple to understand.  If a terminal has echoing
turned on, every character read is written to the terminal
automatically without any action from the program reading from the
terminal.  Most of the time this is a good thing as people want to
see what they have typed, but sometimes it is not so good.  Examples
include where someone is typing in a password \(when they also want
their lines cooked\) and where an application is being controlled by
single key-presses \(which is a case where neither echoing or cooking
are desirable, with echoing being a problem because the key press is
causing a different set of visible changes in the program's output.\)

Cooking is also fairly simple.  A terminal is producing cooked input
when it is working in simply-editable line-at-a-time mode.  When the
terminal isn't in cooked mode, it delivers raw input directly and
immediately to the program.  Cooked input is the default and is useful
for a lot of purposes, but sometimes \(when the application wants to
use single key-presses to control it\) raw input is definitely
preferable.  Example uses of raw input include text editors \(such as
vi or emacs\) or terminal-based menu systems.

I propose supporting these operation modes within Tcl through a single
new option to the [fconfigure] command \(to definitely be implemented
on Unix serial channels - because that is the type of stdin in a
normal interactive session - and suitably on other platforms if
possible\): _-inputmode_.  This will have three legal values:

 normal: This will turn on both echoing and cooking of input, and can
 be considered to be the default configuration for all terminals.

 password: This will turn off echoing but leave cooking turned on.

 raw: This will turn off both echoing and line-cooking.

I'm not aware off-hand of any use-cases for echoed raw mode.  While
there is theoretically a problem due to cross-talk between channels
\(similar to that which was observed with the rationale for the
_-closemode_ option\), it is practically unlikely to be one since
applications that take parsed input from several serial lines are very
rare.

Officially, the default value of the _-inputmode_ option will be
system- and configuration-dependant, since users can use the _stty_
program to configure their terminals prior to calling Tcl.

# Copyright

This document has been placed in the public domain.

Name change from tip/161.tip to tip/161.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

TIP:            161
Title:          Change Default for Menu's -tearoff Option to False
Version:        $Revision: 1.2 $
Author:         Mark Roseman <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        19-Oct-2003
Post-History:   
Tcl-Version:    9.0


~ Abstract

This TIP proposes changing the default value of the ''-tearoff''
option on menu widgets to false, from its current setting of true.

~ Rationale

The default presence of tearoffs for Tk's menus originated with the
Motif look & feel, which was the platform standard used for earlier
Unix-only versions of Tk.  In more modern user interface toolkits on
Unix, as well as Macintosh and Windows, menus do not normally have
tearoffs associated with them.  For applications today, menus without
tearoffs are the standard, with tearoff menus being the exception.

While turning off the tearoff on menus can be accomplished either with
a configuration option on the particular menu, or a global option
setting, this can be a source of confusion for the new Tk developer,
and too easily forgotten by other developers.  Forcing developers to
take extra action to achieve "standard" user interface behavior is
contrary to Tk's philosophy.

~ Proposed Change

Implementation of this TIP requires only changing a single default in
each of the platform specific ''tk*Default.h'' files, and updating the
documentation and test cases.

~ Compatibility

Unfortunately, entries in menus are often accessed by index within
scripts, and the presence or absence of tearoff affects this index.
Therefore, changing the default setting of this option will affect a
large number of scripts.  Though fixing these scripts will be
straightforward (either through adjusting access to individual menus,
or using the option database to turn the tearoff option back on),
because of the incompatibility this TIP is proposed for 9.0 rather
than 8.x.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|


|















|


|


|





|
|



|


>

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

# TIP 161: Change Default for Menu's -tearoff Option to False

	Author:         Mark Roseman <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        19-Oct-2003
	Post-History:   
	Tcl-Version:    9.0
-----

# Abstract

This TIP proposes changing the default value of the _-tearoff_
option on menu widgets to false, from its current setting of true.

# Rationale

The default presence of tearoffs for Tk's menus originated with the
Motif look & feel, which was the platform standard used for earlier
Unix-only versions of Tk.  In more modern user interface toolkits on
Unix, as well as Macintosh and Windows, menus do not normally have
tearoffs associated with them.  For applications today, menus without
tearoffs are the standard, with tearoff menus being the exception.

While turning off the tearoff on menus can be accomplished either with
a configuration option on the particular menu, or a global option
setting, this can be a source of confusion for the new Tk developer,
and too easily forgotten by other developers.  Forcing developers to
take extra action to achieve "standard" user interface behavior is
contrary to Tk's philosophy.

# Proposed Change

Implementation of this TIP requires only changing a single default in
each of the platform specific _tk\*Default.h_ files, and updating the
documentation and test cases.

# Compatibility

Unfortunately, entries in menus are often accessed by index within
scripts, and the presence or absence of tearoff affects this index.
Therefore, changing the default setting of this option will affect a
large number of scripts.  Though fixing these scripts will be
straightforward \(either through adjusting access to individual menus,
or using the option database to turn the tearoff option back on\),
because of the incompatibility this TIP is proposed for 9.0 rather
than 8.x.

# Copyright

This document has been placed in the public domain.

Name change from tip/162.tip to tip/162.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

TIP:            162
Title:          IPv6 Sockets for Tcl
Version:        $Revision: 1.16 $
Author:         Rafael Mart�nez Torres <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         Reinhard Max <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        23-Oct-2003
Post-History:   
Tcl-Version:    8.6


~ Abstract

This TIP is about allowing Tcl to use IPv6 sockets in virtually the
same way that you would use the current (IPv4) sockets.

~ Rationale

IPv6 is the next generation of the IP protocol that underlies
Internet sockets.  IPv6 advantages include a wider address
space (128 bits instead current 32 bits), improved mobility,
mandatory security at IP layer (IPsec...), etc.  Tcl should allow
the programmers try both protocols at their networking programs
without too much effort (dependant on underlying operating system
support, of course), just accepting the literal
address (192.0.2.42, 2001:DB8::baad:f00d) or the DNS
names (www.example.com).

~ Proposed Change

The interpreter should understand:

|socket 192.0.2.42 http
|socket 2001:DB8::baad:f00d echo
|socket -server accept 9999
|socket ipv6.example.com 8080

Where a hostname resolves to multiple addresses in multiple
families, the addresses are tried one by one as returned by the
the resolver library until a connection can be established. The
order depends on the resolver library and its configuration; it
is deliberately not touched by Tcl, so that local preferences are
automatically respected by Tcl programs.

For sockets that actually use IPv6 the output of '''fconfigure'''
needs to be changed to reflect the fact:

Client sockets:

|% fconfigure sock5 -peername
|2001:DB8::baad:f00d ipv6.example.com 7
|% fconfigure sock5 -sockname
|2001:DB8::dead:beef 2001:DB8::dead:beef 49198

Server sockets:

|% socket -server accept 0
|sock3
|% fconfigure sock3 -sockname
|0.0.0.0 0.0.0.0 49198 :: :: 49198

The '''-sockname''' and '''-peername''' options are the affected
ones; for client sockets they can indicate addresses in the IPv6
or IPv4 namespaces, and for server sockets the '''-sockname'''
option will list all the addresses bound (2 in the above
example), three elements each. To maximize backward
compatibility, the IPv4 address (if bound) will always be listed
first. (Client sockets will always only list a single address as
they will always be connected by a definite protocol.)

~ Reference Implementation

A development branch has been opened up; see
[http://wiki.tcl.tk/25947] for details.

An older patch is available for UNIX platforms
[http://www.ngn.euro6ix.org/IPv6/tcl].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|


|

|



|
|

|
|
|
|

|



|
|
|
|








|




|
|
|
|



|
|
|
|

|

|
|
|
|
|
|

|


|


|

|


>

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

# TIP 162: IPv6 Sockets for Tcl

	Author:         Rafael Martínez Torres <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         Reinhard Max <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        23-Oct-2003
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

This TIP is about allowing Tcl to use IPv6 sockets in virtually the
same way that you would use the current \(IPv4\) sockets.

# Rationale

IPv6 is the next generation of the IP protocol that underlies
Internet sockets.  IPv6 advantages include a wider address
space \(128 bits instead current 32 bits\), improved mobility,
mandatory security at IP layer \(IPsec...\), etc.  Tcl should allow
the programmers try both protocols at their networking programs
without too much effort \(dependant on underlying operating system
support, of course\), just accepting the literal
address \(192.0.2.42, 2001:DB8::baad:f00d\) or the DNS
names \(www.example.com\).

# Proposed Change

The interpreter should understand:

	socket 192.0.2.42 http
	socket 2001:DB8::baad:f00d echo
	socket -server accept 9999
	socket ipv6.example.com 8080

Where a hostname resolves to multiple addresses in multiple
families, the addresses are tried one by one as returned by the
the resolver library until a connection can be established. The
order depends on the resolver library and its configuration; it
is deliberately not touched by Tcl, so that local preferences are
automatically respected by Tcl programs.

For sockets that actually use IPv6 the output of **fconfigure**
needs to be changed to reflect the fact:

Client sockets:

	% fconfigure sock5 -peername
	2001:DB8::baad:f00d ipv6.example.com 7
	% fconfigure sock5 -sockname
	2001:DB8::dead:beef 2001:DB8::dead:beef 49198

Server sockets:

	% socket -server accept 0
	sock3
	% fconfigure sock3 -sockname
	0.0.0.0 0.0.0.0 49198 :: :: 49198

The **-sockname** and **-peername** options are the affected
ones; for client sockets they can indicate addresses in the IPv6
or IPv4 namespaces, and for server sockets the **-sockname**
option will list all the addresses bound \(2 in the above
example\), three elements each. To maximize backward
compatibility, the IPv4 address \(if bound\) will always be listed
first. \(Client sockets will always only list a single address as
they will always be connected by a definite protocol.\)

# Reference Implementation

A development branch has been opened up; see
<http://wiki.tcl.tk/25947>  for details.

An older patch is available for UNIX platforms
<http://www.ngn.euro6ix.org/IPv6/tcl> .

# Copyright

This document has been placed in the public domain.

Name change from tip/163.tip to tip/163.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

TIP:		163
Title:		A [dict merge] Subcommand
Version:	$Revision: 1.4 $
Author:		Joe English <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Created:	14-Nov-2003
Post-History:	


~ Abstract

This TIP proposes a new [[dict]] subcommand which is used to combine
multiple dictionaries.

~ Specification

|	dict merge ''dictVal1'' ''dictVal2'' ''...'' ''dictValN''

Returns a new dictionary containing all the key/value pairs in
''dictVal1'' through ''dictValN''.  In the case of duplicate keys,
values from later arguments override those from earlier ones.

~ Implementation

See SF Patch #745851
http://sourceforge.net/support/tracker.php?aid=745851

~ Examples

See the EXAMPLES section of return(n), which currently reads:

| set options [eval [list dict create -level 1] $args]

This could be replaced with

| set options [dict merge {-level 1} $args]

~ Notes

This feature was suggested during the discussion of [111], but since
the vote was already in progress it was not considered at that time.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|


|

|


|


|

|
|

|

|

|



|

|

|


|


>

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

# TIP 163: A [dict merge] Subcommand

	Author:		Joe English <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Created:	14-Nov-2003
	Post-History:	
-----

# Abstract

This TIP proposes a new [dict] subcommand which is used to combine
multiple dictionaries.

# Specification

		dict merge ''dictVal1'' ''dictVal2'' ''...'' ''dictValN''

Returns a new dictionary containing all the key/value pairs in
_dictVal1_ through _dictValN_.  In the case of duplicate keys,
values from later arguments override those from earlier ones.

# Implementation

See SF Patch \#745851
<http://sourceforge.net/support/tracker.php?aid=745851>

# Examples

See the EXAMPLES section of return\(n\), which currently reads:

	 set options [eval [list dict create -level 1] $args]

This could be replaced with

	 set options [dict merge {-level 1} $args]

# Notes

This feature was suggested during the discussion of [[111]](111.md), but since
the vote was already in progress it was not considered at that time.

# Copyright

This document has been placed in the public domain.

Name change from tip/164.tip to tip/164.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

TIP:            164
Title:          Add Rotate Subcommand to the Canvas Widget
Version:        $Revision: 1.5 $
Author:         Arjen Markus <[email protected]>
Author:         Dimitrios Zachariadis <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        17-Nov-2003
Post-History:   
Keywords:       Tk,canvas
Tcl-Version:    8.7


~ Abstract

This TIP proposes to add a ''rotate'' subcommand to the canvas widget
to facilitate rotating items in very much the same way as is now
possible with scaling and moving.

~ Rationale

The canvas currently allows a programmer to scale and move items, but
the third common affine transformation, rotation, is not supported.
This can in itself be simulated by a script (simply get the
coordinates of all items involved, transform them and set the new
coordinates), but if you have several hundreds or even thousands of
items this gets very slow.

Rotation is easy for polygons and lines: simply transform the
coordinates.  For circles and circular arcs new bounding boxes must be
calculated and in addition for arcs the starting angle must be
changed.

Implementing rotation should consider what to do with items that can
not (easily) be rotated: text items, rectangles, non-circular ovals
and arcs, widgets and images.  Currently, text can not be drawn at an
arbitrary angle, so I propose to only transform the coordinates at
which the text is "anchored".  A similar strategy can be used for
widgets and images.

For rectangles and general ovals and arcs there are two choices:

 * Transforming the item into a polygon would solve the definition
   problem (these items are defined by a bounding box and the
   orientation is implicitly assumed), but might break scripts that
   look for a particular type of item.

 * Therefore we will simply calculate a new bounding box and ''ignore
   changes in orientation''.

~ Proposal

Canvases will have a new subcommand, '''rotate''', which will rotate the coordinates of chosen items by a specified angle about a specified point.

 > ''canvas'' '''rotate''' ''itemOrTag'' ''x'' ''y'' ''angle''

Note that most of the arguments are very similar to the canvas's '''scale''' subcommand.  ''Angle'' is measured in degrees, with positive values indicating anti-clockwise rotation.

~~ Canvas Item C API Alterations

[[These are required for this TIP, but are not yet done.]]

~ Reference Implementation

A reference implementation does ''not'' yet exist.

~ Future Work

Should we also consider the possibility of reflections in a line?

Should we also consider more general linear transformations (to be specified via a 2x2 matrix)?  What about full affine transformations (i.e. with the translation components)?

If we implement these from the start, we need to do only a little more
work.

~ Comments

It might be useful to utilize the -anchor Tk option in all canvas items and add a new "-anchoroffset $x,$y" option, where $x $y be canvas distances relevant to the anchor position. Once defined, or with their default values, the -anchor and -anchoroffset values combined will provide the item's center, for placement and rotation purposes. Item sets, constituting symbols, can then be manipulated easily.

It could probably be beneficial to add an -angle option (and an accomplanying -angleunit one), to persist a rotation angle in the configuration database. The presence of an angle value other than zero would help negate rotation, thus re-instating the item to its initial orientation.

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|



|



|

|








|








|
|


|
|

|

|

|

|

|

|

|

|

|



|




|



|

|


>

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

# TIP 164: Add Rotate Subcommand to the Canvas Widget

	Author:         Arjen Markus <[email protected]>
	Author:         Dimitrios Zachariadis <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        17-Nov-2003
	Post-History:   
	Keywords:       Tk,canvas
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to add a _rotate_ subcommand to the canvas widget
to facilitate rotating items in very much the same way as is now
possible with scaling and moving.

# Rationale

The canvas currently allows a programmer to scale and move items, but
the third common affine transformation, rotation, is not supported.
This can in itself be simulated by a script \(simply get the
coordinates of all items involved, transform them and set the new
coordinates\), but if you have several hundreds or even thousands of
items this gets very slow.

Rotation is easy for polygons and lines: simply transform the
coordinates.  For circles and circular arcs new bounding boxes must be
calculated and in addition for arcs the starting angle must be
changed.

Implementing rotation should consider what to do with items that can
not \(easily\) be rotated: text items, rectangles, non-circular ovals
and arcs, widgets and images.  Currently, text can not be drawn at an
arbitrary angle, so I propose to only transform the coordinates at
which the text is "anchored".  A similar strategy can be used for
widgets and images.

For rectangles and general ovals and arcs there are two choices:

 * Transforming the item into a polygon would solve the definition
   problem \(these items are defined by a bounding box and the
   orientation is implicitly assumed\), but might break scripts that
   look for a particular type of item.

 * Therefore we will simply calculate a new bounding box and _ignore
   changes in orientation_.

# Proposal

Canvases will have a new subcommand, **rotate**, which will rotate the coordinates of chosen items by a specified angle about a specified point.

 > _canvas_ **rotate** _itemOrTag_ _x_ _y_ _angle_

Note that most of the arguments are very similar to the canvas's **scale** subcommand.  _Angle_ is measured in degrees, with positive values indicating anti-clockwise rotation.

## Canvas Item C API Alterations

[These are required for this TIP, but are not yet done.]

# Reference Implementation

A reference implementation does _not_ yet exist.

# Future Work

Should we also consider the possibility of reflections in a line?

Should we also consider more general linear transformations \(to be specified via a 2x2 matrix\)?  What about full affine transformations \(i.e. with the translation components\)?

If we implement these from the start, we need to do only a little more
work.

# Comments

It might be useful to utilize the -anchor Tk option in all canvas items and add a new "-anchoroffset $x,$y" option, where $x $y be canvas distances relevant to the anchor position. Once defined, or with their default values, the -anchor and -anchoroffset values combined will provide the item's center, for placement and rotation purposes. Item sets, constituting symbols, can then be manipulated easily.

It could probably be beneficial to add an -angle option \(and an accomplanying -angleunit one\), to persist a rotation angle in the configuration database. The presence of an angle value other than zero would help negate rotation, thus re-instating the item to its initial orientation.

# Copyright

This document is placed in the public domain.

Name change from tip/165.tip to tip/165.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

TIP:            165
Title:          A User-Data Field for Virtual Events
Version:        $Revision: 1.6 $
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        17-Nov-2003
Post-History:   
Keywords:       Tk,substitution
Tcl-Version:    8.5


~ Abstract

This TIP proposes adding to virtual events a new field that is not
interpreted by Tk.  This will make it far easier for user-code to pass
information between creators and consumers of events instead of
forcing the use of fragile global variables for this purpose.

~ Rationale

Virtual events are a powerful mechanism in Tk for representing
window-related occurrences which are not part of the underlying window
system's basic event model.  Examples of these higher-level events
include <<MenuSelect>> and <<ListboxSelect>>, both of which may
represent either particular key actions or particular mouse
movements/clicks, but neither of which has deep significance to the
windowing system.  They are very important to the application though!

There is a problem with virtual events though, and that is that they
do not provide a way of passing some kind of event-specific
information via the event.  This means, among other things, that
neither of the events mentioned above can actually say what it was
that was selected, despite the fact that that would be a natural piece
of information to include.

Other potential uses include in a drag-and-drop system, where the
information passed might be the data being dropped, and perhaps even
inside Tk itself where refactoring many widgets (e.g. the spinbox or
the scrollbar) to use virtual events for their semantic events would
allow for programmers to track what is going on more easily, a
refactoring which would require extra information describing which
subcomponent of those widgets is being activated.  (Actually doing
such a refactoring is outside the scope of this TIP though.)

~ Specification

To make this happen, an extra field is required in the XVirtualEvent
defined in ''generic/tk.h'', which will be placed at the end of the
structure and which will be declared like this (in keeping with the
field naming scheme in the rest of that structure):

|   Tcl_Obj *user_data;

This field will normally be NULL, but if not it must be a pointer to a
''Tcl_Obj'' structure with a non-zero reference count.  (This will
still leave the XVirtualEvent structure smaller than an XCrossingEvent
so no change to core structure sizes will be seen.)  Once the event
has had all its binding callbacks called on it, the reference count of
the user_data field will be decremented once (if it is non-NULL, of
course.)  It will be up to the caller of ''Tk_HandleEvent()'' or
''Tk_QueueWindowEvent()'' (depending on whether the event is being
handled synchronously or asynchronously, respectively) to increment
the reference count.

The contents of that field will be substituted in binding scripts
using the '''%d''' substitution ("d" for "data"), with a NULL being
treated like an empty string.  Empty strings (and NULLs) will be
substituted as {}, similarly to the ''%A'' substitution when a key
press does not have a character associated with it.

Generation of a virtual event with a non-NULL ''user_data'' field will
be done using a new event-field option to '''event generate''':
'''-data'''.  The value passed to that option will be the object to
place inside the ''user_data'' field.

~ Reference Implementation

http://sf.net/tracker/?func=detail&aid=1008975&group_id=12997&atid=312997

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|






|


















|
|


|
|

|


|
|
|

|


|

|

|
|
|
|



|
|
|


|
|
|
|

|

|

|


>

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

# TIP 165: A User-Data Field for Virtual Events

	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        17-Nov-2003
	Post-History:   
	Keywords:       Tk,substitution
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes adding to virtual events a new field that is not
interpreted by Tk.  This will make it far easier for user-code to pass
information between creators and consumers of events instead of
forcing the use of fragile global variables for this purpose.

# Rationale

Virtual events are a powerful mechanism in Tk for representing
window-related occurrences which are not part of the underlying window
system's basic event model.  Examples of these higher-level events
include <<MenuSelect>> and <<ListboxSelect>>, both of which may
represent either particular key actions or particular mouse
movements/clicks, but neither of which has deep significance to the
windowing system.  They are very important to the application though!

There is a problem with virtual events though, and that is that they
do not provide a way of passing some kind of event-specific
information via the event.  This means, among other things, that
neither of the events mentioned above can actually say what it was
that was selected, despite the fact that that would be a natural piece
of information to include.

Other potential uses include in a drag-and-drop system, where the
information passed might be the data being dropped, and perhaps even
inside Tk itself where refactoring many widgets \(e.g. the spinbox or
the scrollbar\) to use virtual events for their semantic events would
allow for programmers to track what is going on more easily, a
refactoring which would require extra information describing which
subcomponent of those widgets is being activated.  \(Actually doing
such a refactoring is outside the scope of this TIP though.\)

# Specification

To make this happen, an extra field is required in the XVirtualEvent
defined in _generic/tk.h_, which will be placed at the end of the
structure and which will be declared like this \(in keeping with the
field naming scheme in the rest of that structure\):

	   Tcl_Obj *user_data;

This field will normally be NULL, but if not it must be a pointer to a
_Tcl\_Obj_ structure with a non-zero reference count.  \(This will
still leave the XVirtualEvent structure smaller than an XCrossingEvent
so no change to core structure sizes will be seen.\)  Once the event
has had all its binding callbacks called on it, the reference count of
the user\_data field will be decremented once \(if it is non-NULL, of
course.\)  It will be up to the caller of _Tk\_HandleEvent\(\)_ or
_Tk\_QueueWindowEvent\(\)_ \(depending on whether the event is being
handled synchronously or asynchronously, respectively\) to increment
the reference count.

The contents of that field will be substituted in binding scripts
using the **%d** substitution \("d" for "data"\), with a NULL being
treated like an empty string.  Empty strings \(and NULLs\) will be
substituted as \{\}, similarly to the _%A_ substitution when a key
press does not have a character associated with it.

Generation of a virtual event with a non-NULL _user\_data_ field will
be done using a new event-field option to **event generate**:
**-data**.  The value passed to that option will be the object to
place inside the _user\_data_ field.

# Reference Implementation

<http://sf.net/tracker/?func=detail&aid=1008975&group\_id=12997&atid=312997>

# Copyright

This document is placed in the public domain.

Name change from tip/166.tip to tip/166.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
136
137
138
139
140
141
142
143
144
145
146
147
148

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

TIP:            166
Title:          Reading and Writing the Photo Image Alpha Channel
Version:        $Revision: 1.12 $
Author:         Donal K. Fellows <[email protected]>
Author:         Simon Bachmann <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        19-Nov-2003
Post-History:   
Keywords:       Tk,image get,image put
Tcl-Version:    8.7


~ Abstract

This TIP describes how to update the '''image get''' and '''image put'''
subcommands so as to allow script-level access to the full alpha
channel information that has been present in the photo image data
model since Tk 8.3.

~Rationale

Alpha channels.  We've had them in Tk's photo image data model (which
is currently 8-bits-per-channel RGBA) for quite some time now.  We can
copy the alpha data around inside the image.  We now display them
correctly on deep-enough displays (many thanks to the people who have
worked on that!)  But can we write alpha data into an image?  No.  Not
unless you have an image format handler that produces alpha data
installed (e.g. the PNG from tkimg.)  I think we should fix this so
that people can read and write the full alpha data from scripts.

~Proposal

I propose to update the ''photoImageInstance'' '''get''' subcommand so
that it takes an extra option '''-withalpha''' (to be placed after the
coordinates). If that option is specified, the subcommand will return
four values instead of three, with the fourth being the contents of
the alpha channel for the pixel. Without this new option, the
subcommand will return three values as before.

I also propose to update the ''photoImageInstance'' '''put''' subcommand
so that alpha channel information may be specified in the following ways
when using the list-of-lists-of-pixel-data format (the image-format
format will be up to the particular image format code, as always.)

 * If a pixel is specified as being the empty string, that pixel will
   be set to be completely transparent.  This parallels the
   interpretation of the empty string as transparency elsewhere within
   the core (notably in [[canvas]] items.)

 * Any standard Tk colour format (those accepted by
   '''Tk_GetColor()''' - e.g.  ''bisque2'' or ''#abcdef'') may have
   the following suffix added - '''@A''' - where A is a fractional
   alpha value in the range 0.0 to 1.0 (which values correspond to
   fully transparent and fully opaque respectively.)

 * Any standard Tk colour format which does not have a '''@A''' suffix
   may have a '''#XX''' suffix, where XX is a pair of hex digits that
   specify an integer alpha value in the range 0 (fully transparent)
   to 255 (fully opaque).

 * Any standard Tk colour format which does not have a '''@A''' suffix
   nor a '''#XX''' suffix may have a '''#X''' suffix, where X is a
   single hex digit that specifies an integer alpha value in the range
   0 (fully transparent) to 255 (fully opaque).  This is expanded in
   range from 4 bits wide to 8 bits wide by multiplication by 0x11.

 * All pixel colours that have neither of the foregoing suffixes are
   to be interpreted as being fully opaque, which is the current
   situation anyway.

 * An additional pixel format is to be supported, consisting of a Tcl
   list of three or four integers in the range 0 to 255, being the
   value of the red channel, green channel, blue channel and alpha
   channel respectively in that order.  An absent alpha channel is to
   be interpreted as full opacity.

 * Two additional pixel formats are to be supported, consisting of a
   '''#''' followed by exactly four or eight hexadecimal digits.  When
   four digits are present, they will be interpreted as containing data
   for the ''RGBA'' channels (in that order), and each digit will be
   expanded internally to 8-bits wide by multiplication by 0x11.  When
   eight digits are present, they will be interpreted as containing data
   for the ''RGBA'' channels (in that order) with two digits for each
   channel.

It should also be possible to include alpha information in the data
retrieved with the ''photoImageInstance'' '''data''' subcommand.
For this, I propose to make the list-of-lists-of-pixel-data format a
regular photo image format (like PNG, GIF, PPM, etc.) with the name
'''default'''. This format will have no file read/write capabilities.
As before, the list-of-lists format will be the default choice for
''photoImageInstance'' '''data''', and the last one to be tried for
''photoImageInstance'' '''put'''. The main benefit of this
change is that it will be possible to request the '''default'''
format explicitly with the '''-format''' option and - most important -
to pass suboptions to the format handler. 
The '''default''' image data format shall accept the suboption
'''-colorformat''' ''type'' which specifies the format to be used to
encode the color and alpha data for each pixel. Accepted values shall
be '''rgb''' for the #RRGGBB format (the current format and default
for the suboption), '''rgba''' for the #RRGGBBAA format, and
'''list''' for the list format with four elements.
This change will have two side effects:

 * The '''-data''' option to photo images will accept image data in the
   list-of-lists form as well. Currently only data in one of the
   registered file formats is accepted.

 * The underlying implementation will become simpler and cleaner.

Finally, the ''photoImageInstance'' '''transparency''' command's
subcommands will be updated in the following way:

 * The '''get''' subcommand will be modified to take an extra option,
   '''-alpha''' (to be placed after the coordinates), that modifies the
   result to be the integral alpha value (in the range 0 to 255) for the
   specified pixel. Without the option, the result shall continue to be
   a boolean that is true exactly when the pixel is wholly transparent.

 * The '''set''' subcommand will be modified to take an extra option,
   '''-alpha''' (to be placed after the new value), that modifies the
   interpretation of the new value so that it is the integral
   alpha value to be set for the pixel.  Without the option, the value 
   will be interpreted as a boolean as before.

~Examples

Create a small image with a black border and a partially-transparent
red area in the center.

|image create photo transExample
|transExample put black -to 0 0 10 10
|transExample put [email protected] -to 2 2 8 8

Retrieve the alpha value of a pixel near the middle of the image
created previously.

|set aVal [transExample transparency get 5 5 -alpha]

Create a green box with a simple shadow effect

|image create photo foo
|# Make a simple graduated fill varying in alpha for the shadow
|for {set i 14} {$i>0} {incr i -1} {
|   set i2 [expr {$i+30}]
|   foo put [format black#%x [expr {15-$i}]] -to $i $i $i2 $i2
|}

|# Put a solid green rectangle on top
|foo put #080 -to 0 0 30 30

Retrieve image data with alpha information in the list-of-lists form
and create a new image with it. 

|image create photo bar -file imageWithTransparency.png
|set imageData [bar data -format {default -colorformat rgba}
|
|# Inspect / modify / save data
|
|image create photo baz -data $imageData

~Reference Implementation

Branch tip-166 on fossil.

~Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|




|

|
|

|
|

|


|

|
|
|




|

|
|




|

|
|
|
|
|

|
|
|
|

|
|

|













|

|


|



|

|
|

|
|
|
|

|
|

|
|
|


|





|


|
|
|



|
|




|




|
|
|




|



|
|
|
|
|
<
>
|
|




|
|
|
|
|
|

|



|


>

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
136
137
138
139
140
141
142
143
144
145
146

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

# TIP 166: Reading and Writing the Photo Image Alpha Channel

	Author:         Donal K. Fellows <[email protected]>
	Author:         Simon Bachmann <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        19-Nov-2003
	Post-History:   
	Keywords:       Tk,image get,image put
	Tcl-Version:    8.7
-----

# Abstract

This TIP describes how to update the **image get** and **image put**
subcommands so as to allow script-level access to the full alpha
channel information that has been present in the photo image data
model since Tk 8.3.

# Rationale

Alpha channels.  We've had them in Tk's photo image data model \(which
is currently 8-bits-per-channel RGBA\) for quite some time now.  We can
copy the alpha data around inside the image.  We now display them
correctly on deep-enough displays \(many thanks to the people who have
worked on that!\)  But can we write alpha data into an image?  No.  Not
unless you have an image format handler that produces alpha data
installed \(e.g. the PNG from tkimg.\)  I think we should fix this so
that people can read and write the full alpha data from scripts.

# Proposal

I propose to update the _photoImageInstance_ **get** subcommand so
that it takes an extra option **-withalpha** \(to be placed after the
coordinates\). If that option is specified, the subcommand will return
four values instead of three, with the fourth being the contents of
the alpha channel for the pixel. Without this new option, the
subcommand will return three values as before.

I also propose to update the _photoImageInstance_ **put** subcommand
so that alpha channel information may be specified in the following ways
when using the list-of-lists-of-pixel-data format \(the image-format
format will be up to the particular image format code, as always.\)

 * If a pixel is specified as being the empty string, that pixel will
   be set to be completely transparent.  This parallels the
   interpretation of the empty string as transparency elsewhere within
   the core \(notably in [canvas] items.\)

 * Any standard Tk colour format \(those accepted by
   **Tk\_GetColor\(\)** - e.g.  _bisque2_ or _\#abcdef_\) may have
   the following suffix added - **@A** - where A is a fractional
   alpha value in the range 0.0 to 1.0 \(which values correspond to
   fully transparent and fully opaque respectively.\)

 * Any standard Tk colour format which does not have a **@A** suffix
   may have a **\#XX** suffix, where XX is a pair of hex digits that
   specify an integer alpha value in the range 0 \(fully transparent\)
   to 255 \(fully opaque\).

 * Any standard Tk colour format which does not have a **@A** suffix
   nor a **\#XX** suffix may have a **\#X** suffix, where X is a
   single hex digit that specifies an integer alpha value in the range
   0 \(fully transparent\) to 255 \(fully opaque\).  This is expanded in
   range from 4 bits wide to 8 bits wide by multiplication by 0x11.

 * All pixel colours that have neither of the foregoing suffixes are
   to be interpreted as being fully opaque, which is the current
   situation anyway.

 * An additional pixel format is to be supported, consisting of a Tcl
   list of three or four integers in the range 0 to 255, being the
   value of the red channel, green channel, blue channel and alpha
   channel respectively in that order.  An absent alpha channel is to
   be interpreted as full opacity.

 * Two additional pixel formats are to be supported, consisting of a
   **\#** followed by exactly four or eight hexadecimal digits.  When
   four digits are present, they will be interpreted as containing data
   for the _RGBA_ channels \(in that order\), and each digit will be
   expanded internally to 8-bits wide by multiplication by 0x11.  When
   eight digits are present, they will be interpreted as containing data
   for the _RGBA_ channels \(in that order\) with two digits for each
   channel.

It should also be possible to include alpha information in the data
retrieved with the _photoImageInstance_ **data** subcommand.
For this, I propose to make the list-of-lists-of-pixel-data format a
regular photo image format \(like PNG, GIF, PPM, etc.\) with the name
**default**. This format will have no file read/write capabilities.
As before, the list-of-lists format will be the default choice for
_photoImageInstance_ **data**, and the last one to be tried for
_photoImageInstance_ **put**. The main benefit of this
change is that it will be possible to request the **default**
format explicitly with the **-format** option and - most important -
to pass suboptions to the format handler. 
The **default** image data format shall accept the suboption
**-colorformat** _type_ which specifies the format to be used to
encode the color and alpha data for each pixel. Accepted values shall
be **rgb** for the \#RRGGBB format \(the current format and default
for the suboption\), **rgba** for the \#RRGGBBAA format, and
**list** for the list format with four elements.
This change will have two side effects:

 * The **-data** option to photo images will accept image data in the
   list-of-lists form as well. Currently only data in one of the
   registered file formats is accepted.

 * The underlying implementation will become simpler and cleaner.

Finally, the _photoImageInstance_ **transparency** command's
subcommands will be updated in the following way:

 * The **get** subcommand will be modified to take an extra option,
   **-alpha** \(to be placed after the coordinates\), that modifies the
   result to be the integral alpha value \(in the range 0 to 255\) for the
   specified pixel. Without the option, the result shall continue to be
   a boolean that is true exactly when the pixel is wholly transparent.

 * The **set** subcommand will be modified to take an extra option,
   **-alpha** \(to be placed after the new value\), that modifies the
   interpretation of the new value so that it is the integral
   alpha value to be set for the pixel.  Without the option, the value 
   will be interpreted as a boolean as before.

# Examples

Create a small image with a black border and a partially-transparent
red area in the center.

	image create photo transExample
	transExample put black -to 0 0 10 10
	transExample put [email protected] -to 2 2 8 8

Retrieve the alpha value of a pixel near the middle of the image
created previously.

	set aVal [transExample transparency get 5 5 -alpha]

Create a green box with a simple shadow effect

	image create photo foo
	# Make a simple graduated fill varying in alpha for the shadow
	for {set i 14} {$i>0} {incr i -1} {
	   set i2 [expr {$i+30}]
	   foo put [format black#%x [expr {15-$i}]] -to $i $i $i2 $i2

	}
	# Put a solid green rectangle on top
	foo put #080 -to 0 0 30 30

Retrieve image data with alpha information in the list-of-lists form
and create a new image with it. 

	image create photo bar -file imageWithTransparency.png
	set imageData [bar data -format {default -colorformat rgba}
	
	# Inspect / modify / save data
	
	image create photo baz -data $imageData

# Reference Implementation

Branch tip-166 on fossil.

# Copyright

This document is placed in the public domain.

Name change from tip/167.tip to tip/167.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

TIP:            167
Title:          Add a New Option for Context Help for Windows
Version:        $Revision: 1.9 $
Author:         Ramon Rib� <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        19-Nov-2003
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes adding a new option to '''wm attributes''' for the
Windows version of Tk that offers contextual help in that window.
Additionally, a new event type '''<Help>''' is defined, that will be
delivered when the user picks the Help button in the window and picks
over a widget.  The event will be also hitted when user presses F1
over one window.

~ Rationale

Contextual help is very important in a program to help users to
interactively learn to use the software capabilities.  Windows offers
a powerful mechanism to facilite the implementation of this contextual
help but current versions of Tk do not take advantage of this feature.
The feature cannot be implemented as an extension as a new event type
is needed so as to be informed from the OS that the user has chosen to
ask for help over that widget.

This contextual help is offered in the following way: when a window is
configured to have this option, a small question mark button is
displayed in the window title bar near the close button. If users pick
that button, a question mark cursor is actived and the user can pick a
widget (or location in a widget.)  The typical program reaction to
this is to offer a pop-up window with some short help text or to open
the program help in the relevant section.

Additionally, the new proposed event '''<Help>''' can also get
information when user presses key F1 over one window.

This implementation is proposed for the Windows OS only, though in the
future some Window Managers like KDE (in Linux) have the same feature
and could be also implemented.  In any case, this TIP only proposes
implementation on Windows.

~ Specification

A new option will be added to '''wm attributes''' with the following
syntax:

 > '''wm attributes''' ''window'' '''-contexthelp''' ?''boolean''?

If set and if the window is transient, the question mark button will
appear in the window title bar.

A new event '''<Help>''' is added to the event list so as a user can
do:

|  bind $w <Help> {puts "You pressed widget %W"}

This event will hit in two situations: when the user presses the
question mark in the title bar of the window and pick a widget; and
when user presses the F1 key (or other platform-defined help key) over
one window (this latter case only for bindings in the toplevel).

The event will support the usual %W %x %y substitutions and other
values.

~ Reference Implementation

http://sf.net/tracker/?func=detail&atid=312997&aid=845248&group_id=12997

~ Comments

It would be preferable to use a virtual event '''<<Help>>'' instead of extending the set of X events.  (In particular, adding a new '''<Help>''' event means there has to be a new '''HelpMask''' bit flag to select for it, and we're running out of event mask bits).

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|

|




|













|



|



|



|

|


|




|


|



|
|




|

|

|

|

|


>

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

# TIP 167: Add a New Option for Context Help for Windows

	Author:         Ramon Ribó <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        19-Nov-2003
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes adding a new option to **wm attributes** for the
Windows version of Tk that offers contextual help in that window.
Additionally, a new event type **<Help>** is defined, that will be
delivered when the user picks the Help button in the window and picks
over a widget.  The event will be also hitted when user presses F1
over one window.

# Rationale

Contextual help is very important in a program to help users to
interactively learn to use the software capabilities.  Windows offers
a powerful mechanism to facilite the implementation of this contextual
help but current versions of Tk do not take advantage of this feature.
The feature cannot be implemented as an extension as a new event type
is needed so as to be informed from the OS that the user has chosen to
ask for help over that widget.

This contextual help is offered in the following way: when a window is
configured to have this option, a small question mark button is
displayed in the window title bar near the close button. If users pick
that button, a question mark cursor is actived and the user can pick a
widget \(or location in a widget.\)  The typical program reaction to
this is to offer a pop-up window with some short help text or to open
the program help in the relevant section.

Additionally, the new proposed event **<Help>** can also get
information when user presses key F1 over one window.

This implementation is proposed for the Windows OS only, though in the
future some Window Managers like KDE \(in Linux\) have the same feature
and could be also implemented.  In any case, this TIP only proposes
implementation on Windows.

# Specification

A new option will be added to **wm attributes** with the following
syntax:

 > **wm attributes** _window_ **-contexthelp** ?_boolean_?

If set and if the window is transient, the question mark button will
appear in the window title bar.

A new event **<Help>** is added to the event list so as a user can
do:

	  bind $w <Help> {puts "You pressed widget %W"}

This event will hit in two situations: when the user presses the
question mark in the title bar of the window and pick a widget; and
when user presses the F1 key \(or other platform-defined help key\) over
one window \(this latter case only for bindings in the toplevel\).

The event will support the usual %W %x %y substitutions and other
values.

# Reference Implementation

<http://sf.net/tracker/?func=detail&atid=312997&aid=845248&group\_id=12997>

# Comments

It would be preferable to use a virtual event **<<Help>>_ instead of extending the set of X events.  \(In particular, adding a new **<Help>** event means there has to be a new **HelpMask** bit flag to select for it, and we're running out of event mask bits\).

# Copyright

This document has been placed in the public domain.

Name change from tip/168.tip to tip/168.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

TIP:		168
Title:		Cubic Bezier Curves on the Canvas
Version:	$Revision: 1.10 $
Author:		Lars Hellstr�m <[email protected]>
Type:		Project
State:		Final
Tcl-Version:	8.5
Vote:		Done
Created:	25-Jan-2004
Post-History:	


~ Abstract

This document proposes a new '''-smooth''' method for '''line''' and
'''polygon''' canvas items that supports cubic Bezier curves and
clarifies some of the existing terminology in that area.

~ Proposal

A new method for the '''-smooth''' canvas item option will be defined.
Under this method, the points defining the item will be interpreted as
a sequence ''knot-point'' ''control-point'' ''control-point''
''knot-point'' ''control-point'' ''control-point'' ... of a curve
composed of cubic Bezier segments.  More precisely, if the list of
coordinates is

#image:168ab List of coordinates

then the ''N''th (counting from zero) segment of the curve consists of
points whose coordinates ''(x,y)'' satisfies

#image:168xy Parametric equations for x and y

for some value of ''t'' between 0 and 1, inclusive.  If there are
''3N+1'' points then the above defines an ''N'' segment curve.  In the
case that the number of points is ''3N'' or ''3N-1'' then they shall
still define an ''N'' segment curve, where in the first case the first
knot of the first segment is reused as the last knot in the last
segment, and in the second case the first knot and control point in
the first segment are reused as the last control point and knot in the
last segment respectively.

Straight line segments in the curve can be encoded as a segment where
the control points are equal to the neighbouring knot points.  While
this is not the only way to encode a straight line, it is a case that
is recognised and handled more efficiently by code that renders the
canvas item.

The name of this new method should be "'''raw'''".

The name of the existing '''-smooth''' method (as returned by the
itemcget widget command) should be changed from "'''bezier'''" to
"'''true'''", and the name "'''bezier'''", while at least in Tcl 8.5
still supported, should be deprecated.

~ Rationale

Cubic Bezier curves, being for example the native curve format in
Postscript and its descendants, is probably the most common format for
smooth curves in computing today.  It is even used internally in Tk;
for each segment of a '''-smooth 1''' curve, rendering starts with the
calculation of a cubic Bezier representation of that curve and
continues to use only this representation when approximating the
smooth curve with straight line segments.  Hence it might be claimed
that the cubic Bezier curve is the "raw" format of a smooth curve in
Tk.  No new calculations need to be implemented in the core to
implement this TIP, it is merely a matter of combining existing
functions in a suitable way and move data around.  Therefore it seems
a waste to not provide cubic Bezier curves, when they are anyway
already half implemented.

The reason for the interpretation of a curve with ''3N'' points given is
that this will cause the curve to be closed.  Conversely, omitting the
final knot point is sometimes used as a way of encoding the fact that
the curve should be closed.  This rule will therefore facilitate the
use of data where then omitted endpoint convention has been employed.
The only reason for the ''3N-1'' point rule is that it fits a simple
scheme (when at the end of the list of coordinates, continue from the
start) that supports the ''3N'' and ''3N+1'' cases.

The reason for deprecating the name "'''bezier'''" for the traditional
smoothing method is that it is at best confusing, and according to
many authorities simply wrong.  The term "Bezier curve" is very often
used as a synonym of "cubic Bezier curve", whence the majority of
programmers new to this feature of the canvas widget would probably
expect "'''-smooth bezier'''" to imply the effect of the smoothing option
proposed in this document rather than the smoothing via quadratic
splines that it currently is.  The amount of disappointment that could
result from the unpleasant discovery that what one thought was the
former is really the latter should not be underestimated.

The reason for changing the official name of the traditional smoothing
method to "'''true'''" are (i) that it is backwards compatible in the sense
that this name works for specifying that smoothing method in all Tk
versions and (ii) that it is somewhat mnemonic, because it happens to
coincide with the format used for curves in ''True''Type fonts.

~ Background

The question of what may rightfully be called "'''bezier'''" is somewhat
complicated and deserves expounding upon.  It really begins with
Bernstein; the ''Bernstein degree n form'' of a polynomial f is

#image:168f Bernstein degree n form polynomial

One advantage this form has over the standard form is that the
coefficients ''a_0, ..., a_n'' are directly comparable to the function
values ''f(0), f(1/n), f(2/n), ..., f(1)''; the two are generally not
equal (with the exception for the endpoints of the ''[[0,1]]'' interval),
but the function values approximates the sequence of coefficients in
various useful ways.  (Bernstein used it to give an elegant proof of
the Weierstrass Approximation Theorem.)

A ''Bezier curve'' (or Bernstein-Bezier curve, as it is sometimes
called) of degree ''n'' is a parametric curve ''P'' defined by a sequence of
''n+1'' points ''P_0, ..., P_n'' (known as the ''control points'' of the
curve) where each coordinate function is the Bernstein polynomial one
gets by taking as ''a_k'' the corresponding coordinate of the point ''P_k''
and parametric time goes from ''0'' to ''1''; formally

#image:168P Bernstein polynomial for points

for ''t'' between ''0'' and ''1'' inclusive.  Higher degree Bezier
curves are not used much in computer graphics (probably because the
effect on the curve of moving an single control point is often not
intuitively clear) but they do exist and it is not illogical to expect
that a

|  $canvas create line $points -smooth bezier

should be the degree-[[expr {[[llength $points]]/2 - 1}]] Bezier curve
defined by the given points.

Another term which often occurs when discussing computer graphic
curves is "spline".  A ''spline'' is a curve that passes through a set
of given points (the ''knots'' of the curve) in a given order,
satisfies some smoothness condition, and in some sense is best
possible under these conditions.  The most common optimality condition
is that the curve should be composed from segments that can be
parameterized by polynomials of given degree, but there are implicit
conditions (minimizing some suitable measure of curve deformation)
which leads to the same family of curves.

The '''-smooth 1''' curves of the Tk canvas are splines (of degree ''2'') in
this sense, even though the points used for defining them are (with
the exception for endpoints) not the knots of the spline.  (Rather,
the internal knots are the midpoints of the line segments joining two
adjacent control point.)  The '''raw''' curves proposed here are in
general ''not'' splines (because they admit discontinuous changes in
tangent direction, thus violating the smoothness condition), but they
often serve as an encoding for pre-computed degree 3 splines and this
use has lead to a confusion in terminology in this area.  It is not
uncommon that piecewise cubic Bezier curves in general are referred to
as "cubic splines", even though that is a more special concept.  It
may also be observed that the endpoints of the Bezier segments are
usually referred to as ''knots'' of the curve, whereas the term
"control points" is often reserved for the non-knot control points.
This rather harmless convention is for example used above.  Incorrect
use of the word "spline" should however be avoided.

~ Alternatives

It would be possible to provide the suggested functionality using a
compiled extension instead, but that seems a waste since almost all of
the functionality is present in the core anyway.

It would also be possible to use the semantics of the Tkspline package
[http://www.graphviz.org/cgi-bin/man?tkspline] '''-smooth''' method
providing cubic Bezier curves, but that package reverts to using the
'''-smooth true''' method of smoothing if the number of points is not ''3N+1'',
which doesn't seem useful and may cause bugs to be less visible.
Using the Tkspline syntax (calling the '''-smooth''' method "spline") should
probably be avoided even if the two methods were compatible, since the
curves produced in general aren't splines.

~ Implementation

A sample implementation of this proposal (minus the part about
changing the name of the existing '''-smooth''' method) exists
[http://sf.net/tracker/?func=detail&aid=886240&group_id=12997&atid=312997].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|


|

|

|
|



|

|
|

|

|
|
|
|











|

|
|
|


|




|










|




|
|
|

|




|






|

|
|

|

|

|

|


|
|
|

|
|

|
|
|
|
|
|

|

|
|

|


|

|



|
|




|


|
|
|

|
|
|





|




|






|

|

|



|

|
|
|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

# TIP 168: Cubic Bezier Curves on the Canvas

	Author:		Lars Hellström <[email protected]>
	Type:		Project
	State:		Final
	Tcl-Version:	8.5
	Vote:		Done
	Created:	25-Jan-2004
	Post-History:	
-----

# Abstract

This document proposes a new **-smooth** method for **line** and
**polygon** canvas items that supports cubic Bezier curves and
clarifies some of the existing terminology in that area.

# Proposal

A new method for the **-smooth** canvas item option will be defined.
Under this method, the points defining the item will be interpreted as
a sequence _knot-point_ _control-point_ _control-point_
_knot-point_ _control-point_ _control-point_ ... of a curve
composed of cubic Bezier segments.  More precisely, if the list of
coordinates is

![List of coordinates](../assets/168ab.png)

then the _N_th \(counting from zero\) segment of the curve consists of
points whose coordinates _\(x,y\)_ satisfies

![Parametric equations for x and y](../assets/168xy.png)

for some value of _t_ between 0 and 1, inclusive.  If there are
_3N\+1_ points then the above defines an _N_ segment curve.  In the
case that the number of points is _3N_ or _3N-1_ then they shall
still define an _N_ segment curve, where in the first case the first
knot of the first segment is reused as the last knot in the last
segment, and in the second case the first knot and control point in
the first segment are reused as the last control point and knot in the
last segment respectively.

Straight line segments in the curve can be encoded as a segment where
the control points are equal to the neighbouring knot points.  While
this is not the only way to encode a straight line, it is a case that
is recognised and handled more efficiently by code that renders the
canvas item.

The name of this new method should be "**raw**".

The name of the existing **-smooth** method \(as returned by the
itemcget widget command\) should be changed from "**bezier**" to
"**true**", and the name "**bezier**", while at least in Tcl 8.5
still supported, should be deprecated.

# Rationale

Cubic Bezier curves, being for example the native curve format in
Postscript and its descendants, is probably the most common format for
smooth curves in computing today.  It is even used internally in Tk;
for each segment of a **-smooth 1** curve, rendering starts with the
calculation of a cubic Bezier representation of that curve and
continues to use only this representation when approximating the
smooth curve with straight line segments.  Hence it might be claimed
that the cubic Bezier curve is the "raw" format of a smooth curve in
Tk.  No new calculations need to be implemented in the core to
implement this TIP, it is merely a matter of combining existing
functions in a suitable way and move data around.  Therefore it seems
a waste to not provide cubic Bezier curves, when they are anyway
already half implemented.

The reason for the interpretation of a curve with _3N_ points given is
that this will cause the curve to be closed.  Conversely, omitting the
final knot point is sometimes used as a way of encoding the fact that
the curve should be closed.  This rule will therefore facilitate the
use of data where then omitted endpoint convention has been employed.
The only reason for the _3N-1_ point rule is that it fits a simple
scheme \(when at the end of the list of coordinates, continue from the
start\) that supports the _3N_ and _3N\+1_ cases.

The reason for deprecating the name "**bezier**" for the traditional
smoothing method is that it is at best confusing, and according to
many authorities simply wrong.  The term "Bezier curve" is very often
used as a synonym of "cubic Bezier curve", whence the majority of
programmers new to this feature of the canvas widget would probably
expect "**-smooth bezier**" to imply the effect of the smoothing option
proposed in this document rather than the smoothing via quadratic
splines that it currently is.  The amount of disappointment that could
result from the unpleasant discovery that what one thought was the
former is really the latter should not be underestimated.

The reason for changing the official name of the traditional smoothing
method to "**true**" are \(i\) that it is backwards compatible in the sense
that this name works for specifying that smoothing method in all Tk
versions and \(ii\) that it is somewhat mnemonic, because it happens to
coincide with the format used for curves in _True_Type fonts.

# Background

The question of what may rightfully be called "**bezier**" is somewhat
complicated and deserves expounding upon.  It really begins with
Bernstein; the _Bernstein degree n form_ of a polynomial f is

![Bernstein degree n form polynomial](../assets/168f.png)

One advantage this form has over the standard form is that the
coefficients _a\_0, ..., a\_n_ are directly comparable to the function
values _f\(0\), f\(1/n\), f\(2/n\), ..., f\(1\)_; the two are generally not
equal \(with the exception for the endpoints of the _[0,1]_ interval\),
but the function values approximates the sequence of coefficients in
various useful ways.  \(Bernstein used it to give an elegant proof of
the Weierstrass Approximation Theorem.\)

A _Bezier curve_ \(or Bernstein-Bezier curve, as it is sometimes
called\) of degree _n_ is a parametric curve _P_ defined by a sequence of
_n\+1_ points _P\_0, ..., P\_n_ \(known as the _control points_ of the
curve\) where each coordinate function is the Bernstein polynomial one
gets by taking as _a\_k_ the corresponding coordinate of the point _P\_k_
and parametric time goes from _0_ to _1_; formally

![Bernstein polynomial for points](../assets/168P.png)

for _t_ between _0_ and _1_ inclusive.  Higher degree Bezier
curves are not used much in computer graphics \(probably because the
effect on the curve of moving an single control point is often not
intuitively clear\) but they do exist and it is not illogical to expect
that a

	  $canvas create line $points -smooth bezier

should be the degree-[expr {[llength $points]/2 - 1\}] Bezier curve
defined by the given points.

Another term which often occurs when discussing computer graphic
curves is "spline".  A _spline_ is a curve that passes through a set
of given points \(the _knots_ of the curve\) in a given order,
satisfies some smoothness condition, and in some sense is best
possible under these conditions.  The most common optimality condition
is that the curve should be composed from segments that can be
parameterized by polynomials of given degree, but there are implicit
conditions \(minimizing some suitable measure of curve deformation\)
which leads to the same family of curves.

The **-smooth 1** curves of the Tk canvas are splines \(of degree _2_\) in
this sense, even though the points used for defining them are \(with
the exception for endpoints\) not the knots of the spline.  \(Rather,
the internal knots are the midpoints of the line segments joining two
adjacent control point.\)  The **raw** curves proposed here are in
general _not_ splines \(because they admit discontinuous changes in
tangent direction, thus violating the smoothness condition\), but they
often serve as an encoding for pre-computed degree 3 splines and this
use has lead to a confusion in terminology in this area.  It is not
uncommon that piecewise cubic Bezier curves in general are referred to
as "cubic splines", even though that is a more special concept.  It
may also be observed that the endpoints of the Bezier segments are
usually referred to as _knots_ of the curve, whereas the term
"control points" is often reserved for the non-knot control points.
This rather harmless convention is for example used above.  Incorrect
use of the word "spline" should however be avoided.

# Alternatives

It would be possible to provide the suggested functionality using a
compiled extension instead, but that seems a waste since almost all of
the functionality is present in the core anyway.

It would also be possible to use the semantics of the Tkspline package
<http://www.graphviz.org/cgi-bin/man?tkspline>  **-smooth** method
providing cubic Bezier curves, but that package reverts to using the
**-smooth true** method of smoothing if the number of points is not _3N\+1_,
which doesn't seem useful and may cause bugs to be less visible.
Using the Tkspline syntax \(calling the **-smooth** method "spline"\) should
probably be avoided even if the two methods were compatible, since the
curves produced in general aren't splines.

# Implementation

A sample implementation of this proposal \(minus the part about
changing the name of the existing **-smooth** method\) exists
<http://sf.net/tracker/?func=detail&aid=886240&group_id=12997&atid=312997> .

# Copyright

This document has been placed in the public domain.

Name change from tip/169.tip to tip/169.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

TIP:            169
Title:          Add Peer Text Widgets
Version:        $Revision: 1.15 $
Author:         Brian Griffin <[email protected]>
Author:         Vince Darley <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        28-Jan-2004
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes adding a method to the text widget that will create
peer text widgets, allowing two or more text widgets to share the
same text, tags, and marks.

~ Rationale

One of the features offered by many text editors is the ability to
split the view of text being edited.  Currently editors based on the
Tk text widget are required to create multiple widgets, duplicating
all insert, delete, etc., operations on both widgets.  The current
text widget already separates almost all aspects of the data from the widget rendering and
it would be a simple task to allow two (or more) widgets to share this
data.

~ Proposed Change

The primary change is the addition of a 'peer' subcommand to any text widget, as follows:

| $text peer create ...
| $text peer names

The proposed implementation splits the widget structure into two
pieces, sharable data and widget specific rendering parts.  The text
tree, tags (including their colours and fonts), marks, images, and undo stack would be placed in a
reference counted, shared section, while the widget configuration options for tkwin, fonts, colors,
bindings, etc., would remain with the widget.  A method (peer create)
is added that will create a new widget that will share the data with
it's "parent."  The shared data also contains a list of peers which
is used to propagate widget updates when the data changes.

|set widget [text .text]
|set peer [$widget peer create .peer]

Once a peer is created it has all the rights and privileges of the
creating parent.  There is no restriction on the peer's window pathname.
The creating parent may also be destroyed without affecting the peer;
only when the last window (peer or parent) is destroyed will the data be
deleted.

In keeping with Tcl's introspection nature, a "peer names" method is
added that will return a list of peer widgets.  This list does not
include itself.

Lastly, all text widgets take two new configuration options to specify that the peer only shows a subset of the lines from the underling b-tree:

|set peer [$widget peer create .peer -startline 53 -endline 125]

will create a peer which contains lines 53 to 125 of the underlying data store.  The default is for a peer to contain the same range of lines as its 'parent', but one can use '-startline {} -endline {}' to force use of the entire b-tree.

Any peer widget can access a list of all ''other'' peers, via the 'peer names' command:

| set peerlist [$widget peer names]

This list does not include $widget itself.

~ Detailed Description

All geometry/pixel-height information for peer widgets are calculated
separately for each peer.  This means each peer can have different
height, width, scrollbar state, (even overall font size) with no
problems.

The 'sel', 'insert', 'current' tag/marks are not shared.  They are
widget specific.  Similarly the '-window' attribute of any embedded
window is not shared, but widget specific (i.e. it can be configured
separately for each peer).  The '-create' option of an embedded window
now supports % substitution of its script to allow multiple peers all to
have embedded windows in a relatively easy fashion.  '%W' is substituted
by the embedding text widget pathname and '%%' by '%'.  So, for example,
the following test works nicely:

|test textWind-17.6 {peer widget window configuration} {
|    catch {destroy .t .tt}
|    pack [text .t]
|    .t delete 1.0 end
|    .t insert 1.0 "Some sample text"
|    toplevel .tt
|    pack [.t peer create .tt.t]
|    .t window create 1.2 -create {frame %W.f -width 10 -height 20 -bg blue}
|    update ; update
|    set res [list [.t window configure 1.2 -window] \
|      [.tt.t window configure 1.2 -window]]
|    destroy .tt .t
|    set res
|} {{-window {} {} {} .t.f} {-window {} {} {} .tt.t.f}}

All top-level text configuration options are widget-specific except
those which involve the undo/redo/modified status of the widget, which
are shared.

~ Further changes

It has been pointed out that some uses of the 'sel' tag in existing Tk-based editors require an additional tag for use when a given widget does not have the input focus (a 'background sel' tag), particularly on Windows/MacOS X where [https://sourceforge.net/tracker/?func=detail&atid=112997&aid=1014213&group_id=12997] applies (selection is never shown in text widgets which don't have the focus).  Such an approach would not work with peer widgets, because the 'background sel' tag would show up on all peers.  This means the cited problem needs to be fixed, and we need programmatic control over the visualization of the "sel" tag in text widgets that don't have the focus.  The proposed solution is the addition of a 'inactiveSelectionBackground' option to each text overall widget.  This new text widget configuration option can take the {} value, in which case the selection is not shown when the widget is not active, or if it takes a value, then that is the colour to use for the inactive selection.  This option is peer-widget-specific (and is effectively implemented by over-riding the 'sel' background colour if the widget doesn't have the focus; a minor modification to the current code on Win/MacOS which ignores 'sel' when the widget doesn't have the focus).

~ To Do

In the current patch (and in the original version of this TIP), bindings are not shared, but remain with the widget.  Currently this
includes tag bindings, but I think it would be better if tag bindings were shared (given that tags 
are shared).  Unless anyone has a use-case showing why they should be
independent, I'll update the implementation accordingly.  Therefore shared tag bindings should be considered part of this TIP.

~ Alternatives

This does not preclude a future TIP from going further and making the B-tree data structure a fully-fledged Tcl structure (like an array or a dict or whatever), of which the text widget is just one example of a client.  However, such issues are beyond the scope of this TIP (except to point out that the implementation is, by necessity, many steps in the same direction).

~ Reference Implementation

A reference implementation based on Tcl 8.5 is available at:

http://sourceforge.net/tracker/?func=detail&atid=312997&aid=994629&group_id=12997

This includes new tests and documentation, and an update to one of the Text widget demos to show off the new functionality.

Incidentally, this patch also fixes the long-standing problem where renaming the text widget breaks the undo-stack (which used to record the actual widget name).

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|






|


|



|
|



|

|




|
|




|








|

|

|

|



|



|




|
|





|
|
|
|
|
|
|
|
|
|
|
|
|
|





|

|

|

|
|
|


|

|

|



|



|

|


>

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

# TIP 169: Add Peer Text Widgets

	Author:         Brian Griffin <[email protected]>
	Author:         Vince Darley <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        28-Jan-2004
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes adding a method to the text widget that will create
peer text widgets, allowing two or more text widgets to share the
same text, tags, and marks.

# Rationale

One of the features offered by many text editors is the ability to
split the view of text being edited.  Currently editors based on the
Tk text widget are required to create multiple widgets, duplicating
all insert, delete, etc., operations on both widgets.  The current
text widget already separates almost all aspects of the data from the widget rendering and
it would be a simple task to allow two \(or more\) widgets to share this
data.

# Proposed Change

The primary change is the addition of a 'peer' subcommand to any text widget, as follows:

	 $text peer create ...
	 $text peer names

The proposed implementation splits the widget structure into two
pieces, sharable data and widget specific rendering parts.  The text
tree, tags \(including their colours and fonts\), marks, images, and undo stack would be placed in a
reference counted, shared section, while the widget configuration options for tkwin, fonts, colors,
bindings, etc., would remain with the widget.  A method \(peer create\)
is added that will create a new widget that will share the data with
it's "parent."  The shared data also contains a list of peers which
is used to propagate widget updates when the data changes.

	set widget [text .text]
	set peer [$widget peer create .peer]

Once a peer is created it has all the rights and privileges of the
creating parent.  There is no restriction on the peer's window pathname.
The creating parent may also be destroyed without affecting the peer;
only when the last window \(peer or parent\) is destroyed will the data be
deleted.

In keeping with Tcl's introspection nature, a "peer names" method is
added that will return a list of peer widgets.  This list does not
include itself.

Lastly, all text widgets take two new configuration options to specify that the peer only shows a subset of the lines from the underling b-tree:

	set peer [$widget peer create .peer -startline 53 -endline 125]

will create a peer which contains lines 53 to 125 of the underlying data store.  The default is for a peer to contain the same range of lines as its 'parent', but one can use '-startline \{\} -endline \{\}' to force use of the entire b-tree.

Any peer widget can access a list of all _other_ peers, via the 'peer names' command:

	 set peerlist [$widget peer names]

This list does not include $widget itself.

# Detailed Description

All geometry/pixel-height information for peer widgets are calculated
separately for each peer.  This means each peer can have different
height, width, scrollbar state, \(even overall font size\) with no
problems.

The 'sel', 'insert', 'current' tag/marks are not shared.  They are
widget specific.  Similarly the '-window' attribute of any embedded
window is not shared, but widget specific \(i.e. it can be configured
separately for each peer\).  The '-create' option of an embedded window
now supports % substitution of its script to allow multiple peers all to
have embedded windows in a relatively easy fashion.  '%W' is substituted
by the embedding text widget pathname and '%%' by '%'.  So, for example,
the following test works nicely:

	test textWind-17.6 {peer widget window configuration} {
	    catch {destroy .t .tt}
	    pack [text .t]
	    .t delete 1.0 end
	    .t insert 1.0 "Some sample text"
	    toplevel .tt
	    pack [.t peer create .tt.t]
	    .t window create 1.2 -create {frame %W.f -width 10 -height 20 -bg blue}
	    update ; update
	    set res [list [.t window configure 1.2 -window] \
	      [.tt.t window configure 1.2 -window]]
	    destroy .tt .t
	    set res
	} {{-window {} {} {} .t.f} {-window {} {} {} .tt.t.f}}

All top-level text configuration options are widget-specific except
those which involve the undo/redo/modified status of the widget, which
are shared.

# Further changes

It has been pointed out that some uses of the 'sel' tag in existing Tk-based editors require an additional tag for use when a given widget does not have the input focus \(a 'background sel' tag\), particularly on Windows/MacOS X where <https://sourceforge.net/tracker/?func=detail&atid=112997&aid=1014213&group_id=12997>  applies \(selection is never shown in text widgets which don't have the focus\).  Such an approach would not work with peer widgets, because the 'background sel' tag would show up on all peers.  This means the cited problem needs to be fixed, and we need programmatic control over the visualization of the "sel" tag in text widgets that don't have the focus.  The proposed solution is the addition of a 'inactiveSelectionBackground' option to each text overall widget.  This new text widget configuration option can take the \{\} value, in which case the selection is not shown when the widget is not active, or if it takes a value, then that is the colour to use for the inactive selection.  This option is peer-widget-specific \(and is effectively implemented by over-riding the 'sel' background colour if the widget doesn't have the focus; a minor modification to the current code on Win/MacOS which ignores 'sel' when the widget doesn't have the focus\).

# To Do

In the current patch \(and in the original version of this TIP\), bindings are not shared, but remain with the widget.  Currently this
includes tag bindings, but I think it would be better if tag bindings were shared \(given that tags 
are shared\).  Unless anyone has a use-case showing why they should be
independent, I'll update the implementation accordingly.  Therefore shared tag bindings should be considered part of this TIP.

# Alternatives

This does not preclude a future TIP from going further and making the B-tree data structure a fully-fledged Tcl structure \(like an array or a dict or whatever\), of which the text widget is just one example of a client.  However, such issues are beyond the scope of this TIP \(except to point out that the implementation is, by necessity, many steps in the same direction\).

# Reference Implementation

A reference implementation based on Tcl 8.5 is available at:

<http://sourceforge.net/tracker/?func=detail&atid=312997&aid=994629&group\_id=12997>

This includes new tests and documentation, and an update to one of the Text widget demos to show off the new functionality.

Incidentally, this patch also fixes the long-standing problem where renaming the text widget breaks the undo-stack \(which used to record the actual widget name\).

# Copyright

This document has been placed in the public domain.

Name change from tip/17.tip to tip/17.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193

194
195
196
197
198

199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289

290
291
292
293
294
295

296
297
298
299
300

301
302
303

304
305
306

307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648

TIP:            17
Title:          Redo Tcl's filesystem
Version:        $Revision: 1.18 $
Author:         Vince Darley <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        17-Nov-2000
Post-History:   
Tcl-Version:    8.4.0


~ Abstract

Many of the most exciting recent developments in Tcl have involved
putting virtual file systems in a file (e.g. Prowrap, Freewrap, Wrap,
TclKit) but these have been largely ''ad hoc'' hacks of various
internal APIs.  This TIP seeks to replace this with a common underlying
API that will, in addition, make porting of Tcl to new platforms a
simpler task as well.

~ Overview

There are two current drawbacks to Tcl's filesystem implementation:

  * virtual filesystems are not properly supported.

  * it is all string-based, rather than Tcl_Obj-based.

Prowrap (http://sourceforge.net/projects/tclpro), Freewrap
(http://home.nycap.rr.com/dlabelle/freewrap/freewrap.html), Wrap
(http://members1.chello.nl/~j.nijtmans/wrap.html), TclKit
(http://www.equi4.com/jcw/wiki.cgi/19.html), ...  are all attempts to
provide an ability to place Tcl scripts and other data inside a single
file (or just a small number of files).  The best and simplest way to
achieve that task (and many other useful tasks) is to let Tcl handle
the contents of a single 'wrapped document' as if it were a
filesystem: the contents may be opened, sourced, stat'd, copied,
globbed, etc.  Also note that at the European Tcl/Tk meeting, the (equal) second-ranked request for Tcl was support for standalone executables (http://mini.net/cgi-bin/wikit/837.html).

This TIP suggests that Tcl's core be modified to allow non-native
filesystems to be plugged in to the core, and hence allow ''perfect''
virtual filesystems to exist.  The implementations provided by all of
the above tools are very far from perfect.  The most obvious types of
virtual filesystem which should be supported are:

  * wrapped/archived document 'bundles' such as TclKits, .zip files,
    etc.

  * remote filesystems (e.g. an FTP site).

but the main point is that all filesystem access should occur through 
a hookable interface, so that Tcl neither knows nor cares what type of
filesystem it is dealing with.

Furthermore this hookable interface should be Tcl_Obj based, providing
a new 'Path' object type, which should be designed with two goals in
mind:

  * allow caching of 'native path representations' (all native Tclp...
    filesystem calls involve various Utf->Native conversions).  For example,
    quick testing for 'file exists' shows that a 20% speed up can be achieved
    by caching the native representation (Windows 2000sp1).

  * allow virtual filesystems to operate very efficiently - this will
    probably require caching of the filesystem to use for a particular
    file.

If all of these goals are achieved, Tcl will have a new filesystem
which is both more efficient and more powerful than the existing
implementation.

~ Technical discussion

 1. Virtual filesystems

  > An examination of the core shows that a very limited support was
    added to tclIOUtil.c in June 1998 (presumably by Scriptics to
    support prowrap) so that TclStat, TclAccess and
    Tcl_OpenFileChannel commands could be intercepted.  (See
    http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/tcl/generic/tclIOUtil.c?rev=1.2&content-type=text/x-cvsweb-markup&cvsroot=tcl)

  > This TIP seeks to provide a ''complete'' implementation of virtual
    file system support, rather than these piecemeal functions.

  > Fortunately, since Tcl is already abstracted across three
    different filesystem types (through the Tclp...) functions, it is
    not that big a task to abstract away to any generic filesystem.

  > One goal of this TIP is to allow an ''extension'' to be written so
    that one can implement a virtual filesystem entirely in Tcl:
    i.e. to provide sufficient hooks into Tcl's core so that an
    extension can capture all filesystem requests and divert them if
    desired.  The goal is not to provide Tcl-level hooks in Tcl's
    core.  Such hooks will only be at the C level, and an extension
    would be required to expose them to the Tcl level.

 2. Objectified filesystem interface.

  > Every filesystem access in Tcl's core usually involves several
    calls to 'access', 'stat', etc.

  > For example 'file atime $path' requires two calls to 'stat' and
    one call to 'utime', all with the same $path argument.  Each of
    these requires a conversion from the same Utf path to the same
    native string representation.  No caching is performed, so each of
    these goes through Tcl_UtfToExternal.  Often Tcl code will use the
    same $path objects for an entire sequence of Tcl 'file'
    operations.  Clearly a representation which cached the native path
    would speed up all of these operations (except the first).

  > The second reason why objectification is desirable is that in a
    pluggable-fs environment we must determine, for each file
    operation, which filesystem to use (whether native, a mounted .zip
    file, a remote FTP site, etc.).  If this information can be cached
    for a particular path, again we will not need to recalculate it at
    every step.  A similar technique to that used by Tcl's bytecode
    compilation will be used: each cached object will have a
    "filesystemEpoch" counter, so that we can tell with each access
    whether the filesystem has been modified (and we must discard the
    cached information).  Mounting/unmounting filesystems will
    obviously modify the filesystemEpoch.

 > A relatively complete implementation of this TIP, and a sample "vfs"
    extension
    now exist, and have been tested through TclKit.  On both the "virtual"
    and "objectification" parts of this tip, the implementation is known to be
    stable and complete (at least on Windows): TclKit can operate 
    through this new vfs
    implementation without the need to override a single Tcl core
    command at the script level, and all reasonable filesystem tests
    (cmdAH.test, fCmd.test, fileName.test, io.test) pass in a scripted document.
    Commands which operate on files
    (image, source, etc.)  and extensions like Image, Winico can be
    made to work in a TclKit automatically!  There is still some
    room for optimisation in some parts of the new objectification
    code (which wasn't
    possible in the old string-based API).  The current
    implementation has
    great efficiency gains for vfs's
    implemented at the script level, since the same Path objects can
    be passed through the entire process, without an intermediate
    conversion (and string duplication which would otherwise be
    required).
    The combination of caching and objectification changes the
    existing list of steps from

|Tcl_Obj -> string -> filesystem -> convert-to-native -> native-call

  > or (with vfs hooked in)

|Tcl_Obj -> string -> vfilesystem -> pick-filesystem
|                          -> convert-to-native -> native-call

  > and

|Tcl_Obj -> string -> vfilesystem -> pick-filesystem
|                          -> Tcl_NewStringObj -> Tcl-vfs-call

  > to

|Tcl_Obj -> vfilesystem -> native-call

  > and

|Tcl_Obj -> vfilesystem -> Tcl-vfs-call

----

A final side-benefit of this proposal would be that it further
modularises the core of Tcl, so that one could, in principle:

  * remove the native filesystem support entirely from Tcl (perhaps
    useful for embedded devices etc), since there will be a clean
    layer separating Tcl from its native filesystem functionality.

  * use Tcl's filesystem for other purposes (outside of Tcl).

However these final two points are explicitly ''not'' the goal of this
TIP!  I simply want to improve Tcl to add vfs support, and the best
way to do that seems (to me) to be along the lines of this TIP.

~ Proposal

The changes to Tcl's core for virtual filesystem support are actually
very minor.  Every occurrence of a
Tclp-filesystem call must be replaced by a call to a hookable
procedure.  The current filesystem structure (defined in tclInt.h) and
hookable procedure list is as follows (for documentation on this
structure, see Documentation section below):

|/*
| * struct Tcl_Filesystem:
| *

| * One such structure exists for each type (kind) of filesystem.
| * It collects together in one place all the functions that are
| * part of the specific filesystem.  Tcl always accesses the
| * filesystem through one of these structures.
| * 

| * Not all entries need be non-NULL; any which are NULL are simply
| * ignored.  However, a complete filesystem should provide all of
| * these functions.
| */
|
|typedef struct Tcl_Filesystem {
|    CONST char *typeName;   /* The name of the filesystem. */
|    int structureLength;    /* Length of this structure, so future
|                             * binary compatibility can be assured. */
|    Tcl_FilesystemVersion version;  
|                            /* Version of the filesystem type. */
|    TclfsPathInFilesystem_ *pathInFilesystemProc;
|                            /* Function to check whether a path is in this
|                             * filesystem */
|    TclfsDupInternalRep_ *dupInternalRepProc;
|                            /* Function to duplicate internal fs rep */ 
|    TclfsFreeInternalRep_ *freeInternalRepProc;
|                            /* Function to free internal fs rep */ 
|    TclfsInternalToNormalizedProc_ *internalToNormalizedProc_;
|                            /* Function to convert internal representation
|                             * to a normalized path */
|    TclfsConvertToInternalProc_ *convertToInternalProc_;
|			    /* Function to convert object to an
|			     * internal representation */
|    TclfsStatProc_ *statProc; /* Function to process a 'Tcl_Stat()' call */
|    TclfsAccessProc_ *accessProc;            
|                            /* Function to process a 'Tcl_Access()' call */
|    TclfsOpenFileChannelProc_ *openFileChannelProc; 
|                            /* Function to process a 'Tcl_OpenFileChannel()' call */
|    TclfsMatchInDirectoryProc_ *matchInDirectoryProc;  
|                            /* Function to process a 'Tcl_MatchInDirectory()' */
|    TclfsGetCwdProc_ *getCwdProc;     
|                            /* Function to process a 'Tcl_GetCwd()' call */
|    TclfsChdirProc_ *chdirProc;            
|                            /* Function to process a 'Tcl_Chdir()' call */
|    TclfsLstatProc_ *lstatProc;            
|                            /* Function to process a 'Tcl_Lstat()' call */
|    TclfsCopyFileProc_ *copyFileProc; 
|                            /* Function to process a 'Tcl_CopyFile()' call */
|    TclfsDeleteFileProc_ *deleteFileProc;            
|                            /* Function to process a 'Tcl_DeleteFile()' call */
|    TclfsRenameFileProc_ *renameFileProc;            
|                            /* Function to process a 'Tcl_RenameFile()' call */
|    TclfsCreateDirectoryProc_ *createDirectoryProc;            
|                            /* Function to process a 'Tcl_CreateDirectory()' call */
|    TclfsCopyDirectoryProc_ *copyDirectoryProc;            
|                            /* Function to process a 'Tcl_CopyDirectory()' call */
|    TclfsRemoveDirectoryProc_ *removeDirectoryProc;            
|                            /* Function to process a 'Tcl_RemoveDirectory()' call */
|    TclfsLoadFileProc_ *loadFileProc; 
|                            /* Function to process a 'Tcl_LoadFile()' call */
|    TclfsUnloadFileProc_ *unloadFileProc;            
|                            /* Function to unload a previously successfully
|                             * loaded file */
|    TclfsReadlinkProc_ *readlinkProc; 
|                            /* Function to process a 'Tcl_Readlink()' call */
|    TclfsListVolumesProc_ *listVolumesProc;            
|                            /* Function to list any filesystem volumes added
|                             * by this filesystem */
|    TclfsFileAttrStringsProc_ *fileAttrStringsProc;
|                            /* Function to list all attributes strings which
|                             * are valid for this filesystem */
|    TclfsFileAttrsGetProc_ *fileAttrsGetProc;
|                            /* Function to process a 'Tcl_FileAttrsGet()' call */
|    TclfsFileAttrsSetProc_ *fileAttrsSetProc;
|                            /* Function to process a 'Tcl_FileAttrsSet()' call */
|    TclfsUtimeProc_ *utimeProc;       
|                            /* Function to process a 'Tcl_Utime()' call */
|    TclfsNormalizePathProc_ *normalizePathProc;       
|                            /* Function to normalize a path */
|} Tcl_Filesystem;

Once that is done, almost no more ''changes'' need be made to Tcl's
core.  We must simply add code (to tclIOUtil.c and declarations to
tclInt.h) to implement the hookable functions and to provide a simple
API by which extensions can hook into the new filesystem support.

This gives us the simplest level of vfs.  Most remaining changes are
objectifying the way Tcl's core uses filesystems.  Many of these
changes actually simplify the core, for example, we replace:

|        case FILE_COPY: {
|            int result;
|            char **argv;
|
|            argv = StringifyObjects(objc, objv);
|            result = TclFileCopyCmd(interp, objc, argv);
|            ckfree((char *) argv);
|            return result;
|        }            


with

|        case FILE_COPY: {
|            return TclFileCopyCmd(interp, objc, objv);
|        }            


and the Unix versions of stat, access, chdir are as simple as:

|int TclpObjStat(Tcl_Obj *pathPtr, struct stat *buf) {
|    return stat(Tclfs_GetNativePath(pathPtr), buf);
|}

|int TclpObjChdir(Tcl_Obj *pathPtr) {
|    return chdir(Tclfs_GetNativePath(pathPtr));
|}

|int TclpObjAccess(Tcl_Obj *pathPtr, int mode) {
|    return access(Tclfs_GetNativePath(pathPtr));
|}


There are a few other small changes required, some which are
absolutely necessary, and some which make the implementation
of a Tcl-level vfs much simpler and more robust:

  * Cross-filesystem copy and rename operations will fail.  A patch was
    added so that Tcl can fall back on 'open r/open w/fcopy/file mtime'
    as a copying method for files, and a new function ::tcl::copyDirectory
    for directories.  These techniques are only used if the source/dest
    are in different filesystems, or if the filesystem Tcl tries to use
    returns the EXDEV posix result in 'errno'.  This is a natural
    extension of Tcl's current way of falling back from 'rename' to 
    'copy and delete'.

  * Add ''-tails'' flag to ''glob'' (and internally to ''TclGlob'') to
    indicate that we only want the tails of the files to be returned.

  * Add ''file normalize path'' subcommand to ''file'', which returns
    an absolute path in which all "..", "." sequences have been
    removed, and the file is a platform-normalized path (e.g. the
    longname is used on windows).

  * Modify the TclDoGlob implementation so it handles recursion itself,
    rather than passing it on to the various TclpMatchFilesTypes functions.
    This simplifies the platform-specific code, and makes vfs support of
    ''glob'' much more robust, easy, complete, etc.  This has the side-
    benefit that TclpMatchFilesTypes need not operate directly on
    the interpreter's result.  The simpler function with a different
    signature has been named ''TclpMatchInDirectory''.

  * Modify the implementation of ''encoding names'' to use the
    TCL_GLOBMODE_TAILS flag to TclGlob, simplifying that code.

  * Add an API to tclIO.c to allow us to Unregister a channel
    ''without'' deleting it.  We need this to be able to take a
    channel created in Tcl (registered and with refcount of 1) and
    turn it into a "pristine channel with refcount 0" as returned by
    Tcl_OpenFileChannel.  This is called ''Tcl_DetachChannel''.

  * Add a function to tclInt.decls called 'TclpVerifyInitialEncodings'
    which is required when all of Tcl is packaged in a virtual 
    filesystem (e.g. TclKit), since Tcl's very early call to 
    TclpSetInitialEncodings fails to achieve anything useful.

  * the perfect vfs support can have some weird side-effects.  For
    instance, if I embed all of tcltest and tests/ inside a TclKit,
    and try to source 'all.tcl', I get errors that each file does not
    exist.  This is because the test code tries to pipe each file in
    turn to a newly created tcl process (open "| tclsh foo.test r"),
    but the files don't really exist (as far as the OS is concerned). 
    We therefore add an introspection command 'file system
    $path' which returns a list of two items: the name of the 
    filesystem and the type of the file within that filesystem.
    For example it might be 'native local', 'native networked',
    'vfs ftp', 'vfs zip' etc.

  * vfs systems on different platforms may require different directory
    separator characters (different to the native characters), 
    especially on MacOS (in which a valid file might be 
    ''HD:Tcl:tcl.zip/lib/tcl8.4/history.tcl''), and we therefore add
    'file separator ?filename?' command to retrieve the correct
    separator to use.

As mentioned above an implementation of all of this now exists.  The
modified Tcl core passes all Tcl tests, and works with a new version of
TclKit (which can itself pass all reasonable tests when executing the
test suite inside a scripted document).  It has
been tested with a variety of wrapped demos (tclhttpd, bwidgets,
widgets, alphatk), and performs very well.  The patch is available
from the author of this TIP, and a version (possibly not the most recent) can be downloaded from: ftp://ftp.ucsd.edu/pub/alpha/tcl/tclobjvfs.diff 

~ Documentation: vfs-aware extensions

All calls to filesystem functions in Tcl's core and in extensions
should preferably be made through the new API defined in tclInt.decls.
All these functions have the prefix 'Tclfs_'.  Of course extensions
which call older string-based APIs (e.g. Tcl_OpenFileChannel) will
still work, but will not benefit from the efficiency of the cached
object representation.  Most of these functions are not commonly used
by extensions (e.g. Tclfs_CopyDirectory), so only the most common are 
listed here:

|    Tcl_Channel Tclfs_OpenFileChannel(Tcl_Interp *interp, Tcl_Obj *pathPtr,
|                                      char *modeString, int permissions)
|    int         Tclfs_EvalFile(Tcl_Interp *interp, Tcl_Obj *fileName)
|    int         Tclfs_Stat(Tcl_Obj *pathPtr, struct stat *buf)
|    int         Tclfs_Access(Tcl_Obj *pathPtr, int mode)

These replace the equivalent string-based APIs.

|    int      Tclfs_ConvertToPathType(Tcl_Interp *interp, Tcl_Obj *pathPtr)

Attempts to convert the given object to a path type.  This is a little
more than a simple
wrapper around ''Tcl_ConvertToType(interp, pathPtr, &tclFsPathType)''.
If it returns TCL_ERROR, the object is not a valid path.  In this
sense it is very similar to Tcl_TranslateFileName for the existing
string-based API.  It should be called before attempting to pass
an object to any of the other filesystem APIs (again in much the same
way as Tcl_TranslateFileName was used in the core).

|    int      Tclfs_EqualPaths(Tcl_Obj* firstPtr, Tcl_Obj* secondPtr)
|    Tcl_Obj* Tclfs_SplitPath(Tcl_Obj* pathPtr, int *lenPtr)
|    Tcl_Obj* Tclfs_JoinPath(Tcl_Obj *listObj, int elements)
|    Tcl_Obj* Tclfs_JoinToPath(Tcl_Obj *basePtr, int objc, Tcl_Obj *CONST objv[])

These all manipulate paths.  They return Tcl_Obj* with refCounts of
zero.

|    Tcl_Obj* Tclfs_GetNormalizedPath(Tcl_Interp *interp, Tcl_Obj* pathObjPtr)
|    char*    Tclfs_GetTranslatedPath(Tcl_Interp *interp, Tcl_Obj* pathPtr)

and finally:

|    char*    Tclfs_GetNativePath(Tcl_Obj* pathObjPtr)

which is used by native filesystems only, and is a shorthand for
getting at the cached native representation for MacOS, Windows or
Unix (as appropriate).  This is always a string based representation,
but may really be of type TCHAR* on Windows, for example.

~ Documentation: writing a new filesystem

The ''objPtr->internalRep.otherValuePtr'' field is a pointer
to one of these structures, for objects of "path" type.

|typedef struct FsPath {
|    char *translatedPathPtr;    /* Name without any ~user sequences */
|    Tcl_Obj *normPathPtr;       /* Normalized absolute path, without .
|                                 * or .. sequences, and without ~user
|                                 * sequences. */
|    Tcl_Obj *cwdPtr;            /* If null, path is absolute, else
|                                 * this points to the cwd object used
|                                 * for this path.  We have a refCount
|                                 * on the object. */ 
|    ClientData nativePathPtr;   /* Native representation of this path,
|                                 * which is filesystem dependent. */
|    int filesystemEpoch;        /* Used to ensure the path representation
|                                 * was generated during the correct
|                                 * filesystem epoch.  The epoch changes
|                                 * when filesystem-mounts are changed. */ 
|    struct Tcl_FilesystemRecord *fsRecPtr;
|                                /* Pointer to the filesystem record 
|                                 * entry to use for this path. */
|} FsPath;

Path to filesystem mapping:

|int TclfsPathInFilesystem_ (Tcl_Obj *pathPtr, ClientData *clientDataPtr)

Is the given path in this filesystem? This function should
return either -1, or it should return TCL_OK.  If it returns
TCL_OK, it may wish to set the clientData parameter to point
to a filesystem specific representation of the path.  (The native 
filesystem actually postpones the calculation of the native
representation until it is requested, but TclKit's vfs immediately
allocates a structure containing an int and Tcl_Obj* which it uses
as an internal representation).

Internal representation manipulation:

|void TclfsFreeInternalRep_ (ClientData clientData)
|ClientData TclfsDupInternalRep_ (ClientData clientData)

These two are called to duplicate and free the clientData field
of the FsPath structure.  If they are NULL, they are ignored (and 
on duplication, the new object's clientData field is set to NULL).

Path normalization:

|int TclfsNormalizePathProc_ (Tcl_Interp *interp, Tcl_Obj *pathPtr, 
|                             int nextCheckpoint)

This function should check the string representation of pathPtr,
starting at character index 'nextCheckpoint', and convert it from that
point onwards (if possible) to a filesystem-specific unique form.  It
should return the character index one beyond where is could no longer
apply (e.g. pointing to a directory separator or end of string).  That
index is then passed on to the next filesystem to continue.  Most
filesystems do not support path ambiguity, in which case the function
need not be implemented at all (a NULL entry in the lookup table is
acceptable).  For example on Windows, the path
"c:/PROGRA~1/tcl/tclkit.exe/lib" would be modified to "C:/Program
Files/Tcl/tclkit.exe/lib" by the core's normalization procedure, which
would return '31', pointing to the '/' in-between .exe and lib.

File manipulation:

For each filesystem function which is implemented, these procs should 
be declared:

|    TclfsAccessProc_ *accessProc;            
|    TclfsStatProc_ *statProc; 
|    TclfsOpenFileChannelProc_ *openFileChannelProc; 
|    TclfsMatchFilesTypesProc_ *matchFilesTypesProc;  
|    TclfsLstatProc_ *lstatProc;            
|    TclfsCopyFileProc_ *copyFileProc; 
|    TclfsRenameFileProc_ *renameFileProc;            
|    TclfsCopyDirectoryProc_ *copyDirectoryProc;            
|    TclfsDeleteFileProc_ *deleteFileProc;            
|    TclfsCreateDirectoryProc_ *createDirectoryProc;            
|    TclfsRemoveDirectoryProc_ *removeDirectoryProc;            
|    TclfsLoadFileProc_ *loadFileProc; 
|    TclfsReadlinkProc_ *readlinkProc; 
|    TclfsListVolumesProc_ *listVolumesProc;            
|    TclfsFileAttrStringsProc_ *fileAttrStringsProc;
|    TclfsFileAttrsGetProc_ *fileAttrsGetProc;
|    TclfsFileAttrsSetProc_ *fileAttrsSetProc;
|    TclfsUtimeProc_ *utimeProc;       

In fact, copy/rename file need not be implemented, because Tcl
will fallback: from rename to copy and delete, and from copy to
open-r/open-w/fcopy/mtime when necessary.  However a filesystem
may well be able to implement these more efficiently than that.

Cd/pwd support:

|    TclfsChdirProc_ *chdirProc;            
|    TclfsGetCwdProc_ *getCwdProc;     

the chdir proc need only return TCL_OK if the path is a valid
directory, and TCL_ERROR otherwise.  There is no need to remember the
path in any way.  Native filesystems will of course want to make the
appropriate system calls to change the real cwd.  Most filesystems will
not implement the 'Cwd' proc, since Tcl keeps track of the cwd for
you.  However, the native filesystem should implement it.

Unload file support:

|    TclfsUnloadFileProc_ *unloadFileProc;            

This function is called automatically by Tcl's core to unload
a file, ''if'' this filesystem was the one which successfully
loaded the file initially.

~ Philosophy

This TIP is influenced by the thoughts behind the TkGS project
(http://sourceforge.net/projects/tkgs/).  Whereas TkGS provides a
general and efficient graphics system, the aim of this TIP is to
provide a similarly general and efficient filesystem.

~ Alternatives

 1. Alternatives to adding vfs support

  > TclKit manages a pretty good job of vfs support.  It is limited by
    the inadequacy of overriding at the Tcl level.  Prowrap is limited
    by the inability to glob, load, cd, pwd, etc.

  > There are currently no better alternatives: if Tcl's C core calls
    C functions directly (as it does), or if extensions call C
    functions directly (as they do), then complete vfs support
    requires a patch like this to Tcl's core.

 2. Alternatives to objectification

  > A previous patch added string-based vfs support to Tcl's core, and 
    required
    very few core changes at all.  It could be adopted instead of an
    objectified filesystem.  This would make Tcl's filesystem more
    complete, but would not make it any more efficient.  Also it is 
    much harder to implement complete 'glob' emulation without the
    newer API.

~ Objections

''Won't all these hooks slow down Tcl's core a lot?''

There are actually remarkably few changes required, so the only
slowdown would occur if additional filesystems are hooked into the
core.  This is similar to the impact of the 'stacked channels'
implementation.  With the objectified filesystem, this does
actually speed up Tcl's core (as remarked above, 'file exists' is 20% 
faster on Windows 2000).

''Won't this break backwards compatibility ("The Tcl question")?''

Not at all.  With the current vfs patch, the entire test
suite passes as before, even with an extra 'reporting' filesystem
activated.  Most reasonable tests now pass even when the test suite is embedded in a wrapped document.

''Won't this make Tcl's core more complex??''

Adding a Tcl_Obj interface is definitely a bit more complex in some areas than the
existing string-based system, but in other areas it cleans things up a lot.  Indeed, one result will be that Tcl's
filesystem is properly abstracted away, which conceptually simplifies 
the core (there will be 10-15 functions which are called for ''all''
filesystem access, whether it is native or virtual).

~ Future thoughts

This section contains items which are outside the scope of this TIP,
but it was thought useful to raise and have documented for the record.

  * Should we remove the native 'Tclpxx' filesystem functions from
    Tcl's API? Or perhaps require a new #define
    TCL_PROVIDE_NATIVE_FILESYSTEM to allow an extension to access
    these calls?  They are all inside tclInt.h, so we could easily
    protect them with such a define.

This patch still places the native filesystem in a preferential
position, and it is hard-coded as the tail of the fs-lookup list.
There are two changes which could be made in the future:

  * Move the native-fs support to a static extension which is loaded
    on startup.  This would ensure the layer now separating Tcl from
    the native FS is not violated, and might let others use Tcl or
    pieces of Tcl in new ways.

  * By incorporating some pieces of the 'vfs' extension into the core
    in the future, and probably making some changes to some of the
    Tclp native-fs functions, we could make Tcl entirely
    filesystem-agnostic (e.g. we could do weird things like mount the
    native filesystem inside a virtual filesystem).  Alternatively,
    if the native filesystem is not loaded at all, that makes for
    a very good way to ensure a wrapped executable is 'safe', because
    it cannot even access the local disk.

Also,

  * Once prowrap is updated to use the new APIs, we should probably
    remove the primitive vfs hooks it currently uses, this will remove
    some obsolete stuff from Tcl's core without affecting anything
    else (I think - any extensions out there use those APIs?).
    Prowrap simply needs to register a Tcl_Filesystem with the stat,
    access and openfilechannel fields set to its existing procedures;
    all other fields can be NULL.  (They would also need to be
    objectified).

  * file copy can now potentially copy across filesystems, which could
    be both very slow (across the internet) and may even want
    different eol conventions on each end.  We could add a
    ''-command'' flag to ''file copy'' (and perhaps ''file rename''),
    and we could perhaps add optional ways of specifying the
    encoding/translation of the transfer?  (The main issue is to
    distinguish between text and binary files, which require automatic
    and binary ''-translation'' respectively).

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|
|




|





|

|
|
|
|

|
|


|


|







|





|



|
|

|









|



|
|
|
|
|

|


|
|


|









|


|



|


|

|

|
|




|
|


|



|



|

|


|
|




|
|



|

|

|
|

|

|
|

|

|

|

|






|
|


|

|

|

|




|
|
|

|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|






|
|
|
|
|
|
|
|
<
|
>


|
|
<
|
>


|
|
<
>
|
|
<
>
|
|
<
>














|


|

|
|




|


|

|
|


|
|

|



|






|
|







|
|
|





|
|
|
|
|

|



|
|


|


|
|
|
|
|



|



|
|
|

|
|

|
|
|
|

|


|
|



|



|
|

|

|


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|



|


|
|
|


|
|



|
|


|
|



|
|



|

|


|
|









|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|








|
|

|
|







|


|


|


|



|



|



|
|
|




|







|

|





|
|

|





|

|


|
|

|





|
|















|
|









|
|

|
|


|

|

|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191

192
193
194
195
196

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286

287
288
289
290
291
292

293
294
295
296
297
298

299
300
301

302
303
304

305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648

# TIP 17: Redo Tcl's filesystem

	Author:         Vince Darley <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        17-Nov-2000
	Post-History:   
	Tcl-Version:    8.4.0
-----

# Abstract

Many of the most exciting recent developments in Tcl have involved
putting virtual file systems in a file \(e.g. Prowrap, Freewrap, Wrap,
TclKit\) but these have been largely _ad hoc_ hacks of various
internal APIs.  This TIP seeks to replace this with a common underlying
API that will, in addition, make porting of Tcl to new platforms a
simpler task as well.

# Overview

There are two current drawbacks to Tcl's filesystem implementation:

  * virtual filesystems are not properly supported.

  * it is all string-based, rather than Tcl\_Obj-based.

Prowrap \(<http://sourceforge.net/projects/tclpro\),> Freewrap
\(<http://home.nycap.rr.com/dlabelle/freewrap/freewrap.html\),> Wrap
\(<http://members1.chello.nl/~j.nijtmans/wrap.html\),> TclKit
\(<http://www.equi4.com/jcw/wiki.cgi/19.html\),> ...  are all attempts to
provide an ability to place Tcl scripts and other data inside a single
file \(or just a small number of files\).  The best and simplest way to
achieve that task \(and many other useful tasks\) is to let Tcl handle
the contents of a single 'wrapped document' as if it were a
filesystem: the contents may be opened, sourced, stat'd, copied,
globbed, etc.  Also note that at the European Tcl/Tk meeting, the \(equal\) second-ranked request for Tcl was support for standalone executables \(<http://mini.net/cgi-bin/wikit/837.html\).>

This TIP suggests that Tcl's core be modified to allow non-native
filesystems to be plugged in to the core, and hence allow _perfect_
virtual filesystems to exist.  The implementations provided by all of
the above tools are very far from perfect.  The most obvious types of
virtual filesystem which should be supported are:

  * wrapped/archived document 'bundles' such as TclKits, .zip files,
    etc.

  * remote filesystems \(e.g. an FTP site\).

but the main point is that all filesystem access should occur through 
a hookable interface, so that Tcl neither knows nor cares what type of
filesystem it is dealing with.

Furthermore this hookable interface should be Tcl\_Obj based, providing
a new 'Path' object type, which should be designed with two goals in
mind:

  * allow caching of 'native path representations' \(all native Tclp...
    filesystem calls involve various Utf->Native conversions\).  For example,
    quick testing for 'file exists' shows that a 20% speed up can be achieved
    by caching the native representation \(Windows 2000sp1\).

  * allow virtual filesystems to operate very efficiently - this will
    probably require caching of the filesystem to use for a particular
    file.

If all of these goals are achieved, Tcl will have a new filesystem
which is both more efficient and more powerful than the existing
implementation.

# Technical discussion

 1. Virtual filesystems

	  > An examination of the core shows that a very limited support was
    added to tclIOUtil.c in June 1998 \(presumably by Scriptics to
    support prowrap\) so that TclStat, TclAccess and
    Tcl\_OpenFileChannel commands could be intercepted.  \(See
    <http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/tcl/generic/tclIOUtil.c?rev=1.2&content-type=text/x-cvsweb-markup&cvsroot=tcl\)>

	  > This TIP seeks to provide a _complete_ implementation of virtual
    file system support, rather than these piecemeal functions.

	  > Fortunately, since Tcl is already abstracted across three
    different filesystem types \(through the Tclp...\) functions, it is
    not that big a task to abstract away to any generic filesystem.

	  > One goal of this TIP is to allow an _extension_ to be written so
    that one can implement a virtual filesystem entirely in Tcl:
    i.e. to provide sufficient hooks into Tcl's core so that an
    extension can capture all filesystem requests and divert them if
    desired.  The goal is not to provide Tcl-level hooks in Tcl's
    core.  Such hooks will only be at the C level, and an extension
    would be required to expose them to the Tcl level.

 2. Objectified filesystem interface.

	  > Every filesystem access in Tcl's core usually involves several
    calls to 'access', 'stat', etc.

	  > For example 'file atime $path' requires two calls to 'stat' and
    one call to 'utime', all with the same $path argument.  Each of
    these requires a conversion from the same Utf path to the same
    native string representation.  No caching is performed, so each of
    these goes through Tcl\_UtfToExternal.  Often Tcl code will use the
    same $path objects for an entire sequence of Tcl 'file'
    operations.  Clearly a representation which cached the native path
    would speed up all of these operations \(except the first\).

	  > The second reason why objectification is desirable is that in a
    pluggable-fs environment we must determine, for each file
    operation, which filesystem to use \(whether native, a mounted .zip
    file, a remote FTP site, etc.\).  If this information can be cached
    for a particular path, again we will not need to recalculate it at
    every step.  A similar technique to that used by Tcl's bytecode
    compilation will be used: each cached object will have a
    "filesystemEpoch" counter, so that we can tell with each access
    whether the filesystem has been modified \(and we must discard the
    cached information\).  Mounting/unmounting filesystems will
    obviously modify the filesystemEpoch.

	 > A relatively complete implementation of this TIP, and a sample "vfs"
    extension
    now exist, and have been tested through TclKit.  On both the "virtual"
    and "objectification" parts of this tip, the implementation is known to be
    stable and complete \(at least on Windows\): TclKit can operate 
    through this new vfs
    implementation without the need to override a single Tcl core
    command at the script level, and all reasonable filesystem tests
    \(cmdAH.test, fCmd.test, fileName.test, io.test\) pass in a scripted document.
    Commands which operate on files
    \(image, source, etc.\)  and extensions like Image, Winico can be
    made to work in a TclKit automatically!  There is still some
    room for optimisation in some parts of the new objectification
    code \(which wasn't
    possible in the old string-based API\).  The current
    implementation has
    great efficiency gains for vfs's
    implemented at the script level, since the same Path objects can
    be passed through the entire process, without an intermediate
    conversion \(and string duplication which would otherwise be
    required\).
    The combination of caching and objectification changes the
    existing list of steps from

		Tcl_Obj -> string -> filesystem -> convert-to-native -> native-call

	  > or \(with vfs hooked in\)

		Tcl_Obj -> string -> vfilesystem -> pick-filesystem
		                          -> convert-to-native -> native-call

	  > and

		Tcl_Obj -> string -> vfilesystem -> pick-filesystem
		                          -> Tcl_NewStringObj -> Tcl-vfs-call

	  > to

		Tcl_Obj -> vfilesystem -> native-call

	  > and

		Tcl_Obj -> vfilesystem -> Tcl-vfs-call

----

A final side-benefit of this proposal would be that it further
modularises the core of Tcl, so that one could, in principle:

  * remove the native filesystem support entirely from Tcl \(perhaps
    useful for embedded devices etc\), since there will be a clean
    layer separating Tcl from its native filesystem functionality.

  * use Tcl's filesystem for other purposes \(outside of Tcl\).

However these final two points are explicitly _not_ the goal of this
TIP!  I simply want to improve Tcl to add vfs support, and the best
way to do that seems \(to me\) to be along the lines of this TIP.

# Proposal

The changes to Tcl's core for virtual filesystem support are actually
very minor.  Every occurrence of a
Tclp-filesystem call must be replaced by a call to a hookable
procedure.  The current filesystem structure \(defined in tclInt.h\) and
hookable procedure list is as follows \(for documentation on this
structure, see Documentation section below\):

	/*
	 * struct Tcl_Filesystem:

	 *
	 * One such structure exists for each type (kind) of filesystem.
	 * It collects together in one place all the functions that are
	 * part of the specific filesystem.  Tcl always accesses the
	 * filesystem through one of these structures.

	 * 
	 * Not all entries need be non-NULL; any which are NULL are simply
	 * ignored.  However, a complete filesystem should provide all of
	 * these functions.
	 */
	
	typedef struct Tcl_Filesystem {
	    CONST char *typeName;   /* The name of the filesystem. */
	    int structureLength;    /* Length of this structure, so future
	                             * binary compatibility can be assured. */
	    Tcl_FilesystemVersion version;  
	                            /* Version of the filesystem type. */
	    TclfsPathInFilesystem_ *pathInFilesystemProc;
	                            /* Function to check whether a path is in this
	                             * filesystem */
	    TclfsDupInternalRep_ *dupInternalRepProc;
	                            /* Function to duplicate internal fs rep */ 
	    TclfsFreeInternalRep_ *freeInternalRepProc;
	                            /* Function to free internal fs rep */ 
	    TclfsInternalToNormalizedProc_ *internalToNormalizedProc_;
	                            /* Function to convert internal representation
	                             * to a normalized path */
	    TclfsConvertToInternalProc_ *convertToInternalProc_;
				    /* Function to convert object to an
				     * internal representation */
	    TclfsStatProc_ *statProc; /* Function to process a 'Tcl_Stat()' call */
	    TclfsAccessProc_ *accessProc;            
	                            /* Function to process a 'Tcl_Access()' call */
	    TclfsOpenFileChannelProc_ *openFileChannelProc; 
	                            /* Function to process a 'Tcl_OpenFileChannel()' call */
	    TclfsMatchInDirectoryProc_ *matchInDirectoryProc;  
	                            /* Function to process a 'Tcl_MatchInDirectory()' */
	    TclfsGetCwdProc_ *getCwdProc;     
	                            /* Function to process a 'Tcl_GetCwd()' call */
	    TclfsChdirProc_ *chdirProc;            
	                            /* Function to process a 'Tcl_Chdir()' call */
	    TclfsLstatProc_ *lstatProc;            
	                            /* Function to process a 'Tcl_Lstat()' call */
	    TclfsCopyFileProc_ *copyFileProc; 
	                            /* Function to process a 'Tcl_CopyFile()' call */
	    TclfsDeleteFileProc_ *deleteFileProc;            
	                            /* Function to process a 'Tcl_DeleteFile()' call */
	    TclfsRenameFileProc_ *renameFileProc;            
	                            /* Function to process a 'Tcl_RenameFile()' call */
	    TclfsCreateDirectoryProc_ *createDirectoryProc;            
	                            /* Function to process a 'Tcl_CreateDirectory()' call */
	    TclfsCopyDirectoryProc_ *copyDirectoryProc;            
	                            /* Function to process a 'Tcl_CopyDirectory()' call */
	    TclfsRemoveDirectoryProc_ *removeDirectoryProc;            
	                            /* Function to process a 'Tcl_RemoveDirectory()' call */
	    TclfsLoadFileProc_ *loadFileProc; 
	                            /* Function to process a 'Tcl_LoadFile()' call */
	    TclfsUnloadFileProc_ *unloadFileProc;            
	                            /* Function to unload a previously successfully
	                             * loaded file */
	    TclfsReadlinkProc_ *readlinkProc; 
	                            /* Function to process a 'Tcl_Readlink()' call */
	    TclfsListVolumesProc_ *listVolumesProc;            
	                            /* Function to list any filesystem volumes added
	                             * by this filesystem */
	    TclfsFileAttrStringsProc_ *fileAttrStringsProc;
	                            /* Function to list all attributes strings which
	                             * are valid for this filesystem */
	    TclfsFileAttrsGetProc_ *fileAttrsGetProc;
	                            /* Function to process a 'Tcl_FileAttrsGet()' call */
	    TclfsFileAttrsSetProc_ *fileAttrsSetProc;
	                            /* Function to process a 'Tcl_FileAttrsSet()' call */
	    TclfsUtimeProc_ *utimeProc;       
	                            /* Function to process a 'Tcl_Utime()' call */
	    TclfsNormalizePathProc_ *normalizePathProc;       
	                            /* Function to normalize a path */
	} Tcl_Filesystem;

Once that is done, almost no more _changes_ need be made to Tcl's
core.  We must simply add code \(to tclIOUtil.c and declarations to
tclInt.h\) to implement the hookable functions and to provide a simple
API by which extensions can hook into the new filesystem support.

This gives us the simplest level of vfs.  Most remaining changes are
objectifying the way Tcl's core uses filesystems.  Many of these
changes actually simplify the core, for example, we replace:

	        case FILE_COPY: {
	            int result;
	            char **argv;
	
	            argv = StringifyObjects(objc, objv);
	            result = TclFileCopyCmd(interp, objc, argv);
	            ckfree((char *) argv);
	            return result;

	        }            

with

	        case FILE_COPY: {
	            return TclFileCopyCmd(interp, objc, objv);

	        }            

and the Unix versions of stat, access, chdir are as simple as:

	int TclpObjStat(Tcl_Obj *pathPtr, struct stat *buf) {
	    return stat(Tclfs_GetNativePath(pathPtr), buf);

	}
	int TclpObjChdir(Tcl_Obj *pathPtr) {
	    return chdir(Tclfs_GetNativePath(pathPtr));

	}
	int TclpObjAccess(Tcl_Obj *pathPtr, int mode) {
	    return access(Tclfs_GetNativePath(pathPtr));

	}

There are a few other small changes required, some which are
absolutely necessary, and some which make the implementation
of a Tcl-level vfs much simpler and more robust:

  * Cross-filesystem copy and rename operations will fail.  A patch was
    added so that Tcl can fall back on 'open r/open w/fcopy/file mtime'
    as a copying method for files, and a new function ::tcl::copyDirectory
    for directories.  These techniques are only used if the source/dest
    are in different filesystems, or if the filesystem Tcl tries to use
    returns the EXDEV posix result in 'errno'.  This is a natural
    extension of Tcl's current way of falling back from 'rename' to 
    'copy and delete'.

  * Add _-tails_ flag to _glob_ \(and internally to _TclGlob_\) to
    indicate that we only want the tails of the files to be returned.

  * Add _file normalize path_ subcommand to _file_, which returns
    an absolute path in which all "..", "." sequences have been
    removed, and the file is a platform-normalized path \(e.g. the
    longname is used on windows\).

  * Modify the TclDoGlob implementation so it handles recursion itself,
    rather than passing it on to the various TclpMatchFilesTypes functions.
    This simplifies the platform-specific code, and makes vfs support of
    _glob_ much more robust, easy, complete, etc.  This has the side-
    benefit that TclpMatchFilesTypes need not operate directly on
    the interpreter's result.  The simpler function with a different
    signature has been named _TclpMatchInDirectory_.

  * Modify the implementation of _encoding names_ to use the
    TCL\_GLOBMODE\_TAILS flag to TclGlob, simplifying that code.

  * Add an API to tclIO.c to allow us to Unregister a channel
    _without_ deleting it.  We need this to be able to take a
    channel created in Tcl \(registered and with refcount of 1\) and
    turn it into a "pristine channel with refcount 0" as returned by
    Tcl\_OpenFileChannel.  This is called _Tcl\_DetachChannel_.

  * Add a function to tclInt.decls called 'TclpVerifyInitialEncodings'
    which is required when all of Tcl is packaged in a virtual 
    filesystem \(e.g. TclKit\), since Tcl's very early call to 
    TclpSetInitialEncodings fails to achieve anything useful.

  * the perfect vfs support can have some weird side-effects.  For
    instance, if I embed all of tcltest and tests/ inside a TclKit,
    and try to source 'all.tcl', I get errors that each file does not
    exist.  This is because the test code tries to pipe each file in
    turn to a newly created tcl process \(open "\| tclsh foo.test r"\),
    but the files don't really exist \(as far as the OS is concerned\). 
    We therefore add an introspection command 'file system
    $path' which returns a list of two items: the name of the 
    filesystem and the type of the file within that filesystem.
    For example it might be 'native local', 'native networked',
    'vfs ftp', 'vfs zip' etc.

  * vfs systems on different platforms may require different directory
    separator characters \(different to the native characters\), 
    especially on MacOS \(in which a valid file might be 
    _HD:Tcl:tcl.zip/lib/tcl8.4/history.tcl_\), and we therefore add
    'file separator ?filename?' command to retrieve the correct
    separator to use.

As mentioned above an implementation of all of this now exists.  The
modified Tcl core passes all Tcl tests, and works with a new version of
TclKit \(which can itself pass all reasonable tests when executing the
test suite inside a scripted document\).  It has
been tested with a variety of wrapped demos \(tclhttpd, bwidgets,
widgets, alphatk\), and performs very well.  The patch is available
from the author of this TIP, and a version \(possibly not the most recent\) can be downloaded from: ftp://ftp.ucsd.edu/pub/alpha/tcl/tclobjvfs.diff 

# Documentation: vfs-aware extensions

All calls to filesystem functions in Tcl's core and in extensions
should preferably be made through the new API defined in tclInt.decls.
All these functions have the prefix 'Tclfs\_'.  Of course extensions
which call older string-based APIs \(e.g. Tcl\_OpenFileChannel\) will
still work, but will not benefit from the efficiency of the cached
object representation.  Most of these functions are not commonly used
by extensions \(e.g. Tclfs\_CopyDirectory\), so only the most common are 
listed here:

	    Tcl_Channel Tclfs_OpenFileChannel(Tcl_Interp *interp, Tcl_Obj *pathPtr,
	                                      char *modeString, int permissions)
	    int         Tclfs_EvalFile(Tcl_Interp *interp, Tcl_Obj *fileName)
	    int         Tclfs_Stat(Tcl_Obj *pathPtr, struct stat *buf)
	    int         Tclfs_Access(Tcl_Obj *pathPtr, int mode)

These replace the equivalent string-based APIs.

	    int      Tclfs_ConvertToPathType(Tcl_Interp *interp, Tcl_Obj *pathPtr)

Attempts to convert the given object to a path type.  This is a little
more than a simple
wrapper around _Tcl\_ConvertToType\(interp, pathPtr, &tclFsPathType\)_.
If it returns TCL\_ERROR, the object is not a valid path.  In this
sense it is very similar to Tcl\_TranslateFileName for the existing
string-based API.  It should be called before attempting to pass
an object to any of the other filesystem APIs \(again in much the same
way as Tcl\_TranslateFileName was used in the core\).

	    int      Tclfs_EqualPaths(Tcl_Obj* firstPtr, Tcl_Obj* secondPtr)
	    Tcl_Obj* Tclfs_SplitPath(Tcl_Obj* pathPtr, int *lenPtr)
	    Tcl_Obj* Tclfs_JoinPath(Tcl_Obj *listObj, int elements)
	    Tcl_Obj* Tclfs_JoinToPath(Tcl_Obj *basePtr, int objc, Tcl_Obj *CONST objv[])

These all manipulate paths.  They return Tcl\_Obj\* with refCounts of
zero.

	    Tcl_Obj* Tclfs_GetNormalizedPath(Tcl_Interp *interp, Tcl_Obj* pathObjPtr)
	    char*    Tclfs_GetTranslatedPath(Tcl_Interp *interp, Tcl_Obj* pathPtr)

and finally:

	    char*    Tclfs_GetNativePath(Tcl_Obj* pathObjPtr)

which is used by native filesystems only, and is a shorthand for
getting at the cached native representation for MacOS, Windows or
Unix \(as appropriate\).  This is always a string based representation,
but may really be of type TCHAR\* on Windows, for example.

# Documentation: writing a new filesystem

The _objPtr->internalRep.otherValuePtr_ field is a pointer
to one of these structures, for objects of "path" type.

	typedef struct FsPath {
	    char *translatedPathPtr;    /* Name without any ~user sequences */
	    Tcl_Obj *normPathPtr;       /* Normalized absolute path, without .
	                                 * or .. sequences, and without ~user
	                                 * sequences. */
	    Tcl_Obj *cwdPtr;            /* If null, path is absolute, else
	                                 * this points to the cwd object used
	                                 * for this path.  We have a refCount
	                                 * on the object. */ 
	    ClientData nativePathPtr;   /* Native representation of this path,
	                                 * which is filesystem dependent. */
	    int filesystemEpoch;        /* Used to ensure the path representation
	                                 * was generated during the correct
	                                 * filesystem epoch.  The epoch changes
	                                 * when filesystem-mounts are changed. */ 
	    struct Tcl_FilesystemRecord *fsRecPtr;
	                                /* Pointer to the filesystem record 
	                                 * entry to use for this path. */
	} FsPath;

Path to filesystem mapping:

	int TclfsPathInFilesystem_ (Tcl_Obj *pathPtr, ClientData *clientDataPtr)

Is the given path in this filesystem? This function should
return either -1, or it should return TCL\_OK.  If it returns
TCL\_OK, it may wish to set the clientData parameter to point
to a filesystem specific representation of the path.  \(The native 
filesystem actually postpones the calculation of the native
representation until it is requested, but TclKit's vfs immediately
allocates a structure containing an int and Tcl\_Obj\* which it uses
as an internal representation\).

Internal representation manipulation:

	void TclfsFreeInternalRep_ (ClientData clientData)
	ClientData TclfsDupInternalRep_ (ClientData clientData)

These two are called to duplicate and free the clientData field
of the FsPath structure.  If they are NULL, they are ignored \(and 
on duplication, the new object's clientData field is set to NULL\).

Path normalization:

	int TclfsNormalizePathProc_ (Tcl_Interp *interp, Tcl_Obj *pathPtr, 
	                             int nextCheckpoint)

This function should check the string representation of pathPtr,
starting at character index 'nextCheckpoint', and convert it from that
point onwards \(if possible\) to a filesystem-specific unique form.  It
should return the character index one beyond where is could no longer
apply \(e.g. pointing to a directory separator or end of string\).  That
index is then passed on to the next filesystem to continue.  Most
filesystems do not support path ambiguity, in which case the function
need not be implemented at all \(a NULL entry in the lookup table is
acceptable\).  For example on Windows, the path
"c:/PROGRA~1/tcl/tclkit.exe/lib" would be modified to "C:/Program
Files/Tcl/tclkit.exe/lib" by the core's normalization procedure, which
would return '31', pointing to the '/' in-between .exe and lib.

File manipulation:

For each filesystem function which is implemented, these procs should 
be declared:

	    TclfsAccessProc_ *accessProc;            
	    TclfsStatProc_ *statProc; 
	    TclfsOpenFileChannelProc_ *openFileChannelProc; 
	    TclfsMatchFilesTypesProc_ *matchFilesTypesProc;  
	    TclfsLstatProc_ *lstatProc;            
	    TclfsCopyFileProc_ *copyFileProc; 
	    TclfsRenameFileProc_ *renameFileProc;            
	    TclfsCopyDirectoryProc_ *copyDirectoryProc;            
	    TclfsDeleteFileProc_ *deleteFileProc;            
	    TclfsCreateDirectoryProc_ *createDirectoryProc;            
	    TclfsRemoveDirectoryProc_ *removeDirectoryProc;            
	    TclfsLoadFileProc_ *loadFileProc; 
	    TclfsReadlinkProc_ *readlinkProc; 
	    TclfsListVolumesProc_ *listVolumesProc;            
	    TclfsFileAttrStringsProc_ *fileAttrStringsProc;
	    TclfsFileAttrsGetProc_ *fileAttrsGetProc;
	    TclfsFileAttrsSetProc_ *fileAttrsSetProc;
	    TclfsUtimeProc_ *utimeProc;       

In fact, copy/rename file need not be implemented, because Tcl
will fallback: from rename to copy and delete, and from copy to
open-r/open-w/fcopy/mtime when necessary.  However a filesystem
may well be able to implement these more efficiently than that.

Cd/pwd support:

	    TclfsChdirProc_ *chdirProc;            
	    TclfsGetCwdProc_ *getCwdProc;     

the chdir proc need only return TCL\_OK if the path is a valid
directory, and TCL\_ERROR otherwise.  There is no need to remember the
path in any way.  Native filesystems will of course want to make the
appropriate system calls to change the real cwd.  Most filesystems will
not implement the 'Cwd' proc, since Tcl keeps track of the cwd for
you.  However, the native filesystem should implement it.

Unload file support:

	    TclfsUnloadFileProc_ *unloadFileProc;            

This function is called automatically by Tcl's core to unload
a file, _if_ this filesystem was the one which successfully
loaded the file initially.

# Philosophy

This TIP is influenced by the thoughts behind the TkGS project
\(<http://sourceforge.net/projects/tkgs/\).>  Whereas TkGS provides a
general and efficient graphics system, the aim of this TIP is to
provide a similarly general and efficient filesystem.

# Alternatives

 1. Alternatives to adding vfs support

	  > TclKit manages a pretty good job of vfs support.  It is limited by
    the inadequacy of overriding at the Tcl level.  Prowrap is limited
    by the inability to glob, load, cd, pwd, etc.

	  > There are currently no better alternatives: if Tcl's C core calls
    C functions directly \(as it does\), or if extensions call C
    functions directly \(as they do\), then complete vfs support
    requires a patch like this to Tcl's core.

 2. Alternatives to objectification

	  > A previous patch added string-based vfs support to Tcl's core, and 
    required
    very few core changes at all.  It could be adopted instead of an
    objectified filesystem.  This would make Tcl's filesystem more
    complete, but would not make it any more efficient.  Also it is 
    much harder to implement complete 'glob' emulation without the
    newer API.

# Objections

_Won't all these hooks slow down Tcl's core a lot?_

There are actually remarkably few changes required, so the only
slowdown would occur if additional filesystems are hooked into the
core.  This is similar to the impact of the 'stacked channels'
implementation.  With the objectified filesystem, this does
actually speed up Tcl's core \(as remarked above, 'file exists' is 20% 
faster on Windows 2000\).

_Won't this break backwards compatibility \("The Tcl question"\)?_

Not at all.  With the current vfs patch, the entire test
suite passes as before, even with an extra 'reporting' filesystem
activated.  Most reasonable tests now pass even when the test suite is embedded in a wrapped document.

_Won't this make Tcl's core more complex??_

Adding a Tcl\_Obj interface is definitely a bit more complex in some areas than the
existing string-based system, but in other areas it cleans things up a lot.  Indeed, one result will be that Tcl's
filesystem is properly abstracted away, which conceptually simplifies 
the core \(there will be 10-15 functions which are called for _all_
filesystem access, whether it is native or virtual\).

# Future thoughts

This section contains items which are outside the scope of this TIP,
but it was thought useful to raise and have documented for the record.

  * Should we remove the native 'Tclpxx' filesystem functions from
    Tcl's API? Or perhaps require a new \#define
    TCL\_PROVIDE\_NATIVE\_FILESYSTEM to allow an extension to access
    these calls?  They are all inside tclInt.h, so we could easily
    protect them with such a define.

This patch still places the native filesystem in a preferential
position, and it is hard-coded as the tail of the fs-lookup list.
There are two changes which could be made in the future:

  * Move the native-fs support to a static extension which is loaded
    on startup.  This would ensure the layer now separating Tcl from
    the native FS is not violated, and might let others use Tcl or
    pieces of Tcl in new ways.

  * By incorporating some pieces of the 'vfs' extension into the core
    in the future, and probably making some changes to some of the
    Tclp native-fs functions, we could make Tcl entirely
    filesystem-agnostic \(e.g. we could do weird things like mount the
    native filesystem inside a virtual filesystem\).  Alternatively,
    if the native filesystem is not loaded at all, that makes for
    a very good way to ensure a wrapped executable is 'safe', because
    it cannot even access the local disk.

Also,

  * Once prowrap is updated to use the new APIs, we should probably
    remove the primitive vfs hooks it currently uses, this will remove
    some obsolete stuff from Tcl's core without affecting anything
    else \(I think - any extensions out there use those APIs?\).
    Prowrap simply needs to register a Tcl\_Filesystem with the stat,
    access and openfilechannel fields set to its existing procedures;
    all other fields can be NULL.  \(They would also need to be
    objectified\).

  * file copy can now potentially copy across filesystems, which could
    be both very slow \(across the internet\) and may even want
    different eol conventions on each end.  We could add a
    _-command_ flag to _file copy_ \(and perhaps _file rename_\),
    and we could perhaps add optional ways of specifying the
    encoding/translation of the transfer?  \(The main issue is to
    distinguish between text and binary files, which require automatic
    and binary _-translation_ respectively\).

# Copyright

This document has been placed in the public domain.

Name change from tip/170.tip to tip/170.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215

216
217
218
219
220
221
222
223
224
225
226
227
228
229
230

231
232
233

234
235
236
237
238
239
240
241
242
243
244
245
246

247
248
249
250


TIP:            170
Title:          Better Support for Nested Lists
Version:        $Revision: 1.6 $
Author:         Sergey Babkin <[email protected]>
Author:         Don Porter <[email protected]>
Author:		Donal K. Fellows <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        30-Jan-2004
Post-History:   
Tcl-Version:    8.7


~ Abstract

Nested lists are easy to create with Tcl but then manipulating them is not
easy. For example, think about how to change a value nested in a list 2 levels
deep? How about 4 levels deep? The proposed new commands make such
manipulation easy, and make the nested lists a great replacement for arrays
and structures in C-like languages.

~Rationale and Specification

The new proposed commands start with the prefix "ldeep". They are desgined to
resemble the classic list commands with "l" names. In the cases when the
meaning of "ldeep" command differs substantially from the "l" command, the
name has been selected to be different (such as "ldeeprep", not
"ldeepreplace").

The commands have been extensively used in the Not A Commander project
[http://nac.sf.net/] and have been adjusted to the observed needs of practical
use. All these commands use the concept of "path" (see [22]) and handle the
concatenation of paths for reasons of convenience (e.g. a "base" path followed
by a "local" path).

~~ Commands

The new proposed commands are:

 > '''ldeepset''' ''listvar path'' ?''path''?... ''value''

Set a ''value'' in a nested list variable. If the variable did not exist
previously, it is created. If the intermediate lists specified in the path did
not exist, they are created as empty lists. This includes the "filler"
elements: for example, if ''listvar'' contained a list of one element and the
path starts with "5 ...", the elements with indexes 1, 2, 3, 4 and 5 will all
be created (and will contain empty strings) and the the further creation
within the element at index 5 will proceed.

A special meaning is assigned by this command to the negative indexes in the
path: they mean "add a new element at the end of the list". So this command
also doubles as a nested version of lappend. For example,

|   ldeepset listvar -1 value

means the same thing as

|   lappend listvar value

This merging has happened because it's often neccessary to add elements to the
lists in the middle of the path. The particular value used to indicate the
addition of an element can be changed to something more symbolic, for example
to "append" instead of a negative value.

The ''ldeepset'' command returns nothing. Since the version without value as
in the common set can not be used, returning the value did not seem to make
sense.  Also when experimenting with large lists from the command line,
returning the value that is a large list itself would cause a long and
unpleasant printout of it.

''(This is only partially superceded by [33] and [331].)''

 > '''ldeepincr''' ''lstvar path'' ?''path''?... ''int-value''

Increase a value within a nested list by ''int-value''. Note that since the
amount of increase has to be differentiated from the ''path'', it's mandatory
even for the value of 1. This is a convenient and often used shortcut for the
'''ldeepindex'''-'''expr'''-'''ldeepset''' sequence.  It returns the value of
the element after increase.

 > '''ldeeprep''' ''lstvar path'' ?''path''?... ''first last element-list''

Replace a range of elements in a sublist identified by the ''path'' with the
elements from the ''element-list''. It returns nothing.

This command is different from '''lreplace''' in two ways, hence the name
change. First, it acts on data in a variable, not on a list as an argument.
Second, the elements for replacement are contained in a list, not as separate
elements on command line. Both differences were created for convenience of
practical use, plus to allow the path to pick up the variable number of
arguments. I have found that I always need to replace elements in a variable,
not as a pass-through operator, and that I almost always need to insert
elements from another list, not just some fixed set of elements.

 > '''ldeeppop''' ''lstvar path'' ?''path''?... ''count''

Remove ''count'' elements from the end of the sublist identified by ''path''
in the variable and return them in a list.

This command was inspired by the pop operator in Perl. Somehow I've never has
a very string need for the other similar commands (which would be
''ldeeppush'' to add elements, and ''ldeepshift'' and ''ldeepunshift'' for
operations on the start of the list) but they can be easily added as well for
completeness.

The command returns the list of the popped elements in the original order. For
example, if ''lstvar'' contained {0 1 2 3 4 5}, "ldeeppop lstvar {} 2" would
return {4 5}, NOT {5 4}.

~Other Extensions for List Support

In my practice I have found that a few other commands make working with lists
much more convenient. They are not directly related to the nested lists but to
the lists in general.

 > '''lconcat''' ''sublist'' ?''sublist''?...

Concatenate the argument lists and return the resulting list. This command is
similar to '''concat''' but avoids converting the values to strings,
concatenating the strings and then re-parsing the strings. When the lists
involved grow to a few megabytes, '''concat''' can become very inefficient
both in the sense of time and memory usage; '''lconcat''' resolved this
inefficiency. Note that it does ''not'' replace '''concat''', which can be
used to assemble lists from pieces in different argument strings. The command
returns the concatenated list.

''(Note that this is largely possible through using'' '''list''' ''and
[157]/[293], and that'' '''concat''' ''is more likely to handle the lists
where this matters efficiently anyway right now due to efficiency tweaks to
its implementation. It remains to be seen whether there is still a need for''
'''lconcat''' ''in other areas...)''

~Reference Implementation

The reference implementation is available as part of the Not A Commander
project [http://nac.sf.net/], the source file ''cutil.c''. To include the new
commands into Tcl, the error messages will have to be adjusted to match the
style used in Tcl, and the man pages will have to be written. The current
implementation has been tested in fair amounts for both correctness and
efficiency by usage in the Not A Commander project, the formal test suite
would have to be written. Further progress in this direction depends on
acceptance of this proposal.

~Comments

Messages on the TCLCORE mailing list have pointed out that nearly everything
proposed here is either equivalent to, or trivially created by composition of
the existing commands '''lindex''', '''lrange''', '''lset''', '''lassign''',
and '''lrepeat'''.  The only novel thing proposed is the ability of '''lset'''
to create new list elements.  If that's still desired, a separate new TIP
proposing that alone would be the best way to deal with that.

I call on the author to withdraw this TIP.

~Copyright

This document has been placed in the public domain.

----

~ Appendix: Removed Commands

''These commands were originally part of this TIP, but have been removed to
this appendix on the grounds that the functionality they describe is now part
of Tcl via other TIPs.''

 > '''ldeepindex''' ''list path'' ?''path''?...

Extract an element from a nested list. The element is identified by the
logical concatenation of the paths. It returns the extracted element.
''(Obsoleted by [22].)''

 > '''ldeeplen''' ''list path'' ?''path''?...

Find the length of a nested sublist. The sublist is identified by the logical
concatenation of the paths. It returns the found length. A non-existing
sublist is assumed to have the length of 0.
''(Obsoleted by [22] and normal llength.)''

 > '''ldeeprange''' ''list path'' ?''path''?... ''first last''

Extract a sublist from a nested list. This command is a convenient equivalent
of

|   lrange [ldeepindex list path ?path?] first last]

"end" is supported as the first or last index. It returns the extracted
sublist.
''(Obsoleted by [22] and normal lrange.)''

 > '''mset''' ''list-of-variable-names list-of-values''

Set the values from the value list to the variable in the variable list at the
same index. The command name stands for "multiple set". This command is
inspired by assignments in Perl.

If there were more variables than the values, the rest of variables are set to
an empty value. If there were more values than variables, then the last
variable is assigned the whole end of a list (as a list).

A special variable name "'''-'''" can be used to throw away a value, or the
whole end of the value list if it's specified as the last one in the variable
list.

The command returns nothing. It can be argued that it would make sense to
return the length of the original list, or the difference between the length
of the values list and the length of the variables list. I don't know which
one is better.

This command is particularly convenient for returning multiple values from a
procedure. For example:

|   proc xxx {a b} {
|      return [list [expr $b+$a] [expr $b*$a]]
|   }

|   mset {sum product} [xxx 1 2]

''(Obsoleted by [57].)''

 > '''ldup''' ''count element'' ?''element''?...

This returns a list produced by duplicating the sequence of elements ''count''
times. This command is inspired by the operator "x" in Perl, and it is a
logical equivalent of:

|   proc ldup {count args} {
|      set res {}
|      for {set i 0} {$i < $count} {incr i} {
|         set res [lconcat $res $args]
|      }

|      return $res
|   }


''(Obsoleted by [136].)''

 > '''lvdup''' ''count element-list''

This returns a list produced by duplicating the ''element-list count'' times.
This command is inspired by the operator "x" in Perl, and it is a logical
equivalent of:

|   proc lvdup {count list} {
|      set res {}
|      for {set i 0} {$i < $count} {incr i} {
|         set res [lconcat $res $list]
|      }

|      return $res
|   }

''(Obsoleted by [136] and [157]/[293].)''


<
|
<
|
|
|
|
|
|
|
|
|
>

|







|




|
|


|
|
|
|

|



|

|


|

|






|



|






|





|

|

|
|

|


|

|
|

|








|

|



|
|
|



|
|

|





|


|

|
|
|



|
|

|
|

|


|







|



|
|





|





|

|

|

|



|

|




|

|




|



|

|







|

|











|
|
<
>
|

|

|

|



|
|
|
|
<
>
|
<
|
>
|

|

|



|
|
|
|
<
>
|
<
|
|
>
>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228

229
230

231
232
233
234
235
236
237
238
239
240
241
242
243
244

245
246

247
248
249
250

# TIP 170: Better Support for Nested Lists

	Author:         Sergey Babkin <[email protected]>
	Author:         Don Porter <[email protected]>
	Author:		Donal K. Fellows <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        30-Jan-2004
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

Nested lists are easy to create with Tcl but then manipulating them is not
easy. For example, think about how to change a value nested in a list 2 levels
deep? How about 4 levels deep? The proposed new commands make such
manipulation easy, and make the nested lists a great replacement for arrays
and structures in C-like languages.

# Rationale and Specification

The new proposed commands start with the prefix "ldeep". They are desgined to
resemble the classic list commands with "l" names. In the cases when the
meaning of "ldeep" command differs substantially from the "l" command, the
name has been selected to be different \(such as "ldeeprep", not
"ldeepreplace"\).

The commands have been extensively used in the Not A Commander project
<http://nac.sf.net/>  and have been adjusted to the observed needs of practical
use. All these commands use the concept of "path" \(see [[22]](22.md)\) and handle the
concatenation of paths for reasons of convenience \(e.g. a "base" path followed
by a "local" path\).

## Commands

The new proposed commands are:

 > **ldeepset** _listvar path_ ?_path_?... _value_

Set a _value_ in a nested list variable. If the variable did not exist
previously, it is created. If the intermediate lists specified in the path did
not exist, they are created as empty lists. This includes the "filler"
elements: for example, if _listvar_ contained a list of one element and the
path starts with "5 ...", the elements with indexes 1, 2, 3, 4 and 5 will all
be created \(and will contain empty strings\) and the the further creation
within the element at index 5 will proceed.

A special meaning is assigned by this command to the negative indexes in the
path: they mean "add a new element at the end of the list". So this command
also doubles as a nested version of lappend. For example,

	   ldeepset listvar -1 value

means the same thing as

	   lappend listvar value

This merging has happened because it's often neccessary to add elements to the
lists in the middle of the path. The particular value used to indicate the
addition of an element can be changed to something more symbolic, for example
to "append" instead of a negative value.

The _ldeepset_ command returns nothing. Since the version without value as
in the common set can not be used, returning the value did not seem to make
sense.  Also when experimenting with large lists from the command line,
returning the value that is a large list itself would cause a long and
unpleasant printout of it.

_\(This is only partially superceded by [[33]](33.md) and [[331]](331.md).\)_

 > **ldeepincr** _lstvar path_ ?_path_?... _int-value_

Increase a value within a nested list by _int-value_. Note that since the
amount of increase has to be differentiated from the _path_, it's mandatory
even for the value of 1. This is a convenient and often used shortcut for the
**ldeepindex**-**expr**-**ldeepset** sequence.  It returns the value of
the element after increase.

 > **ldeeprep** _lstvar path_ ?_path_?... _first last element-list_

Replace a range of elements in a sublist identified by the _path_ with the
elements from the _element-list_. It returns nothing.

This command is different from **lreplace** in two ways, hence the name
change. First, it acts on data in a variable, not on a list as an argument.
Second, the elements for replacement are contained in a list, not as separate
elements on command line. Both differences were created for convenience of
practical use, plus to allow the path to pick up the variable number of
arguments. I have found that I always need to replace elements in a variable,
not as a pass-through operator, and that I almost always need to insert
elements from another list, not just some fixed set of elements.

 > **ldeeppop** _lstvar path_ ?_path_?... _count_

Remove _count_ elements from the end of the sublist identified by _path_
in the variable and return them in a list.

This command was inspired by the pop operator in Perl. Somehow I've never has
a very string need for the other similar commands \(which would be
_ldeeppush_ to add elements, and _ldeepshift_ and _ldeepunshift_ for
operations on the start of the list\) but they can be easily added as well for
completeness.

The command returns the list of the popped elements in the original order. For
example, if _lstvar_ contained \{0 1 2 3 4 5\}, "ldeeppop lstvar \{\} 2" would
return \{4 5\}, NOT \{5 4\}.

# Other Extensions for List Support

In my practice I have found that a few other commands make working with lists
much more convenient. They are not directly related to the nested lists but to
the lists in general.

 > **lconcat** _sublist_ ?_sublist_?...

Concatenate the argument lists and return the resulting list. This command is
similar to **concat** but avoids converting the values to strings,
concatenating the strings and then re-parsing the strings. When the lists
involved grow to a few megabytes, **concat** can become very inefficient
both in the sense of time and memory usage; **lconcat** resolved this
inefficiency. Note that it does _not_ replace **concat**, which can be
used to assemble lists from pieces in different argument strings. The command
returns the concatenated list.

_\(Note that this is largely possible through using_ **list** _and
[[157]](157.md)/[[293]](293.md), and that_ **concat** _is more likely to handle the lists
where this matters efficiently anyway right now due to efficiency tweaks to
its implementation. It remains to be seen whether there is still a need for_
**lconcat** _in other areas...\)_

# Reference Implementation

The reference implementation is available as part of the Not A Commander
project <http://nac.sf.net/> , the source file _cutil.c_. To include the new
commands into Tcl, the error messages will have to be adjusted to match the
style used in Tcl, and the man pages will have to be written. The current
implementation has been tested in fair amounts for both correctness and
efficiency by usage in the Not A Commander project, the formal test suite
would have to be written. Further progress in this direction depends on
acceptance of this proposal.

# Comments

Messages on the TCLCORE mailing list have pointed out that nearly everything
proposed here is either equivalent to, or trivially created by composition of
the existing commands **lindex**, **lrange**, **lset**, **lassign**,
and **lrepeat**.  The only novel thing proposed is the ability of **lset**
to create new list elements.  If that's still desired, a separate new TIP
proposing that alone would be the best way to deal with that.

I call on the author to withdraw this TIP.

# Copyright

This document has been placed in the public domain.

----

# Appendix: Removed Commands

_These commands were originally part of this TIP, but have been removed to
this appendix on the grounds that the functionality they describe is now part
of Tcl via other TIPs._

 > **ldeepindex** _list path_ ?_path_?...

Extract an element from a nested list. The element is identified by the
logical concatenation of the paths. It returns the extracted element.
_\(Obsoleted by [[22]](22.md).\)_

 > **ldeeplen** _list path_ ?_path_?...

Find the length of a nested sublist. The sublist is identified by the logical
concatenation of the paths. It returns the found length. A non-existing
sublist is assumed to have the length of 0.
_\(Obsoleted by [[22]](22.md) and normal llength.\)_

 > **ldeeprange** _list path_ ?_path_?... _first last_

Extract a sublist from a nested list. This command is a convenient equivalent
of

	   lrange [ldeepindex list path ?path?] first last]

"end" is supported as the first or last index. It returns the extracted
sublist.
_\(Obsoleted by [[22]](22.md) and normal lrange.\)_

 > **mset** _list-of-variable-names list-of-values_

Set the values from the value list to the variable in the variable list at the
same index. The command name stands for "multiple set". This command is
inspired by assignments in Perl.

If there were more variables than the values, the rest of variables are set to
an empty value. If there were more values than variables, then the last
variable is assigned the whole end of a list \(as a list\).

A special variable name "**-**" can be used to throw away a value, or the
whole end of the value list if it's specified as the last one in the variable
list.

The command returns nothing. It can be argued that it would make sense to
return the length of the original list, or the difference between the length
of the values list and the length of the variables list. I don't know which
one is better.

This command is particularly convenient for returning multiple values from a
procedure. For example:

	   proc xxx {a b} {
	      return [list [expr $b+$a] [expr $b*$a]]

	   }
	   mset {sum product} [xxx 1 2]

_\(Obsoleted by [[57]](57.md).\)_

 > **ldup** _count element_ ?_element_?...

This returns a list produced by duplicating the sequence of elements _count_
times. This command is inspired by the operator "x" in Perl, and it is a
logical equivalent of:

	   proc ldup {count args} {
	      set res {}
	      for {set i 0} {$i < $count} {incr i} {
	         set res [lconcat $res $args]

	      }
	      return $res

	   }

_\(Obsoleted by [[136]](136.md).\)_

 > **lvdup** _count element-list_

This returns a list produced by duplicating the _element-list count_ times.
This command is inspired by the operator "x" in Perl, and it is a logical
equivalent of:

	   proc lvdup {count list} {
	      set res {}
	      for {set i 0} {$i < $count} {incr i} {
	         set res [lconcat $res $list]

	      }
	      return $res

	   }

_\(Obsoleted by [[136]](136.md) and [[157]](157.md)/[[293]](293.md).\)_

Name change from tip/171.tip to tip/171.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

TIP:            171
Title:          Change Default <MouseWheel> Bindings Behavior
Version:        $Revision: 1.11 $
Author:         Jeff Hobbs <[email protected]>
Author:         Keith Vetter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        05-Mar-2004
Post-History:   
Tcl-Version:    8.6


~ Abstract

This TIP proposes changing the default <MouseWheel> bindings in Tk to have
"better" behaved defaults for a larger set of applications.

~Rationale 

The existing <MouseWheel> bindings only operate on a small handful of widgets,
and only when they have focus. This essentially means that only the text
widget ever has useful <MouseWheel> behavior. This is not how the majority of
applications wish to use the MouseWheel. They operate primarily on a
mouse-focus model (scroll what the mouse is over, not what has '''focus''').
In addition, <Shift-MouseWheel> horizontal scrolling support is added.

~ Specification 

The bindings changes are very simply these:

|proc ::tk::MouseWheel {wFired X Y D {shifted 0}} {
|    # Set event to check based on call
|    set evt "<[expr {$shifted?{Shift-}:{}}]MouseWheel>"
|    # do not double-fire in case the class already has a binding
|    if {[bind [winfo class $wFired] $evt] ne ""} { return }
|    # obtain the window the mouse is over
|    set w [winfo containing $X $Y]
|    # if we are outside the app, try and scroll the focus widget
|    if {![winfo exists $w]} { catch {set w [focus]} }
|    if {[winfo exists $w]} {
|	if {[bind $w $evt] ne ""} {
|	    # Awkward ... this widget has a MouseWheel binding, but to
|	    # trigger successfully in it, we must give it focus.
|	    catch {focus} old
|	    if {$w ne $old} { focus $w }
|	    event generate $w $evt -rootx $X -rooty $Y -delta $D
|	    if {$w ne $old} { focus $old }
|	    return
|	}

|	# aqua and x11/win32 have different delta handling
|	if {[tk windowingsystem] ne "aqua"} {
|	    set delta [expr {- ($D / 30)}]
|	} else {
|	    set delta [expr {- ($D)}]
|	}

|	# scrollbars have different call conventions
|	if {[string match "*Scrollbar" [winfo class $w]]} {
|	    catch {tk::ScrollByUnits $w \
|		       [string index [$w cget -orient] 0] $delta}
|	} else {
|	    set cmd [list $w [expr {$shifted ? "xview" : "yview"}] \
|			 scroll $delta units]
|	    # Walking up to find the proper widget handles cases like
|	    # embedded widgets in a canvas
|	    while {[catch $cmd] && [winfo toplevel $w] ne $w} {
|		set w [winfo parent $w]
|	    }
|	}
|    }
|}




|bind all <MouseWheel> [list ::tk::MouseWheel %W %X %Y %D 0]
|bind all <Shift-MouseWheel> [list ::tk::MouseWheel %W %X %Y %D 1]
|if {[tk windowingsystem] eq "x11"} {
|    # Support for mousewheels on Linux/Unix commonly comes through
|    # mapping the wheel to the extended buttons.
|    bind all <4> [list ::tk::MouseWheel %W %X %Y 120]
|    bind all <5> [list ::tk::MouseWheel %W %X %Y -120]
|}


Instead of requiring a widget to have '''focus''' to receive MouseWheel
events, the new proposal operates with MouseWheel as a global binding. When
fired, it first does a safety check to prevent double-firing if an existing
MouseWheel binding is on the widget.  It then finds the widget which the mouse
if over and uses that as the target for the scrolling event.  If that widget
doesn't exist (usually meaning that it returned {} indicating we are outside
the Tk app), then use the widget which has the actual '''focus'''.

In scrolling, the scrollbar must be treated separately, since it has its own
calling conventions. All others widgets get called with the standard yview
scroll command, caught in case of errors, which are ignored.

This has been discussed on the tcl-mac mailing list already as the desired
behavior, and confirmed to be more intuitive on Windows as well. The above
code is already in use by applications that use widget extensions and
megawidgets such as BWidgets without any adverse effects seen. Note that the
existing MouseWheel bindings must first be removed, using the following code:

|set mw_classes [list Text Listbox Table TreeCtrl]
|foreach class $mw_classes { bind $class <MouseWheel> {} }
|if {[tk windowingsystem] eq "x11"} {
|    foreach class $mw_classes {
|	 bind $class <4> {}
|	 bind $class <5> {}
|    }
|}



~ Reference Implementation 

See above.

~ Discussion

Shift-MouseWheel was added after initial discussion.

Use of "*Scrollbar" is to catch TScrollbar as well.

This is adapted from tklib/style/as.tcl mousewheel adjustments and has proved
useful and workable across a variety of applications.

There is a bit of awkwardness in handling widgets that have their own
MouseWheel bindings in that core Tk requires these have focus to receive the
event. It may be better to fix this forced limitation in Tk rather than the
special-case code above (although that code does work).

~ Copyright 

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|





|


|



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
<
<
<
<
>
>
>
>
|
|
|
|
|
|
|
<
|
>
|




|
|











|
|
|
|
|
|
<
<
|
>
>
|



|



|







|

|


>

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

# TIP 171: Change Default <MouseWheel> Bindings Behavior

	Author:         Jeff Hobbs <[email protected]>
	Author:         Keith Vetter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        05-Mar-2004
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes changing the default <MouseWheel> bindings in Tk to have
"better" behaved defaults for a larger set of applications.

# Rationale 

The existing <MouseWheel> bindings only operate on a small handful of widgets,
and only when they have focus. This essentially means that only the text
widget ever has useful <MouseWheel> behavior. This is not how the majority of
applications wish to use the MouseWheel. They operate primarily on a
mouse-focus model \(scroll what the mouse is over, not what has **focus**\).
In addition, <Shift-MouseWheel> horizontal scrolling support is added.

# Specification 

The bindings changes are very simply these:

	proc ::tk::MouseWheel {wFired X Y D {shifted 0}} {
	    # Set event to check based on call
	    set evt "<[expr {$shifted?{Shift-}:{}}]MouseWheel>"
	    # do not double-fire in case the class already has a binding
	    if {[bind [winfo class $wFired] $evt] ne ""} { return }
	    # obtain the window the mouse is over
	    set w [winfo containing $X $Y]
	    # if we are outside the app, try and scroll the focus widget
	    if {![winfo exists $w]} { catch {set w [focus]} }
	    if {[winfo exists $w]} {
		if {[bind $w $evt] ne ""} {
		    # Awkward ... this widget has a MouseWheel binding, but to
		    # trigger successfully in it, we must give it focus.
		    catch {focus} old
		    if {$w ne $old} { focus $w }
		    event generate $w $evt -rootx $X -rooty $Y -delta $D
		    if {$w ne $old} { focus $old }
		    return

		}
		# aqua and x11/win32 have different delta handling
		if {[tk windowingsystem] ne "aqua"} {
		    set delta [expr {- ($D / 30)}]
		} else {
		    set delta [expr {- ($D)}]

		}
		# scrollbars have different call conventions
		if {[string match "*Scrollbar" [winfo class $w]]} {
		    catch {tk::ScrollByUnits $w \
			       [string index [$w cget -orient] 0] $delta}
		} else {
		    set cmd [list $w [expr {$shifted ? "xview" : "yview"}] \
				 scroll $delta units]
		    # Walking up to find the proper widget handles cases like
		    # embedded widgets in a canvas
		    while {[catch $cmd] && [winfo toplevel $w] ne $w} {
			set w [winfo parent $w]




		    }
		}
	    }
	}
	bind all <MouseWheel> [list ::tk::MouseWheel %W %X %Y %D 0]
	bind all <Shift-MouseWheel> [list ::tk::MouseWheel %W %X %Y %D 1]
	if {[tk windowingsystem] eq "x11"} {
	    # Support for mousewheels on Linux/Unix commonly comes through
	    # mapping the wheel to the extended buttons.
	    bind all <4> [list ::tk::MouseWheel %W %X %Y 120]
	    bind all <5> [list ::tk::MouseWheel %W %X %Y -120]

	}

Instead of requiring a widget to have **focus** to receive MouseWheel
events, the new proposal operates with MouseWheel as a global binding. When
fired, it first does a safety check to prevent double-firing if an existing
MouseWheel binding is on the widget.  It then finds the widget which the mouse
if over and uses that as the target for the scrolling event.  If that widget
doesn't exist \(usually meaning that it returned \{\} indicating we are outside
the Tk app\), then use the widget which has the actual **focus**.

In scrolling, the scrollbar must be treated separately, since it has its own
calling conventions. All others widgets get called with the standard yview
scroll command, caught in case of errors, which are ignored.

This has been discussed on the tcl-mac mailing list already as the desired
behavior, and confirmed to be more intuitive on Windows as well. The above
code is already in use by applications that use widget extensions and
megawidgets such as BWidgets without any adverse effects seen. Note that the
existing MouseWheel bindings must first be removed, using the following code:

	set mw_classes [list Text Listbox Table TreeCtrl]
	foreach class $mw_classes { bind $class <MouseWheel> {} }
	if {[tk windowingsystem] eq "x11"} {
	    foreach class $mw_classes {
		 bind $class <4> {}
		 bind $class <5> {}


	    }
	}

# Reference Implementation 

See above.

# Discussion

Shift-MouseWheel was added after initial discussion.

Use of "\*Scrollbar" is to catch TScrollbar as well.

This is adapted from tklib/style/as.tcl mousewheel adjustments and has proved
useful and workable across a variety of applications.

There is a bit of awkwardness in handling widgets that have their own
MouseWheel bindings in that core Tk requires these have focus to receive the
event. It may be better to fix this forced limitation in Tk rather than the
special-case code above \(although that code does work\).

# Copyright 

This document has been placed in the public domain.

Name change from tip/172.tip to tip/172.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

TIP:            172
Title:          Improve UNIX Tk Look and Feel
Version:        $Revision: 1.4 $
Author:         David N. Welton <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           No voting
Created:        08-Mar-2004
Post-History:   
Tcl-Version:    8.5
Obsoleted-By:	248


~ Abstract

In the spirit of "worse is better", this TIP proposes a simple way to
notably improve Tk's look and feel for the 8.5 release of Tk.  It does
not fix all the problems, and won't make Tk look like whatever toolkit
is "native" on the user's machine (Gtk or Qt), but will at least
improve the current situation.

~ Rationale

This TIP is needed because people continue to complain about Tk's
outdated look.  This TIP, being extremely easy to implement, should be
put into place while we await a technically superior solution such as
the Tile project.

~ Proposed Change

The two things that ought to happen are as follows:

 1. The code now located in the tklib "style" module should be tweaked to       further
    improve its look (for instance Pat Thoyts suggests a few
    additional improvements at the bottom of the page), and included
    as the default look for Tk on Unix in the 8.5 release.  Credit
    goes to Jeremy Collins and the Tk revitalization project for most
    of the code, I believe.

 2. A loadable package should be distributed with Tk that reverts the
    look and feel to "classic Tk", so that "package require classictk"
    would be the only change necessary to not use the new look.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|


|






|




|
|








|


>

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

# TIP 172: Improve UNIX Tk Look and Feel

	Author:         David N. Welton <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           No voting
	Created:        08-Mar-2004
	Post-History:   
	Tcl-Version:    8.5
	Obsoleted-By:	248
-----

# Abstract

In the spirit of "worse is better", this TIP proposes a simple way to
notably improve Tk's look and feel for the 8.5 release of Tk.  It does
not fix all the problems, and won't make Tk look like whatever toolkit
is "native" on the user's machine \(Gtk or Qt\), but will at least
improve the current situation.

# Rationale

This TIP is needed because people continue to complain about Tk's
outdated look.  This TIP, being extremely easy to implement, should be
put into place while we await a technically superior solution such as
the Tile project.

# Proposed Change

The two things that ought to happen are as follows:

 1. The code now located in the tklib "style" module should be tweaked to       further
    improve its look \(for instance Pat Thoyts suggests a few
    additional improvements at the bottom of the page\), and included
    as the default look for Tk on Unix in the 8.5 release.  Credit
    goes to Jeremy Collins and the Tk revitalization project for most
    of the code, I believe.

 2. A loadable package should be distributed with Tk that reverts the
    look and feel to "classic Tk", so that "package require classictk"
    would be the only change necessary to not use the new look.

# Copyright

This document has been placed in the public domain.

Name change from tip/173.tip to tip/173.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
TIP:            173
Title:          Internationalisation and Refactoring of the 'clock' Command
Version:        $Revision: 1.22 $
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        11-Mar-2004
Post-History:   
Discussions-To: news:comp.lang.tcl
Tcl-Version:    8.5


~ Abstract

The [[clock]] command provides Tcl's fundamental facilities for
computing with dates and times.  It has served Tcl faithfully since
7.6, but the computing world has advanced significantly in the decade
that it has been in service.  This TIP proposes a (nearly entirely
compatible) reimplementation of [[clock]] that will allow for fewer
ambiguities on input, improved localisation, more portability, and
less exposure of platform-dependent bugs.  A significantly greater
fraction of [[clock]] shall be implemented in Tcl than it is today,
and the code shall be refactored to use the ensemble mechanism
introducted for Tcl 8.5 (see [112]).

~ Rationale

There is an embarrassing number of open bugs and feature requests
against the [[clock]] command.  As the maintainer of [[clock]], the
author of this TIP has also received a number of informal feature
requests that are not logged at SourceForge.  Unfortunately, many of
the requested fixes and enhancements cannot be effectively addressed
with the current architecture of [[clock]].

 1. Several users have requested additional input formats to [[clock
    scan]], notably the full range of ISO8601 time formats (including
    formats based on week number and day-of-week); year and
    day-of-year; Apache "web log" dates and times; numeric dates
    placing the month before the day; and localised names of months
    and days of the week.  Unfortunately, these formats simply cannot
    be added in the current architecture of [[clock scan]]; in fact,
    there are several outstanding bugs in [[clock scan]] (for example,
    the parsing of numeric time zones east of Greenwich) that cannot
    be fixed without breaking something else.

 > The fundamental issue is that [[clock scan]] is asked to process
   input with too many ambiguities.  An input token such as ''2000'',
   for example, may be interpreted as a year, a time of day, or a
   number ("now + 2000 seconds").  ''1000'' may (perhaps) not be a
   year, but could be a time of day, a number, or a time zone.
   Localisation would only make this problem worse.  Without
   additional guidance, there is, even in theory, no way to determine
   whether ''03-11-2004'' represents the third of November or the
   eleventh of March.

 > To solve this problem, a radical redesign of [[clock scan]] is
   required; the programmer ''must'' be allowed to specify an expected
   input format (or set of expected formats).

 > A side effect of such a redesign would be improved ease of
   maintenance.  The current [[clock scan]] is a YACC-derived parser;
   the build process, however, runs a script on the output of YACC to
   modify its memory management and alter its external symbol names to
   make it compatible with Tcl's conventions.  This script is fragile;
   at present, it is known to work only with the version of YACC
   distributed with Solaris.

 > There are a number of other issues with [[clock scan]] that could
   be addressed at the same time with such a redesign.  For instance,
   there is a known problem at present that an input string that
   specifies time and time zone but not date can return a time that is
   one day too early or late; this problem arises because the existing
   parser presumes the current ''local'' date when parsing such a
   string, rather than the current date in the given time zone.  The
   problem is difficult to address because of the left-to-right nature
   of the LALR(1) parser.

 2. A few enhancements have been requested to [[clock format]]; most
    notably, proper localization on all platforms.  In addition, the
    documentation of [[clock format]] is at best approximate, because
    it depends on the ''strftime'' function in the Standard C Library.
    This function differs among platforms, because the C standard, the
    Posix standard, and the Single Unix Specification have gone
    through evolution over time, and few platforms support all the
    features of the current generation of any of them.

 > In addition, the Year 2038 bug looms large on the horizon.  On most
   32-bit platforms, ''time_t'' (used in the C library funtions) is a
   32-bit count of seconds from 1 January 1970; dates beyond 2038
   cannot be represented in this format.

 > The dependence on a complex library function such as ''strftime''
   introduces obscure platform-dependent bugs.  Several open bugs in
   [[clock format]], for instance, fail only on HP-UX, or only on
   Windows.

 > Date formats have been requested (specifically, the Japanese civil
   calendar) that are beyond the capabilities of the Standard C
   Library functions.

 > [[clock format]] does not honor user preferences for date/time
   format on Windows.

 > All of these concerns seem to indicate that our current dependency
   upon vendor-supplied date and time manipulation routines is ill
   advised.  A single implementation that we control will make the
   behavior consistent among platforms, allow the localisation to
   follow Tcl's conventions, and let us lead rather than follow the
   vendor in fixing bugs.

 3. Server applications frequently require support of multiple locales
    and multiple time zones within a single process, because they need
    to parse input and format output according to the client's
    environment. The current [[clock]] facilities either do not
    support localization at all, or else support a change to locale
    only by changing environment variables.  This technique, once
    again, exposes bugs in the vendor libraries.  It also introduces
    difficulties with thread safety; Tcl does not have a single
    mechanism whereby the ''TZ'' and ''LC_TIME'' environment variables
    are protected.

 4. The only mechanism for performing calculations like "one month
    after the current date" is [[clock scan]].  While this works well
    in practice, using a parser to perform arithmetic seems somewhat
    perverse.

~ Specification

The [[clock]] command shall be reimplemented as an ensemble [112],
with most of the subcommands implemented in Tcl.  A minimal set of the
existing C code shall be refactored and placed inside a
''::tcl::clock'' namespace.  The existing subcommands ''seconds'' and
''clicks'' shall be exposed.  The existing ''scan'' shall be hidden
inside the namespace.  [[clock scan]] and [[clock format]] shall be
reimplemented in Tcl.  In addition, a new [[clock add]] command shall be added.

The syntax and semantics of the [[clock clicks]] and [[clock seconds]]
commands will remain unchanged.

~~~clock scan

The [[clock scan]] command shall have the syntax:

 > '''clock scan''' ''string''
                    ?'''-base''' ''baseTime''?
                    ?'''-format''' ''format''?
                    ?'''-gmt''' ''boolean''?
                    ?'''-locale''' ''name''?
                    ?'''-timezone''' ''timeZone''?

It accepts a character string representing a date and time and returns
the time that the string represents, expressed as a count of seconds
from the Posix epoch (1 January 1970, 0000 UTC).

If a '''-format''' option is not supplied, the scan is a ''free format''
scan.  The existing YACC parser for ''clock scan'' will be used to
interpret the input string.  ''This form of the command is explicitly
deprecated'' because of the inherent ambiguities in interpreting the
input string.  The free-format version of [[clock scan]] does not
accept '''-locale''' or '''-timezone''' options, since the legacy code
does not support multiple locales or time zones.

If the '''-format''' options is supplied, it is interpreted as a
specification for the expected input form.  If the given string
matches the input form, it is converted to a count of seconds and
returned; otherwise, an error is thrown. See ''FORMATS'' below for a
discussion of the available format groups and their interpretation.

Extraction of the date from the input string is guided by what fields
are present in the format.  The order of preference, from highest to
lowest, is:

 {seconds from epoch}, {starDate}: Date fields that specify both date
   and time take highest precedence.  If format groups for these
   fields appear multiple times, the rightmost takes precedence.

 {Julian Day Number}: The Julian Day Number uniquely specifies a
   calendar date.

 {century, year, month, day of month}, {century, year, day of year}, {century, year, week of year, day of week}, {locale era, locale year, month, day of month}:
   Formats with complete year are
   preferred to formats with a two-digit year.  For a two digit year,
   the date range is constrained to lie between 1938 and 2037.

 {year, month, day of month}, {year, day of year}, {year, week of year, day of week}, {year of locale era, month, day of month}:
   Formats that specify the year are preferred to those that do not.

 {month, day of month}, {day of year}, {week of year, day of week}:
   Formats that specify a day within the year are preferred to those
   that specify merely the day of week or day of month.  Formats that
   do not specify the year are presumed to designate the base year.

 {day of month}, {day of week}: If none of the above rules apply, a
   day of the month or day of the week standing alone is interpreted
   as belonging to the base month or week.

 None of the above: If no combination of fields that specifies a date
   is found, the base date is used.

The time of day returned by [[clock scan]] is determined by the
presence of fields in the format string, in the following order of
preference.

 {seconds from epoch, StarDate}: If either of these fields is present,
   it uniquely determines date and time.

 {am/pm indicator, hour am/pm, minute, second}, {hour, minute, second}:
   Time with seconds is preferred to time without seconds.

 {am/pm indicator, hour am/pm, minute}, {hour, minute}: Time can be
   interpreted without the seconds.

 {am/pm indicator, hour am/pm}, {hour}: Time can be expressed as an
   hour alone, ''e.g.'',

| clock scan "6 pm" -format "%I %p"

 None of the above: If none of the above indicators is present,
   ''00:00:00'' (the start of the day) in the given time zone is used.

In all of the foregoing discussion, the 'base date', 'base month',
'base week', and 'base year' refer to the day, month, week or year
designated by the '''-base''' parameter, which is a count of seconds
from the Posix epoch.  If no '''-base''' parameter is supplied, the
current date is used as the base date.  The year, month, week and day
are obtained by interpreting the base date in the time zone specified
by the date/time string.  If the given format does not include a time
zone, then the base time is interpreted in the default time zone; see
''TIME ZONES'' below for the way that the default time zone is
determined, and the interpretation of the '''-timezone''' and '''-gmt'''
options.

The locale is used to determine the spelling of native language words
such as the names of months, names of weekdays, am/pm indicators, and
locale eras.  It is also used in the interpretation of the format
groups, '%X', '%x', and '%c'.  In addition, the locale determines the
date at which the calendar in use changes from the Julian calendar to
the Gregorian.  If no '''-locale''' parameter is supplied, the default
is to use the root locale.  See ''LOCALISATION'' below for more
information.

~~~clock format

The [[clock format]] command shall have the syntax:

 > '''clock format''' ''string''
                      ?'''-format''' ''format''?
                      ?'''-gmt''' ''boolean''?
                      ?'''-locale''' ''name''?
                      ?'''-timezone''' ''timeZone''?

It accepts a time, expressed in seconds from the Posix epoch of 1
January 1970, 00:00 UTC, and formats it according to the given format
string.  See ''FORMATS'' below for a discussion of the available
format codes.  If no format string is supplied, a default format, {%a
%b %d %H:%M:%S %Z %Y} is used.

The '''-timezone''', '''-gmt''', and '''-locale''' options are interpreted
as for [[clock scan]].  See ''TIME ZONES'' and ''LOCALISATION'' below
for how these options work.

~~~clock add

This command performs arithmetic on dates and times.  The syntax
is:

 > '''clock add''' ''time'' ?''count unit''?...
   ?'''-gmt''' ''boolean''? ?'''-timezone''' ''timeZone''?
   ?'''-locale''' ''name''?

It accepts a time, expressed in seconds from the Posix epoch of 1
January 1970, 00:00 UTC, and adds or subtracts units of time from it
according to the alternating ''count'' and ''unit'' parameters.  Each
''count'' must be a wide integer; each ''unit'' is one of the
following:

| years   year    months  month
|                 weeks   week    days    day
| hours   hour    minutes minute  seconds second

The command works by converting the given time to a calendar day and
time of day in the given locale and time zone.  To that day and time
of day, it adds or subtracts the given offsets ''in sequence''.  It
reconverts the resulting time to a count of seconds, again using the
given locale and time zone, and returns that count of seconds.

There are subtle differences in many cases between adding seemingly
similar offsets.  For instance, on the day before Daylight Saving Time
goes into effect, adding 24 hours will give "the time 24 hours from
the base time, irrespective of any clock change", while adding 1 day
will give "the time it will be at the same time of day on the
following day."  Similarly, adding 1 month on 30 January will give
either 28 or 29 February.  There are equally strange effects when
performing date/time arithmetic across the change between the Julian
and Gregorian calendars.

The '''-timezone''', '''-gmt''', and '''-locale''' options are used to
control the interpretation of the count of seconds as a calendar day
and time.  Refer to ''TIME ZONES'' and ''LOCALIZATION'' below for a
fuller discussion.

~~Formats

The [[clock scan]] and [[clock format]] commands will be implemented
in Tcl, without depending on the local ''strftime'' and ''strptime''
functions.  For this reason, format groups will function identically
on all platforms.  The format groups will be interpreted as follows.

 %a: On output, receives the abbreviation for the day of the week in
     the given locale.  On input, matches the name of the day of the
     week (in the given locale) in either abbreviated or full form,
     and may be used to determine the calendar date.

 %A: On output, receives the full name of the day of the week in the
     given locale.  On input, treated identically with %a.

 %b: On output, receives the abbreviation for the name of the month in
     the given locale.  On input, matches the name of the month (in
     the given locale) in either abbreviated or full form, and may be
     used to determine the calendar date.

 %B: On output, receives the full name of the month in the given
     locale.  On input, treated identically with %b.

 %C: On output, receives the number of the century, in Indo-Arabic
     numerals.  On input, matches one or two digits, and accepts the
     number of the century in Indo-Arabic numerals.  May be used to
     determine the calendar date.

 %c: On output, produces a correct locale-dependent representation of
     date and time of day.  On input, matches whatever format ''%c''
     produces in the given locale, and may be used to determine
     calendar date and time.

 %d: On output, produces the number of the day of the month, in
     Indo-Arabic numerals, with a leading zero.  On input, matches one
     or two digits, accepts the day of the month, and may be used to
     determine calendar date.
<
|
<
|
|
|
|
|
|
|
|
>

|

|


|
|


|

|

|


|



|

|
|
|



|
|
|


|
|

|



|


|
|
|

|
|






|




|


|

|

|
|





|
|



|

|


|
|


|


|









|




|



|



|

|


|
|
|
|

|


|

|

|
|
|
|
|
|



|

|
|
|
|
|
|


|


|






|



|


|




|


|




|






|



|


|


|


|
|

|


|



|
|




|
|







|
|


|

|

|
|
|
|
|



|
|
|

|
|


|




|
|
|



|
|


|
|
|



|













|

|


|

|
|





|






|
|











|








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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337

# TIP 173: Internationalisation and Refactoring of the 'clock' Command

	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        11-Mar-2004
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Tcl-Version:    8.5
-----

# Abstract

The [clock] command provides Tcl's fundamental facilities for
computing with dates and times.  It has served Tcl faithfully since
7.6, but the computing world has advanced significantly in the decade
that it has been in service.  This TIP proposes a \(nearly entirely
compatible\) reimplementation of [clock] that will allow for fewer
ambiguities on input, improved localisation, more portability, and
less exposure of platform-dependent bugs.  A significantly greater
fraction of [clock] shall be implemented in Tcl than it is today,
and the code shall be refactored to use the ensemble mechanism
introducted for Tcl 8.5 \(see [[112]](112.md)\).

# Rationale

There is an embarrassing number of open bugs and feature requests
against the [clock] command.  As the maintainer of [clock], the
author of this TIP has also received a number of informal feature
requests that are not logged at SourceForge.  Unfortunately, many of
the requested fixes and enhancements cannot be effectively addressed
with the current architecture of [clock].

 1. Several users have requested additional input formats to [clock
    scan], notably the full range of ISO8601 time formats \(including
    formats based on week number and day-of-week\); year and
    day-of-year; Apache "web log" dates and times; numeric dates
    placing the month before the day; and localised names of months
    and days of the week.  Unfortunately, these formats simply cannot
    be added in the current architecture of [clock scan]; in fact,
    there are several outstanding bugs in [clock scan] \(for example,
    the parsing of numeric time zones east of Greenwich\) that cannot
    be fixed without breaking something else.

	 > The fundamental issue is that [clock scan] is asked to process
   input with too many ambiguities.  An input token such as _2000_,
   for example, may be interpreted as a year, a time of day, or a
   number \("now \+ 2000 seconds"\).  _1000_ may \(perhaps\) not be a
   year, but could be a time of day, a number, or a time zone.
   Localisation would only make this problem worse.  Without
   additional guidance, there is, even in theory, no way to determine
   whether _03-11-2004_ represents the third of November or the
   eleventh of March.

	 > To solve this problem, a radical redesign of [clock scan] is
   required; the programmer _must_ be allowed to specify an expected
   input format \(or set of expected formats\).

	 > A side effect of such a redesign would be improved ease of
   maintenance.  The current [clock scan] is a YACC-derived parser;
   the build process, however, runs a script on the output of YACC to
   modify its memory management and alter its external symbol names to
   make it compatible with Tcl's conventions.  This script is fragile;
   at present, it is known to work only with the version of YACC
   distributed with Solaris.

	 > There are a number of other issues with [clock scan] that could
   be addressed at the same time with such a redesign.  For instance,
   there is a known problem at present that an input string that
   specifies time and time zone but not date can return a time that is
   one day too early or late; this problem arises because the existing
   parser presumes the current _local_ date when parsing such a
   string, rather than the current date in the given time zone.  The
   problem is difficult to address because of the left-to-right nature
   of the LALR\(1\) parser.

 2. A few enhancements have been requested to [clock format]; most
    notably, proper localization on all platforms.  In addition, the
    documentation of [clock format] is at best approximate, because
    it depends on the _strftime_ function in the Standard C Library.
    This function differs among platforms, because the C standard, the
    Posix standard, and the Single Unix Specification have gone
    through evolution over time, and few platforms support all the
    features of the current generation of any of them.

	 > In addition, the Year 2038 bug looms large on the horizon.  On most
   32-bit platforms, _time\_t_ \(used in the C library funtions\) is a
   32-bit count of seconds from 1 January 1970; dates beyond 2038
   cannot be represented in this format.

	 > The dependence on a complex library function such as _strftime_
   introduces obscure platform-dependent bugs.  Several open bugs in
   [clock format], for instance, fail only on HP-UX, or only on
   Windows.

	 > Date formats have been requested \(specifically, the Japanese civil
   calendar\) that are beyond the capabilities of the Standard C
   Library functions.

	 > [clock format] does not honor user preferences for date/time
   format on Windows.

	 > All of these concerns seem to indicate that our current dependency
   upon vendor-supplied date and time manipulation routines is ill
   advised.  A single implementation that we control will make the
   behavior consistent among platforms, allow the localisation to
   follow Tcl's conventions, and let us lead rather than follow the
   vendor in fixing bugs.

 3. Server applications frequently require support of multiple locales
    and multiple time zones within a single process, because they need
    to parse input and format output according to the client's
    environment. The current [clock] facilities either do not
    support localization at all, or else support a change to locale
    only by changing environment variables.  This technique, once
    again, exposes bugs in the vendor libraries.  It also introduces
    difficulties with thread safety; Tcl does not have a single
    mechanism whereby the _TZ_ and _LC\_TIME_ environment variables
    are protected.

 4. The only mechanism for performing calculations like "one month
    after the current date" is [clock scan].  While this works well
    in practice, using a parser to perform arithmetic seems somewhat
    perverse.

# Specification

The [clock] command shall be reimplemented as an ensemble [[112]](112.md),
with most of the subcommands implemented in Tcl.  A minimal set of the
existing C code shall be refactored and placed inside a
_::tcl::clock_ namespace.  The existing subcommands _seconds_ and
_clicks_ shall be exposed.  The existing _scan_ shall be hidden
inside the namespace.  [clock scan] and [clock format] shall be
reimplemented in Tcl.  In addition, a new [clock add] command shall be added.

The syntax and semantics of the [clock clicks] and [clock seconds]
commands will remain unchanged.

### clock scan

The [clock scan] command shall have the syntax:

 > **clock scan** _string_
                    ?**-base** _baseTime_?
                    ?**-format** _format_?
                    ?**-gmt** _boolean_?
                    ?**-locale** _name_?
                    ?**-timezone** _timeZone_?

It accepts a character string representing a date and time and returns
the time that the string represents, expressed as a count of seconds
from the Posix epoch \(1 January 1970, 0000 UTC\).

If a **-format** option is not supplied, the scan is a _free format_
scan.  The existing YACC parser for _clock scan_ will be used to
interpret the input string.  _This form of the command is explicitly
deprecated_ because of the inherent ambiguities in interpreting the
input string.  The free-format version of [clock scan] does not
accept **-locale** or **-timezone** options, since the legacy code
does not support multiple locales or time zones.

If the **-format** options is supplied, it is interpreted as a
specification for the expected input form.  If the given string
matches the input form, it is converted to a count of seconds and
returned; otherwise, an error is thrown. See _FORMATS_ below for a
discussion of the available format groups and their interpretation.

Extraction of the date from the input string is guided by what fields
are present in the format.  The order of preference, from highest to
lowest, is:

 \{seconds from epoch\}, \{starDate\}: Date fields that specify both date
   and time take highest precedence.  If format groups for these
   fields appear multiple times, the rightmost takes precedence.

 \{Julian Day Number\}: The Julian Day Number uniquely specifies a
   calendar date.

 \{century, year, month, day of month\}, \{century, year, day of year\}, \{century, year, week of year, day of week\}, \{locale era, locale year, month, day of month\}:
   Formats with complete year are
   preferred to formats with a two-digit year.  For a two digit year,
   the date range is constrained to lie between 1938 and 2037.

 \{year, month, day of month\}, \{year, day of year\}, \{year, week of year, day of week\}, \{year of locale era, month, day of month\}:
   Formats that specify the year are preferred to those that do not.

 \{month, day of month\}, \{day of year\}, \{week of year, day of week\}:
   Formats that specify a day within the year are preferred to those
   that specify merely the day of week or day of month.  Formats that
   do not specify the year are presumed to designate the base year.

 \{day of month\}, \{day of week\}: If none of the above rules apply, a
   day of the month or day of the week standing alone is interpreted
   as belonging to the base month or week.

 None of the above: If no combination of fields that specifies a date
   is found, the base date is used.

The time of day returned by [clock scan] is determined by the
presence of fields in the format string, in the following order of
preference.

 \{seconds from epoch, StarDate\}: If either of these fields is present,
   it uniquely determines date and time.

 \{am/pm indicator, hour am/pm, minute, second\}, \{hour, minute, second\}:
   Time with seconds is preferred to time without seconds.

 \{am/pm indicator, hour am/pm, minute\}, \{hour, minute\}: Time can be
   interpreted without the seconds.

 \{am/pm indicator, hour am/pm\}, \{hour\}: Time can be expressed as an
   hour alone, _e.g._,

	 clock scan "6 pm" -format "%I %p"

 None of the above: If none of the above indicators is present,
   _00:00:00_ \(the start of the day\) in the given time zone is used.

In all of the foregoing discussion, the 'base date', 'base month',
'base week', and 'base year' refer to the day, month, week or year
designated by the **-base** parameter, which is a count of seconds
from the Posix epoch.  If no **-base** parameter is supplied, the
current date is used as the base date.  The year, month, week and day
are obtained by interpreting the base date in the time zone specified
by the date/time string.  If the given format does not include a time
zone, then the base time is interpreted in the default time zone; see
_TIME ZONES_ below for the way that the default time zone is
determined, and the interpretation of the **-timezone** and **-gmt**
options.

The locale is used to determine the spelling of native language words
such as the names of months, names of weekdays, am/pm indicators, and
locale eras.  It is also used in the interpretation of the format
groups, '%X', '%x', and '%c'.  In addition, the locale determines the
date at which the calendar in use changes from the Julian calendar to
the Gregorian.  If no **-locale** parameter is supplied, the default
is to use the root locale.  See _LOCALISATION_ below for more
information.

### clock format

The [clock format] command shall have the syntax:

 > **clock format** _string_
                      ?**-format** _format_?
                      ?**-gmt** _boolean_?
                      ?**-locale** _name_?
                      ?**-timezone** _timeZone_?

It accepts a time, expressed in seconds from the Posix epoch of 1
January 1970, 00:00 UTC, and formats it according to the given format
string.  See _FORMATS_ below for a discussion of the available
format codes.  If no format string is supplied, a default format, \{%a
%b %d %H:%M:%S %Z %Y\} is used.

The **-timezone**, **-gmt**, and **-locale** options are interpreted
as for [clock scan].  See _TIME ZONES_ and _LOCALISATION_ below
for how these options work.

### clock add

This command performs arithmetic on dates and times.  The syntax
is:

 > **clock add** _time_ ?_count unit_?...
   ?**-gmt** _boolean_? ?**-timezone** _timeZone_?
   ?**-locale** _name_?

It accepts a time, expressed in seconds from the Posix epoch of 1
January 1970, 00:00 UTC, and adds or subtracts units of time from it
according to the alternating _count_ and _unit_ parameters.  Each
_count_ must be a wide integer; each _unit_ is one of the
following:

	 years   year    months  month
	                 weeks   week    days    day
	 hours   hour    minutes minute  seconds second

The command works by converting the given time to a calendar day and
time of day in the given locale and time zone.  To that day and time
of day, it adds or subtracts the given offsets _in sequence_.  It
reconverts the resulting time to a count of seconds, again using the
given locale and time zone, and returns that count of seconds.

There are subtle differences in many cases between adding seemingly
similar offsets.  For instance, on the day before Daylight Saving Time
goes into effect, adding 24 hours will give "the time 24 hours from
the base time, irrespective of any clock change", while adding 1 day
will give "the time it will be at the same time of day on the
following day."  Similarly, adding 1 month on 30 January will give
either 28 or 29 February.  There are equally strange effects when
performing date/time arithmetic across the change between the Julian
and Gregorian calendars.

The **-timezone**, **-gmt**, and **-locale** options are used to
control the interpretation of the count of seconds as a calendar day
and time.  Refer to _TIME ZONES_ and _LOCALIZATION_ below for a
fuller discussion.

## Formats

The [clock scan] and [clock format] commands will be implemented
in Tcl, without depending on the local _strftime_ and _strptime_
functions.  For this reason, format groups will function identically
on all platforms.  The format groups will be interpreted as follows.

 %a: On output, receives the abbreviation for the day of the week in
     the given locale.  On input, matches the name of the day of the
     week \(in the given locale\) in either abbreviated or full form,
     and may be used to determine the calendar date.

 %A: On output, receives the full name of the day of the week in the
     given locale.  On input, treated identically with %a.

 %b: On output, receives the abbreviation for the name of the month in
     the given locale.  On input, matches the name of the month \(in
     the given locale\) in either abbreviated or full form, and may be
     used to determine the calendar date.

 %B: On output, receives the full name of the month in the given
     locale.  On input, treated identically with %b.

 %C: On output, receives the number of the century, in Indo-Arabic
     numerals.  On input, matches one or two digits, and accepts the
     number of the century in Indo-Arabic numerals.  May be used to
     determine the calendar date.

 %c: On output, produces a correct locale-dependent representation of
     date and time of day.  On input, matches whatever format _%c_
     produces in the given locale, and may be used to determine
     calendar date and time.

 %d: On output, produces the number of the day of the month, in
     Indo-Arabic numerals, with a leading zero.  On input, matches one
     or two digits, accepts the day of the month, and may be used to
     determine calendar date.
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
      and may be used to determine calendar date.

 %EX: On output, produces the time of day in the locale's alternative
      representation.  On input, accepts whatever %EX produces and may
      be used to determine time of day.

 %Ey: On output, produces the number of the current year relative to
      the locale's current era ''%EC'', expressed in the locale's
      alternative numerals.  On input, accepts the number of the year
      relative to the current era in the locale's alternative
      numerics, and may be used to determine calendar date.

 %EY: On output, produces an unambiguous representation of the current
      year in the locale's alternative calendar and alternative
      numerals.  This group is often synonymous with %EC%Ey.  On







|







358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
      and may be used to determine calendar date.

 %EX: On output, produces the time of day in the locale's alternative
      representation.  On input, accepts whatever %EX produces and may
      be used to determine time of day.

 %Ey: On output, produces the number of the current year relative to
      the locale's current era _%EC_, expressed in the locale's
      alternative numerals.  On input, accepts the number of the year
      relative to the current era in the locale's alternative
      numerics, and may be used to determine calendar date.

 %EY: On output, produces an unambiguous representation of the current
      year in the locale's alternative calendar and alternative
      numerals.  This group is often synonymous with %EC%Ey.  On
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
     with the ISO8601 week number.  On input, accepts a four-digit
     year number, and may be used to determine calendar date if the %V
     format group is also present.

 %h: Synonymous with %b.

 %H: On output, produces the two-digit hour of the day on a 24-hour
     clock (00-24).  On input, matches two digits, and may be used to
     determine time of day.

 %I: On output, produces the two-digit hour of the day on a 12-hour
     clock (12-11).  On input, matches two digits, and may be used to
     determine time of day.

 %j: On output, produces the three-digit number of the day of the
     year.  On input, matches three digits, and may be used to
     determine the day of the year.

 %J: On output, produces the number of the Julian Day Number beginning
     at noon of the given date.  The Julian Day Number is a
     representation popular with astronomers; it is a count of days in
     which Day 1 is 1 January, 4713 B.C.E., on the proleptic Julian
     calendar; in this system, 1 January 2000 is Julian Day 2451545.
     On input, matches any string of digits and interprets it as a
     Julian Day; may be used to determine calendar date.

 %k: On output, produces the number of the hour on a 24-hour clock
     (0-24) without a leading zero.  On input, matches one or two
     digits and may be used to determine time of day.

 %l: On output, produces the number of the hour on a 12-hour clock
     (12-11) without a leading zero.  On input, matches one or two
     digits and may be used to determine time of day.

 %m: On output, produces the number of the month (01-12), with exactly
     two digits (using a leading zero if necessary).  On input,
     matches exactly two digits and may be used to determine calendar
     date.

 %M: On output, produces the number of the minute of the hour (00-59)
     with exactly two digits (using a leading zero if necessary).  On
     input, matches exactly two digits and may be used to determine
     time of day.

 %N: On output, produces the number of the month, with no leading
     zero.  On input, matches one or two digits, and may be used to
     determine time of day.

 %Od, %Oe, %OH, %OI, %Ok, %Ol, %Om, %OM, %OS, %Ou, %ow, %Oy: All of
     these format groups are synonymous with their counterparts
     without the 'O', except that the string is produced and parsed in
     the locale-dependent alternative numerals.

 %p: On output, produces the indicator for 'a.m.', or 'p.m.'
     appropriate for the given locale, converted to upper case.  On
     input, accepts whatever %p produces (in upper or lower case) and
     may be used to determine time of day.

 %P: On output, produces the indicator for 'a.m.', or 'p.m.'
     appropriate for the given locale.  On input, accepts whatever %p
     produces (in upper or lower case) and may be used to determine
     time of day.

 %Q: On output, produces a StarDate.  On input, accepts a StarDate and
     may be used to determine calendar date and time of day.

 %r: On output, produces a locale-dependent time of day representation
     on a 12-hour clock.  On input, accepts whatever %r produces and
     may be used to determine time of day.

 %R: On output, produces a locale-dependent time of day representation
     on a 24-hour clock.  On input, accepts whatever %R produces and
     may be used to determine time of day.

 %s: On output, produces a string of digits representing the count of
     seconds since 1 January 1970, 00:00 UTC.  On input, accepts a
     string of digits and accepts it as such a count; may be used to
     determine date and time of day.

 %S: On output, produces a two-digit number of the second of the
     minute (00-59).  On input, accepts two digits.  May be used to
     determine time of day.

 %t: On output, produces a TAB character.  On input, matches a TAB
     character.

 %T: Synonymous with %H:%M:%S.

 %u: On output, produces the number of the day of the week
     (1-Monday,7-Sunday).  On input, accepts a single digit.  May be
     used to determine calendar day.

 %U: On output, produces the ordinal number of the week of the year
     (00-53).  The first Sunday of the year is the first day of week
     01.  On input accepts two digits ''which are otherwise ignored.''
     This format group is never used in determining an input date.

 %V: On output, produces the number of the ISO8601 week as a two digit
     number (01-53).  Week 01 is the week containing January 4; or the
     first week of the year containing at least 4 days; or the week
     containing the first Thursday of the year (the three statements
     are equivalent). Each week begins on a Monday.  On input, accepts
     the ISO8601 week number, and may be used to determine the
     calendar day.

 %w: On output, produces a week number (00-53) within the year; week
     01 begins on the first Monday of the year.  On input, accepts two
     digits, ''which are otherwise ignored.''  This format group is
     never used in determining an input date.

 %x: On output, produces the date in a locale-dependent
     representation.  On input, accepts whatever %x produces and may
     be used to determine calendar date.

 %X: On output, produces the time of day in a locale-dependent







|



|















|



|


|
|



|
|














|




|



















|








|



|
|



|

|
|



|

|







382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
     with the ISO8601 week number.  On input, accepts a four-digit
     year number, and may be used to determine calendar date if the %V
     format group is also present.

 %h: Synonymous with %b.

 %H: On output, produces the two-digit hour of the day on a 24-hour
     clock \(00-24\).  On input, matches two digits, and may be used to
     determine time of day.

 %I: On output, produces the two-digit hour of the day on a 12-hour
     clock \(12-11\).  On input, matches two digits, and may be used to
     determine time of day.

 %j: On output, produces the three-digit number of the day of the
     year.  On input, matches three digits, and may be used to
     determine the day of the year.

 %J: On output, produces the number of the Julian Day Number beginning
     at noon of the given date.  The Julian Day Number is a
     representation popular with astronomers; it is a count of days in
     which Day 1 is 1 January, 4713 B.C.E., on the proleptic Julian
     calendar; in this system, 1 January 2000 is Julian Day 2451545.
     On input, matches any string of digits and interprets it as a
     Julian Day; may be used to determine calendar date.

 %k: On output, produces the number of the hour on a 24-hour clock
     \(0-24\) without a leading zero.  On input, matches one or two
     digits and may be used to determine time of day.

 %l: On output, produces the number of the hour on a 12-hour clock
     \(12-11\) without a leading zero.  On input, matches one or two
     digits and may be used to determine time of day.

 %m: On output, produces the number of the month \(01-12\), with exactly
     two digits \(using a leading zero if necessary\).  On input,
     matches exactly two digits and may be used to determine calendar
     date.

 %M: On output, produces the number of the minute of the hour \(00-59\)
     with exactly two digits \(using a leading zero if necessary\).  On
     input, matches exactly two digits and may be used to determine
     time of day.

 %N: On output, produces the number of the month, with no leading
     zero.  On input, matches one or two digits, and may be used to
     determine time of day.

 %Od, %Oe, %OH, %OI, %Ok, %Ol, %Om, %OM, %OS, %Ou, %ow, %Oy: All of
     these format groups are synonymous with their counterparts
     without the 'O', except that the string is produced and parsed in
     the locale-dependent alternative numerals.

 %p: On output, produces the indicator for 'a.m.', or 'p.m.'
     appropriate for the given locale, converted to upper case.  On
     input, accepts whatever %p produces \(in upper or lower case\) and
     may be used to determine time of day.

 %P: On output, produces the indicator for 'a.m.', or 'p.m.'
     appropriate for the given locale.  On input, accepts whatever %p
     produces \(in upper or lower case\) and may be used to determine
     time of day.

 %Q: On output, produces a StarDate.  On input, accepts a StarDate and
     may be used to determine calendar date and time of day.

 %r: On output, produces a locale-dependent time of day representation
     on a 12-hour clock.  On input, accepts whatever %r produces and
     may be used to determine time of day.

 %R: On output, produces a locale-dependent time of day representation
     on a 24-hour clock.  On input, accepts whatever %R produces and
     may be used to determine time of day.

 %s: On output, produces a string of digits representing the count of
     seconds since 1 January 1970, 00:00 UTC.  On input, accepts a
     string of digits and accepts it as such a count; may be used to
     determine date and time of day.

 %S: On output, produces a two-digit number of the second of the
     minute \(00-59\).  On input, accepts two digits.  May be used to
     determine time of day.

 %t: On output, produces a TAB character.  On input, matches a TAB
     character.

 %T: Synonymous with %H:%M:%S.

 %u: On output, produces the number of the day of the week
     \(1-Monday,7-Sunday\).  On input, accepts a single digit.  May be
     used to determine calendar day.

 %U: On output, produces the ordinal number of the week of the year
     \(00-53\).  The first Sunday of the year is the first day of week
     01.  On input accepts two digits _which are otherwise ignored._
     This format group is never used in determining an input date.

 %V: On output, produces the number of the ISO8601 week as a two digit
     number \(01-53\).  Week 01 is the week containing January 4; or the
     first week of the year containing at least 4 days; or the week
     containing the first Thursday of the year \(the three statements
     are equivalent\). Each week begins on a Monday.  On input, accepts
     the ISO8601 week number, and may be used to determine the
     calendar day.

 %w: On output, produces a week number \(00-53\) within the year; week
     01 begins on the first Monday of the year.  On input, accepts two
     digits, _which are otherwise ignored._  This format group is
     never used in determining an input date.

 %x: On output, produces the date in a locale-dependent
     representation.  On input, accepts whatever %x produces and may
     be used to determine calendar date.

 %X: On output, produces the time of day in a locale-dependent
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841

842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957


 %Y: On output, produces the four-digit calendar year.  On input,
     accepts four digits and may be used to determine calendar date.
     Note that %Y does not yield a year appropriate for use with the
     ISO8601 week number %V; programs should use %G for that purpose.

 %z: On output, produces the current time zone, expressed in hours and
     minutes east (+hhmm) or west (-hhmm) of Greenwich.  On input,
     accepts a time zone specifier (see ''TIME ZONES'' below) that
     will be used to determine the time zone.

 %Z: On output, produces the current time zone's name, possibly
     translated to the given locale.  On input, accepts a time zone
     specifier (see ''TIME ZONES'' below) that will be used to
     determine the time zone.  ''This option should, in general, be
     used on input only when parsing RFC822 dates.'' Other uses are
     fraught with ambiguity; for instance, the string ''BST'' may
     represent ''British Summer Time'' or ''Brazilian Standard Time''.
     It is recommended that date/time strings for use by computers use
     numeric time zones instead.

 %%: On output, produces a literal '%' charater.  On input, matches a
     literal '%' character.

 %+: Synonymous with "%a %b %e %H:%M:%S %Z %Y".

~~Time Zones

There are several ways that a time zone may be specified for use with
[[clock scan]], [[clock format]] and [[clock add]].  In order of preference:

 * The time zone may appear in the input string matched by a %z or %Z
   format group in [[clock scan]].  These format groups match time
   zones in the forms +hhmm, +hhmmss, -hhmm, -hhmmss, and alphanumeric
   strings.  The numeric representations are self explanatory; an
   alphanumeric string must be the one of:

| gmt     ut      utc     bst     wet     wat     at
| nft     nst     ndt     ast     adt     est     edt
| cst     cdt     mst     mdt     pst     pdt     yst
| ydt     hst     hdt     cat     ahst    nt      idlw
| cet     cest    met     mewt    mest    swt     sst
| eet     eest    bt      it      zp4     zp5     ist
| zp6     wast    wadt    jt      cct     jst     cast
| cadt    east    eadt    gst     nzt     nzst    nzdt
| idle

 > or a single letter other than J.  Generally speaking, numeric time
   zones should be preferred for communication among computers; the
   alphanumeric time zones are provided primarily for the parsing of
   legacy RFC822 time stamps.

 * The time zone may appear in the '''-timezone''' argument to the
   [[clock]] command, or may be implied by the presence of '''-gmt 1'''.
   It is an error to use '''-timezone''' and '''-gmt''' in the same
   call.  The '''-gmt 1''' option may be regarded as an obsolete
   synonym of '''-timezone :UTC'''.

 * The time zone may appear in the environment variable, ''TCL_TZ''.

 * The time zone may appear in the environment variable, ''TZ''.

 * Failing all of these, on Windows systems, the time zone will be
   obtained from the Registry.

 * As a last resort, the time zone is set to ':localtime'.

Once the time zone is obtained by one of these means, it is
interpreted as follows:

 ":localtime": This specifier requests that the C library functions
   ''localtime()'' and ''mktime()'' be used whenever converting times
   between local and Greenwich.  It is generally used as a last resort
   if the time zone can be determined in no other way.

 "+hhmm", "+hhmmss", "-hhmm", "-hhmmss": These specifiers give the
   time zone explicitly in terms of hours, minutes and seconds east
   (+) or west (-) of Greenwich.

 ":filename": The given file name is interpreted as a path name
   relative to [[info library]]/tzdata, and the specified file is
   loaded as a Tcl script.  The script is expected to set the
   '':filename'' element in the ''tzdata'' array to a list of
   transitions.  Each transition is a four-element list comprising:

 > * the time at which the transition takes place, expressed in
     seconds from the Posix Epoch (1 January 1970, 00:00 UTC)

 > * the offset (in seconds east of Greenwich) to apply.

 > * an indicator (0=Standard Time, 1=Daylight Saving Time)

 > * the name to use when displaying the given time zone in the root
     locale.

 > The first transition is expected to take place at time
   -9223372036854775808, the smallest value of a wide integer.

 Any string recognizable as a Posix time zone specifier: A time zone
   may be specified in Posix syntax (see
   [http://www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap08.html]),
   for example ''EST5EDT'' or
   ''EST+05:00EDT+04:00,M4.1.0/01:00,M10.5.0/02:00''.

Any other string is processed by prefixing a colon and attempting to
load the given file, as shown above.

~~Localisation

The [[clock]] command is localised by a set of message catalogs
located in [[file join [[info library]] clock msgs]] and loaded into
the namespace, ::tcl::clock.  The possible strings to be translated
include:

 AM: The string that identifies ''ante meridiem'' times when
     expressing a time of day in the given locale.  This string has
     the value, {am} in the root locale.

 BCE: The string that identifies dates before the Common Era in the
     given locale.  This string has the value, {B.C.E.} in the root
     locale.  Those localising this string should be aware that,
     depending on local culture, a name such as "B.C."  (before
     Christ) may be offensive.

 CE: The string that identifies dates of the Common Era in the given
     locale.  This string has the value, {C.E.} in the root locale.
     Those localising this string should be aware that, depending on
     local culture, a name such as "A.D."  (Latin, ''anno Domini'',
     "in the year of Our Lord") may be offensive.

 DATE_FORMAT: The format specifier for calendar dates in the given
     locale.  In the root locale, %m/%d/%Y is used for compatibility
     with earlier versions of the [[clock]] command, even though
     %Y-%m-%d would probably be preferable.

 DATE_TIME_FORMAT: The format specifier for combined date and time in
     the given locale.  In the root locale, {%a %b %e %H:%M:%S %Y} is
     used for compatibility with earlier versions of the [[clock]]
     command, even though %Y-%m-%dT%H:%M:%S would be preferable.

 DAYS_OF_WEEK_ABBREV: Abbreviations of the days of the week in the
     given locale.  In the root locale, this string has the value,
     {Sun Mon Tue Wed Thu Fri Sat}.  In any locale, this string
     is expected to represent a valid Tcl list.

 DAYS_OF_WEEK_FULL: Full names of the days of the week in the given
     locale.  In the root locale, this string has the value, {Sunday
     Monday Tuesday Wednesday Thursday Friday Saturday}.
     In any locale, this string is expected to represent a valid
     Tcl list.

 GREGORIAN_CHANGE_DATE: The date on which the change from the Julian
     to the Gregorian calendar takes place, expressed as a Julian Day
     Number.  In the root locale, this string has the value,
     {2299161}, corresponding to 15 October 1582 New Style. In the
     'en' locale, this value is {2361222}, 14 September 1752 New
     Style.

 LOCALE_DATE_FORMAT: The format to use when formatting dates in the
     locale's alternative calendar.  In the root locale,
     LOCALE_DATE_FORMAT is ''%x'', which causes formatting without
     alternative numerals.

 LOCALE_DATE_TIME_FORMAT: The format to use when formatting date/time
     strings in the locale's alternative calendar.  In the root locale,
     LOCALE_DATE_TIME_FORMAT is ''%Ex %EX'', which causes concatenation
     of the locale's format for date, a space character, and the
     locale's format for time.

 LOCALE_ERAS: In a locale where a calendar with multiple eras is in
     use, gives a list of triples.  The first element of each triple
     is the time (in seconds from the Posix epoch of 1 January 1970,
     00:00 UTC) at which the era begins; the second is the name of the
     era, and the third is a constant offset to be subtracted from the
     Gregorian year to give the year of the era.
     In any locale, this string is expected to represent a valid
     Tcl list.

 LOCALE_NUMERALS: In a locale where alternative numerals may be used,
     gives a list containing the numerals that represent the numbers
     from zero to ninety-nine.  Note that these numerals are the ones
     typically used on calendars, not the ones that represent
     currencies or quantities.  For instance, in a Han locale, the
     number twenty-one is represented by \u5eff\u4e00, not by
     \u4e8c\u5341\u4e00.
     In any locale, this string is expected to represent a valid
     Tcl list.

 LOCALE_TIME_FORMAT: The time format to use when formatting a time of
     day using a locale's alternative numerals. In the root locale,
     this string is ''%X'', which causes formatting without alternative
     numerals.

 LOCALE_YEAR_FORMAT: The time format to use when formatting a year in
     the locale's alternative calendar.  In the root locale, this
     string is %Y.

 MONTHS_ABBREV: Abbreviated names of the months in the given locale.
     In the root locale, consists of three-letter abbreviations for
     the English months: Jan-Dec.
     In any locale, this string is expected to represent a valid
     Tcl list.

 MONTHS_FULL: Full names of the months in the given locale.  In the
     root locale, consists of the names of the English months in order
     from 'January' to 'December'.
     In any locale, this string is expected to represent a valid
     Tcl list.

 PM: The string that identifies ''post meridiem'' times when
     expressing a time of day in the given locale.  This string has
     the value, {pm} in the root locale.

 TIME_FORMAT: String that specifies the default time format in the
     given locale.  In the root locale, this string is {%H:%M:%S}

 TIME_FORMAT_12: String that formats time on a 12-hour clock in the
     given locale.  In the root locale, this string is {%I:%M:%S %p}.

 TIME_FORMAT_24: String that formats time on a 24-hour clock in the
     given locale.  In the root locale, this string is {%H:%M}.

There is a defined order for substitution of locale strings, which
constrains the format groups that can appear in the ''_FORMAT'' strings.
Specifically:

   * DATE_TIME_FORMAT and LOCALE_DATE_TIME_FORMAT may contain any
     format groups other than ''%c'' and ''%Ec''.

   * LOCALE_DATE_FORMAT and LOCALE_TIME_FORMAT may not contain
     ''%c'', ''%Ec'', ''%Ex'', or ''%EX''.

   * DATE_FORMAT and TIME_FORMAT may not contain ''%c'', ''%Ec'',
     ''%x'', ''%Ex'', ''%X'', or ''%EX''.

   * TIME_FORMAT_12 and TIME_FORMAT_24 may not contain ''%c'', ''%Ec'',
     ''%r'', ''%R'', ''%T'', ''%x'', ''%Ex'', ''%X'', or ''%EX''.

   * LOCALE_YEAR_FORMAT may not contain  ''%c'', ''%Ec'',
     ''%r'', ''%R'', ''%T'', ''%x'', ''%Ex'', ''%X'', ''%EX'', or ''%Ey''.

''Example.'' The following file is "ja.msg", which localises the
[[clock]] command to a Japanese locale.

|namespace eval ::tcl::clock {
|    ::msgcat::mcset ja DAYS_OF_WEEK_ABBREV [list \
|        "\u65e5"\
|        "\u6708"\
|        "\u706b"\
|        "\u6c34"\
|        "\u6728"\
|        "\u91d1"\
|        "\u571f"]
|    ::msgcat::mcset ja DAYS_OF_WEEK_FULL [list \
|        "\u65e5\u66dc\u65e5"\
|        "\u6708\u66dc\u65e5"\
|        "\u706b\u66dc\u65e5"\
|        "\u6c34\u66dc\u65e5"\
|        "\u6728\u66dc\u65e5"\
|        "\u91d1\u66dc\u65e5"\
|        "\u571f\u66dc\u65e5"]
|    ::msgcat::mcset ja MONTHS_ABBREV [list \
|        "1"\
|        "2"\
|        "3"\
|        "4"\
|        "5"\
|        "6"\
|        "7"\
|        "8"\
|        "9"\
|        "10"\
|        "11"\
|        "12"\
|        ""]
|    ::msgcat::mcset ja MONTHS_FULL [list \
|        "1\u6708"\
|        "2\u6708"\
|        "3\u6708"\
|        "4\u6708"\
|        "5\u6708"\
|        "6\u6708"\
|        "7\u6708"\
|        "8\u6708"\
|        "9\u6708"\
|        "10\u6708"\
|        "11\u6708"\
|        "12\u6708"\
|        ""]
|    ::msgcat::mcset ja BCE "\u7d00\u5143\u524d"
|    ::msgcat::mcset ja CE "\u897f\u66a6"
|    ::msgcat::mcset ja AM "\u5348\u524d"
|    ::msgcat::mcset ja PM "\u5348\u5f8c"
|    ::msgcat::mcset ja DATE_FORMAT "%Y/%m/%d"
|    ::msgcat::mcset ja TIME_FORMAT "%k:%M:%S"
|    ::msgcat::mcset ja DATE_TIME_FORMAT "%Y/%m/%d %k:%M:%S %z"
|    ::msgcat::mcset ja LOCALE_NUMERALS "\u3007 \u4e00 \u4e8c \u4e09 \u56db
|       \u4e94 \u516d \u4e03 \u516b \u4e5d \u5341 \u5341\u4e00 \u5341\u4e8c
|       \u5341\u4e09 \u5341\u56db \u5341\u4e94 \u5341\u516d \u5341\u4e03 
|       \u5341\u516b \u5341\u4e5d \u4e8c\u5341 \u5eff\u4e00 \u5eff\u4e8c 
|       \u5eff\u4e09 \u5eff\u56db \u5eff\u4e94 \u5eff\u516d \u5eff\u4e03 
|       \u5eff\u516b \u5eff\u4e5d \u4e09\u5341 \u5345\u4e00 \u5345\u4e8c 
|       \u5345\u4e09 \u5345\u56db \u5345\u4e94 \u5345\u516d \u5345\u4e03 
|       \u5345\u516b \u5345\u4e5d \u56db\u5341 \u56db\u5341\u4e00 
|       \u56db\u5341\u4e8c \u56db\u5341\u4e09 \u56db\u5341\u56db 
|       \u56db\u5341\u4e94 \u56db\u5341\u516d \u56db\u5341\u4e03 
|       \u56db\u5341\u516b \u56db\u5341\u4e5d \u4e94\u5341 
|       \u4e94\u5341\u4e00 
|       \u4e94\u5341\u4e8c \u4e94\u5341\u4e09 \u4e94\u5341\u56db 
|       \u4e94\u5341\u4e94 \u4e94\u5341\u516d \u4e94\u5341\u4e03 
|       \u4e94\u5341\u516b \u4e94\u5341\u4e5d \u516d\u5341 
|       \u516d\u5341\u4e00 \u516d\u5341\u4e8c \u516d\u5341\u4e09 
|       \u516d\u5341\u56db \u516d\u5341\u4e94 \u516d\u5341\u516d 
|       \u516d\u5341\u4e03 \u516d\u5341\u516b \u516d\u5341\u4e5d
|       \u4e03\u5341 
|       \u4e03\u5341\u4e00 \u4e03\u5341\u4e8c \u4e03\u5341\u4e09 
|       \u4e03\u5341\u56db \u4e03\u5341\u4e94 \u4e03\u5341\u516d 
|       \u4e03\u5341\u4e03 \u4e03\u5341\u516b \u4e03\u5341\u4e5d
|       \u516b\u5341 
|       \u516b\u5341\u4e00 \u516b\u5341\u4e8c \u516b\u5341\u4e09 
|       \u516b\u5341\u56db \u516b\u5341\u4e94 \u516b\u5341\u516d 
|       \u516b\u5341\u4e03 \u516b\u5341\u516b \u516b\u5341\u4e5d 
|       \u4e5d\u5341 
|       \u4e5d\u5341\u4e00 \u4e5d\u5341\u4e8c \u4e5d\u5341\u4e09 
|       \u4e5d\u5341\u56db \u4e5d\u5341\u4e94 \u4e5d\u5341\u516d 
|       \u4e5d\u5341\u4e03 \u4e5d\u5341\u516b \u4e5d\u5341\u4e5d"
|    ::msgcat::mcset ja LOCALE_DATE_FORMAT "%EY\u5e74%B%Od\u65e5"
|    ::msgcat::mcset ja LOCALE_TIME_FORMAT "%OH\u6642%OM\u5206%OS\u79d2"
|    ::msgcat::mcset ja LOCALE_DATE_TIME_FORMAT \
|        "%A %EY\u5e74%B%Od\u65e5%OH\u6642%OM\u5206%OS\u79d2 %z"
|    ::msgcat::mcset ja LOCALE_ERAS "
|        {-9223372036854775808 \u897f\u66a6 0} 
|        {-3060979200 \u660e\u6cbb 1867} 
|        {-1812153600 \u5927\u6b63 1911} 
|        {-1357603200 \u662d\u548c 1925} 
|        {568512000 \u5e73\u6210 1987}"
|}


In addition to the standard locales, two special locales may appear on
the '''-locale''' parameter; '''current''', which designates the result of
evaluating [[mclocale]], and '''system''', which designates the current
"system" locale, which is determined by (in order of preference):

   * the date/time format settings on the Windows control panel

   * the environment variable LC_TIME

   * the current locale from [[mclocale]].

~~ Build System

Several tools are provided for the use of maintainers:

 loadICU.tcl:
    Given a distribution of IBM's ''icu4c''
    [http://oss.software.ibm.com/icu/index.html],
    this program analyzes the source code of the message catalogs and
    extracts appropriate Tcl-based messages for the date and time
    formats in the supported locales.

 loadtzif.tcl:
    Given a time zone information file used by the Olson version of
    'tzset' (for a description, see the latest 'tzcode' file in
    [ftp://elsie.nci.nih.gov/pub/]), creates the corresponding Tcl
    'tzdata' file.

 makeTestCases.tcl:
    Makes several thousand auto-generated test cases to exercise
    the time conversion algorithms.

 tclZIC.tcl:
    Given the source code for the Olson time zone descriptions
    (obtainable as the latest 'tzdata' file in
    [ftp://elsie.nci.nih.gov/pub/]), creates the full set of Tcl
    'tzdata' files.

Since these tools depend on third party source, they will not be
included in the usual build steps; instead, maintainers will be
expected to run them whenever changing files on which they depend.  It
will be a good practice to update the ICU and Olson files just before
cutting a release.

~ Reference Implementation

The implementation of a refactored [[clock]] command is a work
in progress, and interested developers are urged to contact the
TIP author if they want to help with implementation, documentation,
or testing.  The code is available in the same SourceForge
repository as the Tcl core, and Tcl maintainers can obtain it
with

|  cvs -d:ext:[email protected]:/cvsroot/tcl co newclock

~ Notes on the cost of implementation

Since it is well known that Tcl code is typically 30-50 times slower
than the equivalent C, it is to be expected that [[clock scan]],
[[clock format]], and [[clock add]]
will be in that performance range.  [[clock seconds]] and
[[clock clicks]] will still be C code and are not expected to
suffer a measurable change in performance.  (If they do, the
implementors plan to address the issue.)

The cost of the time zone data files and the message catalogs
is not trivial; they occupy about 1.6 megabytes exclusive of file
system fragmentation and may occupy multiple megabytes depending
on the minimum size of a file.  The implementors assume (and are
working to ensure) that some sort of compressed virtual file system
will be available as core functionality in the 8.5 final release.
With zlib compression, the message catalogs and time zone data total
less than half a megabyte.  It is worth noting that a distribution
that must run in the absolute minimum space may omit both message
catalogs and time zone data; if this is done, named time zones
(e.g., :America/New_York) will not be available on systems such
as Windows that lack 'zoneinfo', and will suffer from Y2038
bugs on systems such as Solaris and Linux that have 'zoneinfo'.
Without the message catalogs, the only
supported locale will be the root locale (and on Windows, the 'system' locale).  This combination
provides functionality comparable to the [[clock]] command prior
to this TIP.  The Tcl code that implements [[clock]] is less than
eighty kilobytes with comments and blank lines removed; this
amount of overhead is thought to be negligible.

~ Bugs

The reference implementation does not attempt any calendars not based
on the hybrid Julian/Gregorian calendar.  This implementation is
adequate for the Western countries and for the Japanese civil
calendar, but does not address the Hijri, Hebraic, Thai, Chinese or
Korean calendars. (No Tcl user has requested these, to the best of the
knowledge of the author of this TIP.)

The Gregorian change date is not supplied in most locales.

Localisation in most locales was done by an American who is probably
excessively ignorant in such matters.

This TIP makes no effort to be compliant with RFC 2550 
[http://www.faqs.org/rfcs/rfc2550.html].

~ Copyright

Copyright 2004, by Kevin B. Kenny.  Redistribution permitted under the
terms of the Open Publication License
[http://www.opencontent.org/openpub/].

~ Acknowledgments

The author of this TIP wishes to thank all the Tcl'ers who have
taken the time to read and comment on it, most notably Joe English,
Donal K. Fellows, Jeff Hobbs, Arjen Markus, Reinhard Max,
Christopher Nelson, Donald G. Porter,
Pascal Scheffers, and Peter da Silva.








|
|




|
|
|
|
|






|

|


|


|
|



|
|
|
|
|
|
|
|
|

|




|
|
|
|
|

|

|










|



|

|


|

|


|
|

|

|

|






|
|
|
|




|

|
|



|

|


|

|
|


|

|
|

|

|


|
|
|


|

|


|
|
|



|


|
|


|

|


|

|



|

|
|





|




|
|



|

|


|



|





|





|

|

|
|

|
|

|
|


|


|
|

|
|

|
|

|
|

|
|

|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>


|
|
|



|

|

|




|
|






|
|








|
|








|

|






|

|


|
|
|
|
|
|




|
|





|



|
|
|



|





|
|







|

|



|

|






>
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839

840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957

 %Y: On output, produces the four-digit calendar year.  On input,
     accepts four digits and may be used to determine calendar date.
     Note that %Y does not yield a year appropriate for use with the
     ISO8601 week number %V; programs should use %G for that purpose.

 %z: On output, produces the current time zone, expressed in hours and
     minutes east \(\+hhmm\) or west \(-hhmm\) of Greenwich.  On input,
     accepts a time zone specifier \(see _TIME ZONES_ below\) that
     will be used to determine the time zone.

 %Z: On output, produces the current time zone's name, possibly
     translated to the given locale.  On input, accepts a time zone
     specifier \(see _TIME ZONES_ below\) that will be used to
     determine the time zone.  _This option should, in general, be
     used on input only when parsing RFC822 dates._ Other uses are
     fraught with ambiguity; for instance, the string _BST_ may
     represent _British Summer Time_ or _Brazilian Standard Time_.
     It is recommended that date/time strings for use by computers use
     numeric time zones instead.

 %%: On output, produces a literal '%' charater.  On input, matches a
     literal '%' character.

 %\+: Synonymous with "%a %b %e %H:%M:%S %Z %Y".

## Time Zones

There are several ways that a time zone may be specified for use with
[clock scan], [clock format] and [clock add].  In order of preference:

 * The time zone may appear in the input string matched by a %z or %Z
   format group in [clock scan].  These format groups match time
   zones in the forms \+hhmm, \+hhmmss, -hhmm, -hhmmss, and alphanumeric
   strings.  The numeric representations are self explanatory; an
   alphanumeric string must be the one of:

		 gmt     ut      utc     bst     wet     wat     at
		 nft     nst     ndt     ast     adt     est     edt
		 cst     cdt     mst     mdt     pst     pdt     yst
		 ydt     hst     hdt     cat     ahst    nt      idlw
		 cet     cest    met     mewt    mest    swt     sst
		 eet     eest    bt      it      zp4     zp5     ist
		 zp6     wast    wadt    jt      cct     jst     cast
		 cadt    east    eadt    gst     nzt     nzst    nzdt
		 idle

	 > or a single letter other than J.  Generally speaking, numeric time
   zones should be preferred for communication among computers; the
   alphanumeric time zones are provided primarily for the parsing of
   legacy RFC822 time stamps.

 * The time zone may appear in the **-timezone** argument to the
   [clock] command, or may be implied by the presence of **-gmt 1**.
   It is an error to use **-timezone** and **-gmt** in the same
   call.  The **-gmt 1** option may be regarded as an obsolete
   synonym of **-timezone :UTC**.

 * The time zone may appear in the environment variable, _TCL\_TZ_.

 * The time zone may appear in the environment variable, _TZ_.

 * Failing all of these, on Windows systems, the time zone will be
   obtained from the Registry.

 * As a last resort, the time zone is set to ':localtime'.

Once the time zone is obtained by one of these means, it is
interpreted as follows:

 ":localtime": This specifier requests that the C library functions
   _localtime\(\)_ and _mktime\(\)_ be used whenever converting times
   between local and Greenwich.  It is generally used as a last resort
   if the time zone can be determined in no other way.

 "\+hhmm", "\+hhmmss", "-hhmm", "-hhmmss": These specifiers give the
   time zone explicitly in terms of hours, minutes and seconds east
   \(\+\) or west \(-\) of Greenwich.

 ":filename": The given file name is interpreted as a path name
   relative to [info library]/tzdata, and the specified file is
   loaded as a Tcl script.  The script is expected to set the
   _:filename_ element in the _tzdata_ array to a list of
   transitions.  Each transition is a four-element list comprising:

 > \* the time at which the transition takes place, expressed in
     seconds from the Posix Epoch \(1 January 1970, 00:00 UTC\)

 > \* the offset \(in seconds east of Greenwich\) to apply.

 > \* an indicator \(0=Standard Time, 1=Daylight Saving Time\)

 > \* the name to use when displaying the given time zone in the root
     locale.

 > The first transition is expected to take place at time
   -9223372036854775808, the smallest value of a wide integer.

 Any string recognizable as a Posix time zone specifier: A time zone
   may be specified in Posix syntax \(see
   <http://www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap08.html> \),
   for example _EST5EDT_ or
   _EST\+05:00EDT\+04:00,M4.1.0/01:00,M10.5.0/02:00_.

Any other string is processed by prefixing a colon and attempting to
load the given file, as shown above.

## Localisation

The [clock] command is localised by a set of message catalogs
located in [file join [info library] clock msgs] and loaded into
the namespace, ::tcl::clock.  The possible strings to be translated
include:

 AM: The string that identifies _ante meridiem_ times when
     expressing a time of day in the given locale.  This string has
     the value, \{am\} in the root locale.

 BCE: The string that identifies dates before the Common Era in the
     given locale.  This string has the value, \{B.C.E.\} in the root
     locale.  Those localising this string should be aware that,
     depending on local culture, a name such as "B.C."  \(before
     Christ\) may be offensive.

 CE: The string that identifies dates of the Common Era in the given
     locale.  This string has the value, \{C.E.\} in the root locale.
     Those localising this string should be aware that, depending on
     local culture, a name such as "A.D."  \(Latin, _anno Domini_,
     "in the year of Our Lord"\) may be offensive.

 DATE\_FORMAT: The format specifier for calendar dates in the given
     locale.  In the root locale, %m/%d/%Y is used for compatibility
     with earlier versions of the [clock] command, even though
     %Y-%m-%d would probably be preferable.

 DATE\_TIME\_FORMAT: The format specifier for combined date and time in
     the given locale.  In the root locale, \{%a %b %e %H:%M:%S %Y\} is
     used for compatibility with earlier versions of the [clock]
     command, even though %Y-%m-%dT%H:%M:%S would be preferable.

 DAYS\_OF\_WEEK\_ABBREV: Abbreviations of the days of the week in the
     given locale.  In the root locale, this string has the value,
     \{Sun Mon Tue Wed Thu Fri Sat\}.  In any locale, this string
     is expected to represent a valid Tcl list.

 DAYS\_OF\_WEEK\_FULL: Full names of the days of the week in the given
     locale.  In the root locale, this string has the value, \{Sunday
     Monday Tuesday Wednesday Thursday Friday Saturday\}.
     In any locale, this string is expected to represent a valid
     Tcl list.

 GREGORIAN\_CHANGE\_DATE: The date on which the change from the Julian
     to the Gregorian calendar takes place, expressed as a Julian Day
     Number.  In the root locale, this string has the value,
     \{2299161\}, corresponding to 15 October 1582 New Style. In the
     'en' locale, this value is \{2361222\}, 14 September 1752 New
     Style.

 LOCALE\_DATE\_FORMAT: The format to use when formatting dates in the
     locale's alternative calendar.  In the root locale,
     LOCALE\_DATE\_FORMAT is _%x_, which causes formatting without
     alternative numerals.

 LOCALE\_DATE\_TIME\_FORMAT: The format to use when formatting date/time
     strings in the locale's alternative calendar.  In the root locale,
     LOCALE\_DATE\_TIME\_FORMAT is _%Ex %EX_, which causes concatenation
     of the locale's format for date, a space character, and the
     locale's format for time.

 LOCALE\_ERAS: In a locale where a calendar with multiple eras is in
     use, gives a list of triples.  The first element of each triple
     is the time \(in seconds from the Posix epoch of 1 January 1970,
     00:00 UTC\) at which the era begins; the second is the name of the
     era, and the third is a constant offset to be subtracted from the
     Gregorian year to give the year of the era.
     In any locale, this string is expected to represent a valid
     Tcl list.

 LOCALE\_NUMERALS: In a locale where alternative numerals may be used,
     gives a list containing the numerals that represent the numbers
     from zero to ninety-nine.  Note that these numerals are the ones
     typically used on calendars, not the ones that represent
     currencies or quantities.  For instance, in a Han locale, the
     number twenty-one is represented by \\u5eff\\u4e00, not by
     \\u4e8c\\u5341\\u4e00.
     In any locale, this string is expected to represent a valid
     Tcl list.

 LOCALE\_TIME\_FORMAT: The time format to use when formatting a time of
     day using a locale's alternative numerals. In the root locale,
     this string is _%X_, which causes formatting without alternative
     numerals.

 LOCALE\_YEAR\_FORMAT: The time format to use when formatting a year in
     the locale's alternative calendar.  In the root locale, this
     string is %Y.

 MONTHS\_ABBREV: Abbreviated names of the months in the given locale.
     In the root locale, consists of three-letter abbreviations for
     the English months: Jan-Dec.
     In any locale, this string is expected to represent a valid
     Tcl list.

 MONTHS\_FULL: Full names of the months in the given locale.  In the
     root locale, consists of the names of the English months in order
     from 'January' to 'December'.
     In any locale, this string is expected to represent a valid
     Tcl list.

 PM: The string that identifies _post meridiem_ times when
     expressing a time of day in the given locale.  This string has
     the value, \{pm\} in the root locale.

 TIME\_FORMAT: String that specifies the default time format in the
     given locale.  In the root locale, this string is \{%H:%M:%S\}

 TIME\_FORMAT\_12: String that formats time on a 12-hour clock in the
     given locale.  In the root locale, this string is \{%I:%M:%S %p\}.

 TIME\_FORMAT\_24: String that formats time on a 24-hour clock in the
     given locale.  In the root locale, this string is \{%H:%M\}.

There is a defined order for substitution of locale strings, which
constrains the format groups that can appear in the _\_FORMAT_ strings.
Specifically:

   * DATE\_TIME\_FORMAT and LOCALE\_DATE\_TIME\_FORMAT may contain any
     format groups other than _%c_ and _%Ec_.

   * LOCALE\_DATE\_FORMAT and LOCALE\_TIME\_FORMAT may not contain
     _%c_, _%Ec_, _%Ex_, or _%EX_.

   * DATE\_FORMAT and TIME\_FORMAT may not contain _%c_, _%Ec_,
     _%x_, _%Ex_, _%X_, or _%EX_.

   * TIME\_FORMAT\_12 and TIME\_FORMAT\_24 may not contain _%c_, _%Ec_,
     _%r_, _%R_, _%T_, _%x_, _%Ex_, _%X_, or _%EX_.

   * LOCALE\_YEAR\_FORMAT may not contain  _%c_, _%Ec_,
     _%r_, _%R_, _%T_, _%x_, _%Ex_, _%X_, _%EX_, or _%Ey_.

_Example._ The following file is "ja.msg", which localises the
[clock] command to a Japanese locale.

	namespace eval ::tcl::clock {
	    ::msgcat::mcset ja DAYS_OF_WEEK_ABBREV [list \
	        "\u65e5"\
	        "\u6708"\
	        "\u706b"\
	        "\u6c34"\
	        "\u6728"\
	        "\u91d1"\
	        "\u571f"]
	    ::msgcat::mcset ja DAYS_OF_WEEK_FULL [list \
	        "\u65e5\u66dc\u65e5"\
	        "\u6708\u66dc\u65e5"\
	        "\u706b\u66dc\u65e5"\
	        "\u6c34\u66dc\u65e5"\
	        "\u6728\u66dc\u65e5"\
	        "\u91d1\u66dc\u65e5"\
	        "\u571f\u66dc\u65e5"]
	    ::msgcat::mcset ja MONTHS_ABBREV [list \
	        "1"\
	        "2"\
	        "3"\
	        "4"\
	        "5"\
	        "6"\
	        "7"\
	        "8"\
	        "9"\
	        "10"\
	        "11"\
	        "12"\
	        ""]
	    ::msgcat::mcset ja MONTHS_FULL [list \
	        "1\u6708"\
	        "2\u6708"\
	        "3\u6708"\
	        "4\u6708"\
	        "5\u6708"\
	        "6\u6708"\
	        "7\u6708"\
	        "8\u6708"\
	        "9\u6708"\
	        "10\u6708"\
	        "11\u6708"\
	        "12\u6708"\
	        ""]
	    ::msgcat::mcset ja BCE "\u7d00\u5143\u524d"
	    ::msgcat::mcset ja CE "\u897f\u66a6"
	    ::msgcat::mcset ja AM "\u5348\u524d"
	    ::msgcat::mcset ja PM "\u5348\u5f8c"
	    ::msgcat::mcset ja DATE_FORMAT "%Y/%m/%d"
	    ::msgcat::mcset ja TIME_FORMAT "%k:%M:%S"
	    ::msgcat::mcset ja DATE_TIME_FORMAT "%Y/%m/%d %k:%M:%S %z"
	    ::msgcat::mcset ja LOCALE_NUMERALS "\u3007 \u4e00 \u4e8c \u4e09 \u56db
	       \u4e94 \u516d \u4e03 \u516b \u4e5d \u5341 \u5341\u4e00 \u5341\u4e8c
	       \u5341\u4e09 \u5341\u56db \u5341\u4e94 \u5341\u516d \u5341\u4e03 
	       \u5341\u516b \u5341\u4e5d \u4e8c\u5341 \u5eff\u4e00 \u5eff\u4e8c 
	       \u5eff\u4e09 \u5eff\u56db \u5eff\u4e94 \u5eff\u516d \u5eff\u4e03 
	       \u5eff\u516b \u5eff\u4e5d \u4e09\u5341 \u5345\u4e00 \u5345\u4e8c 
	       \u5345\u4e09 \u5345\u56db \u5345\u4e94 \u5345\u516d \u5345\u4e03 
	       \u5345\u516b \u5345\u4e5d \u56db\u5341 \u56db\u5341\u4e00 
	       \u56db\u5341\u4e8c \u56db\u5341\u4e09 \u56db\u5341\u56db 
	       \u56db\u5341\u4e94 \u56db\u5341\u516d \u56db\u5341\u4e03 
	       \u56db\u5341\u516b \u56db\u5341\u4e5d \u4e94\u5341 
	       \u4e94\u5341\u4e00 
	       \u4e94\u5341\u4e8c \u4e94\u5341\u4e09 \u4e94\u5341\u56db 
	       \u4e94\u5341\u4e94 \u4e94\u5341\u516d \u4e94\u5341\u4e03 
	       \u4e94\u5341\u516b \u4e94\u5341\u4e5d \u516d\u5341 
	       \u516d\u5341\u4e00 \u516d\u5341\u4e8c \u516d\u5341\u4e09 
	       \u516d\u5341\u56db \u516d\u5341\u4e94 \u516d\u5341\u516d 
	       \u516d\u5341\u4e03 \u516d\u5341\u516b \u516d\u5341\u4e5d
	       \u4e03\u5341 
	       \u4e03\u5341\u4e00 \u4e03\u5341\u4e8c \u4e03\u5341\u4e09 
	       \u4e03\u5341\u56db \u4e03\u5341\u4e94 \u4e03\u5341\u516d 
	       \u4e03\u5341\u4e03 \u4e03\u5341\u516b \u4e03\u5341\u4e5d
	       \u516b\u5341 
	       \u516b\u5341\u4e00 \u516b\u5341\u4e8c \u516b\u5341\u4e09 
	       \u516b\u5341\u56db \u516b\u5341\u4e94 \u516b\u5341\u516d 
	       \u516b\u5341\u4e03 \u516b\u5341\u516b \u516b\u5341\u4e5d 
	       \u4e5d\u5341 
	       \u4e5d\u5341\u4e00 \u4e5d\u5341\u4e8c \u4e5d\u5341\u4e09 
	       \u4e5d\u5341\u56db \u4e5d\u5341\u4e94 \u4e5d\u5341\u516d 
	       \u4e5d\u5341\u4e03 \u4e5d\u5341\u516b \u4e5d\u5341\u4e5d"
	    ::msgcat::mcset ja LOCALE_DATE_FORMAT "%EY\u5e74%B%Od\u65e5"
	    ::msgcat::mcset ja LOCALE_TIME_FORMAT "%OH\u6642%OM\u5206%OS\u79d2"
	    ::msgcat::mcset ja LOCALE_DATE_TIME_FORMAT \
	        "%A %EY\u5e74%B%Od\u65e5%OH\u6642%OM\u5206%OS\u79d2 %z"
	    ::msgcat::mcset ja LOCALE_ERAS "
	        {-9223372036854775808 \u897f\u66a6 0} 
	        {-3060979200 \u660e\u6cbb 1867} 
	        {-1812153600 \u5927\u6b63 1911} 
	        {-1357603200 \u662d\u548c 1925} 
	        {568512000 \u5e73\u6210 1987}"

	}

In addition to the standard locales, two special locales may appear on
the **-locale** parameter; **current**, which designates the result of
evaluating [mclocale], and **system**, which designates the current
"system" locale, which is determined by \(in order of preference\):

   * the date/time format settings on the Windows control panel

   * the environment variable LC\_TIME

   * the current locale from [mclocale].

## Build System

Several tools are provided for the use of maintainers:

 loadICU.tcl:
    Given a distribution of IBM's _icu4c_
    <http://oss.software.ibm.com/icu/index.html> ,
    this program analyzes the source code of the message catalogs and
    extracts appropriate Tcl-based messages for the date and time
    formats in the supported locales.

 loadtzif.tcl:
    Given a time zone information file used by the Olson version of
    'tzset' \(for a description, see the latest 'tzcode' file in
    [ftp://elsie.nci.nih.gov/pub/]\), creates the corresponding Tcl
    'tzdata' file.

 makeTestCases.tcl:
    Makes several thousand auto-generated test cases to exercise
    the time conversion algorithms.

 tclZIC.tcl:
    Given the source code for the Olson time zone descriptions
    \(obtainable as the latest 'tzdata' file in
    [ftp://elsie.nci.nih.gov/pub/]\), creates the full set of Tcl
    'tzdata' files.

Since these tools depend on third party source, they will not be
included in the usual build steps; instead, maintainers will be
expected to run them whenever changing files on which they depend.  It
will be a good practice to update the ICU and Olson files just before
cutting a release.

# Reference Implementation

The implementation of a refactored [clock] command is a work
in progress, and interested developers are urged to contact the
TIP author if they want to help with implementation, documentation,
or testing.  The code is available in the same SourceForge
repository as the Tcl core, and Tcl maintainers can obtain it
with

	  cvs -d:ext:[email protected]:/cvsroot/tcl co newclock

# Notes on the cost of implementation

Since it is well known that Tcl code is typically 30-50 times slower
than the equivalent C, it is to be expected that [clock scan],
[clock format], and [clock add]
will be in that performance range.  [clock seconds] and
[clock clicks] will still be C code and are not expected to
suffer a measurable change in performance.  \(If they do, the
implementors plan to address the issue.\)

The cost of the time zone data files and the message catalogs
is not trivial; they occupy about 1.6 megabytes exclusive of file
system fragmentation and may occupy multiple megabytes depending
on the minimum size of a file.  The implementors assume \(and are
working to ensure\) that some sort of compressed virtual file system
will be available as core functionality in the 8.5 final release.
With zlib compression, the message catalogs and time zone data total
less than half a megabyte.  It is worth noting that a distribution
that must run in the absolute minimum space may omit both message
catalogs and time zone data; if this is done, named time zones
\(e.g., :America/New\_York\) will not be available on systems such
as Windows that lack 'zoneinfo', and will suffer from Y2038
bugs on systems such as Solaris and Linux that have 'zoneinfo'.
Without the message catalogs, the only
supported locale will be the root locale \(and on Windows, the 'system' locale\).  This combination
provides functionality comparable to the [clock] command prior
to this TIP.  The Tcl code that implements [clock] is less than
eighty kilobytes with comments and blank lines removed; this
amount of overhead is thought to be negligible.

# Bugs

The reference implementation does not attempt any calendars not based
on the hybrid Julian/Gregorian calendar.  This implementation is
adequate for the Western countries and for the Japanese civil
calendar, but does not address the Hijri, Hebraic, Thai, Chinese or
Korean calendars. \(No Tcl user has requested these, to the best of the
knowledge of the author of this TIP.\)

The Gregorian change date is not supplied in most locales.

Localisation in most locales was done by an American who is probably
excessively ignorant in such matters.

This TIP makes no effort to be compliant with RFC 2550 
<http://www.faqs.org/rfcs/rfc2550.html> .

# Copyright

Copyright 2004, by Kevin B. Kenny.  Redistribution permitted under the
terms of the Open Publication License
<http://www.opencontent.org/openpub/> .

# Acknowledgments

The author of this TIP wishes to thank all the Tcl'ers who have
taken the time to read and comment on it, most notably Joe English,
Donal K. Fellows, Jeff Hobbs, Arjen Markus, Reinhard Max,
Christopher Nelson, Donald G. Porter,
Pascal Scheffers, and Peter da Silva.

Name change from tip/174.tip to tip/174.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

TIP:            174
Title:          Math Operators as Commands
Version:        $Revision: 1.21 $
Author:         Kristoffer Lawson <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         David S. Cargo <[email protected]>
Author:         Peter Spjuth <[email protected]>
Author:         Kevin B. Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        15-Mar-2004
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP describes a proposal for math operators in Tcl as separate commands,
acting much like the equivalent in the Lisp language. This would make simple
usage of mathematics much clearer.

~ Rationale

While the '''expr''' command works fairly well for longer mathematical
expressions, it is extremely tedious for the most common uses, such as
handling indices. Take the following examples:

| set newList [lrange $list [expr {$idx - 5}] [expr {$idx + 5}]]
| .c create oval [expr {$x - $r}] [expr {$y - $r}] [expr {$x + $r}] [expr {$y + $r}]

Many find this particular aspect of Tcl unappealing. It gets increasingly
difficult to read as more and more simple mathematical expressions build up.
(See ''Example'' below for how these will look after the proposed change.)

~ Proposed Change

 1. A group of Tcl commands are added which would handle mathematical
    operations without the need to use '''expr'''. Most commands would take a
    variable amount of arguments and would work such that the operator is
    applied to the combination of the first and second arguments. The result
    of this combination is then used with the operator for the third argument,
    etc. If only one argument is given, it is returned as is. See below for
    details for each operator. An example implementation of the '''+'''
    command in Tcl follows:

| proc ::tcl::mathop::+ {args} {
|     set r 0
|     foreach operand $args {
|         set r [expr {$r + $operand}]
|     }

|     return $r
| }


 2. All operator commands will be kept in the '''::tcl::mathop''' (in line
    with ''::tcl::mathfunc'' from [232]) namespace, from which they would most
    commonly be imported into the calling namespace (or resolved in it by
    means of the '''namespace path''' ([229]) command).

 3. The commands are not connected to their corresponding '''expr''' operator.
    Overloading or adding any command in '''::tcl::mathop''' does ''not''
    affect operators in '''expr''' or any other command that calls
    ''Tcl_ExprObj'', and nor does overriding '''expr''' alter the behaviour of
    any command in ''':::tcl::mathop'''.

~~ Operator Commands Details

Unary operators '''~''' and '''!''' always take one argument.

|Op/argc  0    1   2   3+
|~       err  ~a  err  err
|!       err  !a  err  err

Left-associative operators that naturally allow 0 or more arguments do so:

|Op/argc  0   1   2     3+
|+        0   a   a+b   a+b+c...
|*        1   a   a*b   a*b*c...
|&       -1   a   a&b   a&b&c...
|^        0   a   a^b   a^b^c...
||        0   a   a|b   a|b|c...

Other left or right associative operators. Operator '''**''' is right
associative, which needs to be noted clearly.

|Op/argc  0   1   2     3+
|**       1   a   a**b  a**(b**(c...))

(This behaviour depends on the eventual modification of the '''**''' operator
in [[expr]] to have right-associativity, which is the subject of [274]. If TIP
#274 fails, '''**''' should be left- or non-associative.)

Nonassociative operators (including the list operators, "'''in'''" and
"'''ni'''") must always be binary.

|Op/argc   0    1    2      3+
|<<       err  err  a<<b    err
|>>       err  err  a>>b    err
|%        err  err  a%b     err
|!=       err  err  a!=b    err
|ne       err  err  a ne b  err
|in       err  err  a in b  err
|ni       err  err  a ni b  err

Subtract and divide treat their arguments in a left-associative way ''except''
for in the unary case. Unary minus is negation, and unary divide is reciprocal.

|Op/argc  0    1      2    3-
|-       err  -a     a-b  ((a-b)-c)...
|/       err  1.0/a  a/b  ((a/b)/c)...

Comparison operators other than '''!=''' and '''ne''' test for ordering:

|Op/argc  0  1   2       3+
|<        1  1  a<b     ((a<b)&(b<c)&...)
|<=       1  1  a<=b    ((a<=b)&(b<=c)&...)
|>        1  1  a>b     ((a>b)&(b>c)&...)
|>=       1  1  a>=b    ((a>=b)&(b>=c)&...)
|==       1  1  a==b    ((a==b)&(b==c)&...)
|eq       1  1  a eq b  ((a eq b)&(b eq c)&...)

(Note the single '''&'''; a Tcl command is not capable of "short circuit"
evaluation of its arguments.)

The operators that do conditional evaluation of their arguments (&&, || and
?:) are not included. This is because their characteristic evaluation laziness
is best modelled using the existing '''if''' command.

~~ Example

As an example use, let us change the lines from above:

| set newList [lrange $list [- $idx 5] [+ $idx 5]]
| .c create oval [- $x $r] [- $y $r] [+ $x $r] [+ $y $r]

This is clearly shorter and much easier on the eyes. There is no need to
consider the effects of bracing expressions.

Sum of a list becomes

| set sum [+ {expand}$list]

~ Security considerations

It is worth noting that variadic operators have no way of "short circuit"
evaluation, much as putative '''&&''' and '''||''' commands would not. This
consideration means that they must be used with caution in cases where
expressions have side effects; all their arguments will be evaluated.
Commands like

|   < 1 0 [don't do this!]
|   / 0 0 [don't do this!]

will indeed evaluate the string in square brackets.

If expressions like these are constructed from user input, care must be taken
to place them in a safe execution environment or otherwise defend against code
injection attacks. (This last consideration is somewhat far-fetched, since it
is implausible that an injection attack would be able to generate [[< 1 0
[[don't do this!]]]] but not [[< [[don't do this!]] 0]].)

~ Implementation

~~ Efficiency

These commands can naturally be compiled and thus as efficient as their
corresponding '''expr''' operators. The following lines should probably result
in the same byte codes.

|set x [expr {$a * $b + $c}]
|set x [+ [* $a $b] $c]

~~ Reference Implementation

Available online at SourceForge
[http://sf.net/tracker/?func=detail&aid=1578137&group_id=10894&atid=310894].
The patch is for this TIP as it stood several versions ago; in particular, it
does not implement the ordering comparators and gets associativity wrong in a
couple of other cases. Nevertheless, the authors of this TIP believe it to be
an adequate proof that the ideas of the TIP are implementable with good
performance.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
>

|





|

|



|
|



|

|


|




|


|
|
|
|
<
>
|
<
|
>
|
|
|
|

|
|
|
|
|

|

|

|
|
|



|
|
|
|
|
|

|


|
|

|
|
|

|
|

|
|
|
|
|
|
|
|

|


|
|
|

|

|
|
|
|
|
|
|

|
|

|
|
|

|



|
|






|

|


|




|
|





|
|
|

|

|


|


|
|

|


|






|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

# TIP 174: Math Operators as Commands

	Author:         Kristoffer Lawson <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         David S. Cargo <[email protected]>
	Author:         Peter Spjuth <[email protected]>
	Author:         Kevin B. Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        15-Mar-2004
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP describes a proposal for math operators in Tcl as separate commands,
acting much like the equivalent in the Lisp language. This would make simple
usage of mathematics much clearer.

# Rationale

While the **expr** command works fairly well for longer mathematical
expressions, it is extremely tedious for the most common uses, such as
handling indices. Take the following examples:

	 set newList [lrange $list [expr {$idx - 5}] [expr {$idx + 5}]]
	 .c create oval [expr {$x - $r}] [expr {$y - $r}] [expr {$x + $r}] [expr {$y + $r}]

Many find this particular aspect of Tcl unappealing. It gets increasingly
difficult to read as more and more simple mathematical expressions build up.
\(See _Example_ below for how these will look after the proposed change.\)

# Proposed Change

 1. A group of Tcl commands are added which would handle mathematical
    operations without the need to use **expr**. Most commands would take a
    variable amount of arguments and would work such that the operator is
    applied to the combination of the first and second arguments. The result
    of this combination is then used with the operator for the third argument,
    etc. If only one argument is given, it is returned as is. See below for
    details for each operator. An example implementation of the **\+**
    command in Tcl follows:

		 proc ::tcl::mathop::+ {args} {
		     set r 0
		     foreach operand $args {
		         set r [expr {$r + $operand}]

		     }
		     return $r

		 }

 2. All operator commands will be kept in the **::tcl::mathop** \(in line
    with _::tcl::mathfunc_ from [[232]](232.md)\) namespace, from which they would most
    commonly be imported into the calling namespace \(or resolved in it by
    means of the **namespace path** \([[229]](229.md)\) command\).

 3. The commands are not connected to their corresponding **expr** operator.
    Overloading or adding any command in **::tcl::mathop** does _not_
    affect operators in **expr** or any other command that calls
    _Tcl\_ExprObj_, and nor does overriding **expr** alter the behaviour of
    any command in **:::tcl::mathop**.

## Operator Commands Details

Unary operators **~** and **!** always take one argument.

	Op/argc  0    1   2   3+
	~       err  ~a  err  err
	!       err  !a  err  err

Left-associative operators that naturally allow 0 or more arguments do so:

	Op/argc  0   1   2     3+
	+        0   a   a+b   a+b+c...
	*        1   a   a*b   a*b*c...
	&       -1   a   a&b   a&b&c...
	^        0   a   a^b   a^b^c...
	|        0   a   a|b   a|b|c...

Other left or right associative operators. Operator **\*\*** is right
associative, which needs to be noted clearly.

	Op/argc  0   1   2     3+
	**       1   a   a**b  a**(b**(c...))

\(This behaviour depends on the eventual modification of the **\*\*** operator
in [expr] to have right-associativity, which is the subject of [[274]](274.md). If TIP
\#274 fails, **\*\*** should be left- or non-associative.\)

Nonassociative operators \(including the list operators, "**in**" and
"**ni**"\) must always be binary.

	Op/argc   0    1    2      3+
	<<       err  err  a<<b    err
	>>       err  err  a>>b    err
	%        err  err  a%b     err
	!=       err  err  a!=b    err
	ne       err  err  a ne b  err
	in       err  err  a in b  err
	ni       err  err  a ni b  err

Subtract and divide treat their arguments in a left-associative way _except_
for in the unary case. Unary minus is negation, and unary divide is reciprocal.

	Op/argc  0    1      2    3-
	-       err  -a     a-b  ((a-b)-c)...
	/       err  1.0/a  a/b  ((a/b)/c)...

Comparison operators other than **!=** and **ne** test for ordering:

	Op/argc  0  1   2       3+
	<        1  1  a<b     ((a<b)&(b<c)&...)
	<=       1  1  a<=b    ((a<=b)&(b<=c)&...)
	>        1  1  a>b     ((a>b)&(b>c)&...)
	>=       1  1  a>=b    ((a>=b)&(b>=c)&...)
	==       1  1  a==b    ((a==b)&(b==c)&...)
	eq       1  1  a eq b  ((a eq b)&(b eq c)&...)

\(Note the single **&**; a Tcl command is not capable of "short circuit"
evaluation of its arguments.\)

The operators that do conditional evaluation of their arguments \(&&, \|\| and
?:\) are not included. This is because their characteristic evaluation laziness
is best modelled using the existing **if** command.

## Example

As an example use, let us change the lines from above:

	 set newList [lrange $list [- $idx 5] [+ $idx 5]]
	 .c create oval [- $x $r] [- $y $r] [+ $x $r] [+ $y $r]

This is clearly shorter and much easier on the eyes. There is no need to
consider the effects of bracing expressions.

Sum of a list becomes

	 set sum [+ {expand}$list]

# Security considerations

It is worth noting that variadic operators have no way of "short circuit"
evaluation, much as putative **&&** and **\|\|** commands would not. This
consideration means that they must be used with caution in cases where
expressions have side effects; all their arguments will be evaluated.
Commands like

	   < 1 0 [don't do this!]
	   / 0 0 [don't do this!]

will indeed evaluate the string in square brackets.

If expressions like these are constructed from user input, care must be taken
to place them in a safe execution environment or otherwise defend against code
injection attacks. \(This last consideration is somewhat far-fetched, since it
is implausible that an injection attack would be able to generate [< 1 0
[don't do this!]] but not [< [don't do this!] 0].\)

# Implementation

## Efficiency

These commands can naturally be compiled and thus as efficient as their
corresponding **expr** operators. The following lines should probably result
in the same byte codes.

	set x [expr {$a * $b + $c}]
	set x [+ [* $a $b] $c]

## Reference Implementation

Available online at SourceForge
<http://sf.net/tracker/?func=detail&aid=1578137&group_id=10894&atid=310894> .
The patch is for this TIP as it stood several versions ago; in particular, it
does not implement the ordering comparators and gets associativity wrong in a
couple of other cases. Nevertheless, the authors of this TIP believe it to be
an adequate proof that the ideas of the TIP are implementable with good
performance.

# Copyright

This document has been placed in the public domain.

Name change from tip/175.tip to tip/175.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

TIP:            175
Title:          Add an -async Option to [open]
Version:        $Revision: 1.9 $
Author:         Neil Madden <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        15-Mar-2004
Post-History:   
Tcl-Version:    9.0


~ Abstract

This TIP propose to add an ''-async'' option to the [[open]] command,
with identical semantics to the ''-async'' option to the [[socket]]
command.

~ Rationale

With the introduction of Virtual File Systems (VFS, see [17]), it is
now possible to use [[open]] to access resources which are not
available in the local file system.  However, initial access to these
resources may take some time (for instance, in an HTTP VFS, this
requires an HTTP GET request to a remote server).  Currently, while
this request is being processed, the Tcl application will block
waiting for a response.  It may take several seconds before the open
call returns, and control is passed back to the application.  Delays
of this length can cause problems, especially in applications with a
Tk graphical user interface, which will not repond to events until the
call has completed.  Tcl provides mechanisms to avoid this initial
blocking for the socket command, and in the HTTP package.  However,
this functionality is missing from the open command.  For VFS to
become useful for writing network code, this functionality needs to be
added.

~ Proposed Change

This TIP proposes adding an ''-async'' option to the open command.
The new syntax for the open command would be:

| open ?-async? ?--? name ?access? ?permissions?

The "--" marker is also proposed to signify "end of options".  This is
needed as ''name'' can be anything, including the string "-async", and
so some mechanism is needed to distinguish between the ''-async''
option, and the name.  This is in line with other commands which take
multiple options.

When the ''-async'' option is present, the open command will return
immediately, without waiting for the underlying channel to be created
and connected.  If the channel is configured for blocking mode, a
''gets'' or ''flush'' that is done on the channel before the
connection is made will wait until the connection is completed, or
fails.  If the channel is configured for nonblocking mode, then a
''gets'' or ''flush'' on the channel before the connection has been
made will return immediately and ''fblocked'' on the channel will
return 1.  This is exactly the same behaviour of the current
implementation of the ''-async'' option to the ''socket'' command.

In addition, each VFS should support the ''-error'' option to ''fconfigure'' to allow scripts to determine the cause of an error when asynchronous opening fails. Furthermore, there needs to be a mechanism for notifying a script when an asynchronous open fails. This could be achieved by firing any fileevents (readable or writeable) which are registered on the resulting channel. This is the behaviour of [[socket -async]].

In order for this TIP to be implemented, there would have to be
changes to the VFS layer in Tcl.  There are at three ways to accomplish this:

 1. Extend Tcl_FSOpenFileChannelProc to accept an ''async'' argument, of type ''int''.

 2. Extend the Tcl_Filesystem structure to add a new callback, alongside T_FSOFCP. For instance, Tcl_FSOpenFileChannelAsyncProc.

 3. (Ab)use the ''mode'' parameter, and add a mask such as TCL_ASYNC.

Of these, option 3 is the easiest in terms of maintaining compatibility, but is not the nicest implementation.

~ Reference Implementation

A reference implementation does ''not'' yet exist.  The TIP author
would be willing to implement any changes needed, but currently is not
familiar with the internal workings of the VFS system.

~ Questions

Should the ''-async'' option be supported when a command pipeline is
being created?

Should a more general option passing mechanism be implemented?  It is
possible that some VFS implementations may require more information
than is currently available in order to correctly create a channel
(the ''-myaddr'' and ''-myport'' options to socket spring to mind).
Would it be more sensible to consider a proposal for a more general
option passing mechanism, to avoid further updates to the API in the
future? This TIP does ''not'' propose such a mechanism.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|


|

|
|

|
|











|

|


|


|
|



|


|


|
|

|

|




|

|

|



|

|



|

|





|


|

|


>

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

# TIP 175: Add an -async Option to [open]

	Author:         Neil Madden <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        15-Mar-2004
	Post-History:   
	Tcl-Version:    9.0
-----

# Abstract

This TIP propose to add an _-async_ option to the [open] command,
with identical semantics to the _-async_ option to the [socket]
command.

# Rationale

With the introduction of Virtual File Systems \(VFS, see [[17]](17.md)\), it is
now possible to use [open] to access resources which are not
available in the local file system.  However, initial access to these
resources may take some time \(for instance, in an HTTP VFS, this
requires an HTTP GET request to a remote server\).  Currently, while
this request is being processed, the Tcl application will block
waiting for a response.  It may take several seconds before the open
call returns, and control is passed back to the application.  Delays
of this length can cause problems, especially in applications with a
Tk graphical user interface, which will not repond to events until the
call has completed.  Tcl provides mechanisms to avoid this initial
blocking for the socket command, and in the HTTP package.  However,
this functionality is missing from the open command.  For VFS to
become useful for writing network code, this functionality needs to be
added.

# Proposed Change

This TIP proposes adding an _-async_ option to the open command.
The new syntax for the open command would be:

	 open ?-async? ?--? name ?access? ?permissions?

The "--" marker is also proposed to signify "end of options".  This is
needed as _name_ can be anything, including the string "-async", and
so some mechanism is needed to distinguish between the _-async_
option, and the name.  This is in line with other commands which take
multiple options.

When the _-async_ option is present, the open command will return
immediately, without waiting for the underlying channel to be created
and connected.  If the channel is configured for blocking mode, a
_gets_ or _flush_ that is done on the channel before the
connection is made will wait until the connection is completed, or
fails.  If the channel is configured for nonblocking mode, then a
_gets_ or _flush_ on the channel before the connection has been
made will return immediately and _fblocked_ on the channel will
return 1.  This is exactly the same behaviour of the current
implementation of the _-async_ option to the _socket_ command.

In addition, each VFS should support the _-error_ option to _fconfigure_ to allow scripts to determine the cause of an error when asynchronous opening fails. Furthermore, there needs to be a mechanism for notifying a script when an asynchronous open fails. This could be achieved by firing any fileevents \(readable or writeable\) which are registered on the resulting channel. This is the behaviour of [socket -async].

In order for this TIP to be implemented, there would have to be
changes to the VFS layer in Tcl.  There are at three ways to accomplish this:

 1. Extend Tcl\_FSOpenFileChannelProc to accept an _async_ argument, of type _int_.

 2. Extend the Tcl\_Filesystem structure to add a new callback, alongside T\_FSOFCP. For instance, Tcl\_FSOpenFileChannelAsyncProc.

 3. \(Ab\)use the _mode_ parameter, and add a mask such as TCL\_ASYNC.

Of these, option 3 is the easiest in terms of maintaining compatibility, but is not the nicest implementation.

# Reference Implementation

A reference implementation does _not_ yet exist.  The TIP author
would be willing to implement any changes needed, but currently is not
familiar with the internal workings of the VFS system.

# Questions

Should the _-async_ option be supported when a command pipeline is
being created?

Should a more general option passing mechanism be implemented?  It is
possible that some VFS implementations may require more information
than is currently available in order to correctly create a channel
\(the _-myaddr_ and _-myport_ options to socket spring to mind\).
Would it be more sensible to consider a proposal for a more general
option passing mechanism, to avoid further updates to the API in the
future? This TIP does _not_ propose such a mechanism.

# Copyright

This document has been placed in the public domain.

Name change from tip/176.tip to tip/176.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

TIP:            176
Title:          Add String Index Values
Version:        $Revision: 1.8 $
Author:         Damon Courtney <[email protected]>
Author:         Don Porter <[email protected]>
Author:         Damon Courtney <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        16-Mar-2004
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes extended index formats to be recognized by
'''TclGetIntForIndex''', supporting simple index arithmetic
for string and list indices.

~Rationale

Most of Tcl's commands that accept an integer index of some kind also
accept a string index in the format of ''end-N''.  This is an
extremely useful feature which I hope to extend just slightly by
allowing simple addition to the standard index forms to be done during
index processing.  The change is mostly just syntactic sugar, but it
extends a functionality that is already there and does not change any
other syntax.

The aim of the proposal is to allow shorthand list and string
operations like so:

|set x [lsearch $list $elem]
|set new [lrange $list $x-1 $x+1]
|
|set x [string first $string "foo"]
|set new [string range $string $x $x+5]

~Proposal

The description of the supported index formats documented for
the '''string index''' command will be updated to read:

   * ''integer''

   >   * For any index value that passes '''string is integer -strict''',
         the char specified at this integral index (e.g. '''2''' would
         refer to the '''c''' in '''abcd''').

   * end

   >   * The last char of the string (e.g.  '''end''' would refer to
         the '''d''' in '''abcd''').

   * end-''N''

   >   * The last char of the string minus the specified integer
         offset ''N'' (e.g. '''end-1''' would refer to the '''c'''
         in '''abcd''').

   * end+''N''

   >   * The last char of the string plus the specified integer
         offset ''N'' (e.g. '''end+-1''' would refer to the '''c'''
         in '''abcd''').

   * ''M''+''N''

   >   * The char specified at the integral index that is the sum of
         integer values ''M'' and ''N'' (e.g.  '''1+1''' would refer
         to the '''c''' in '''abcd''').

   * ''M''-''N''

   >   * The char specified at the integral index that is the difference
         of integer values ''M'' and ''N'' (e.g. '''2-1''' would refer to
         the '''b''' in '''abcd''').

   * In the specifications above, the integer value ''M'' contains no
     trailing whitespace and the integer value ''N'' contains no
     leading whitespace.

The internal routine '''TclGetIntForIndex''' will be updated to
implement the parsing specified by the documentation above.

The documentation of all Tcl commands that call '''TclGetIntForIndex'''
to parse index values will be updated to refer to the documentation
for '''string index''' for a description of the index format. 
These commands include '''lindex''', '''linsert''', '''lrange''',
'''lreplace''', '''lsearch''', '''lset''', '''lsort''', and
'''string'''.  This
documentation update will remove any mention that the index values
'''e''' and '''en''' are supported (as prefixes of '''end''').  Their
support will be continued for compatibility, but that support will
now be undocumented and deprecated.

The implementation of the commands '''regexp -start''' and
'''regsub -start''' will be updated to call '''TclGetIntForIndex'''
so that the full set of index formats will be supported.  (Currently
only integer values are accepted).

The error message produced by '''TclGetIntForIndex''' when parsing
an invalid index will be updated to give the advice
'''must be integer?[+-]integer? or end?[+-]integer?''',
in agreement with the extended set of index formats.

~Implementation

Tcl Patch 1165695 is a draft implementation.  It accomplishes everything
proposed above except the update to the error message.  If this proposal
is accepted, that change, plus the large number of test suite updates
it would require, will be added.  Tests of the new functionality are
also still to come.

~Compatibility

Support for the index format end-''N'' where ''N'' is an integer
with leading whitespace is removed by this proposal.  For example
the string '''end- 1''' will no longer be recognized as a valid index.
Most programmers are surprised to learn that this format is supported
currently, so this incompatibility is not expected to cause much
of a problem.

~Discussion Summary

This feature is added as a quick, simple convenience to having to always use a full-blown expression for a minor task.

It was briefly discussed that since indexes already allowed a space between the - and the N we should continue to support this, but it makes the implementation harder, and no one seemed to care that much.  The fact that it breaks backwards compatibility is a small issue since no one seems to use indexes in this manner anyway.

The idea of making indexes extend a list beyond its length by doing something like [linsert $list end+10 $elem] was discussed but tabled since it is much harder to implement and is really outside the scope of this TIP.  This may be something to discuss for a future TIP though.

~Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|


|


|


|









|
|
|
|
|

|


|

|

|
|
|



|
|

|

|
|
|

|

|
|
|

|

|
|
|

|

|
|
|

|
|


|


|

|
|
|
|

|



|
|
|
|

|

|


|







|

|

|




|







|


>

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

# TIP 176: Add String Index Values

	Author:         Damon Courtney <[email protected]>
	Author:         Don Porter <[email protected]>
	Author:         Damon Courtney <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        16-Mar-2004
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes extended index formats to be recognized by
**TclGetIntForIndex**, supporting simple index arithmetic
for string and list indices.

# Rationale

Most of Tcl's commands that accept an integer index of some kind also
accept a string index in the format of _end-N_.  This is an
extremely useful feature which I hope to extend just slightly by
allowing simple addition to the standard index forms to be done during
index processing.  The change is mostly just syntactic sugar, but it
extends a functionality that is already there and does not change any
other syntax.

The aim of the proposal is to allow shorthand list and string
operations like so:

	set x [lsearch $list $elem]
	set new [lrange $list $x-1 $x+1]
	
	set x [string first $string "foo"]
	set new [string range $string $x $x+5]

# Proposal

The description of the supported index formats documented for
the **string index** command will be updated to read:

   * _integer_

	   >   \* For any index value that passes **string is integer -strict**,
         the char specified at this integral index \(e.g. **2** would
         refer to the **c** in **abcd**\).

   * end

	   >   \* The last char of the string \(e.g.  **end** would refer to
         the **d** in **abcd**\).

   * end-_N_

	   >   \* The last char of the string minus the specified integer
         offset _N_ \(e.g. **end-1** would refer to the **c**
         in **abcd**\).

   * end\+_N_

	   >   \* The last char of the string plus the specified integer
         offset _N_ \(e.g. **end\+-1** would refer to the **c**
         in **abcd**\).

   * _M_\+_N_

	   >   \* The char specified at the integral index that is the sum of
         integer values _M_ and _N_ \(e.g.  **1\+1** would refer
         to the **c** in **abcd**\).

   * _M_-_N_

	   >   \* The char specified at the integral index that is the difference
         of integer values _M_ and _N_ \(e.g. **2-1** would refer to
         the **b** in **abcd**\).

   * In the specifications above, the integer value _M_ contains no
     trailing whitespace and the integer value _N_ contains no
     leading whitespace.

The internal routine **TclGetIntForIndex** will be updated to
implement the parsing specified by the documentation above.

The documentation of all Tcl commands that call **TclGetIntForIndex**
to parse index values will be updated to refer to the documentation
for **string index** for a description of the index format. 
These commands include **lindex**, **linsert**, **lrange**,
**lreplace**, **lsearch**, **lset**, **lsort**, and
**string**.  This
documentation update will remove any mention that the index values
**e** and **en** are supported \(as prefixes of **end**\).  Their
support will be continued for compatibility, but that support will
now be undocumented and deprecated.

The implementation of the commands **regexp -start** and
**regsub -start** will be updated to call **TclGetIntForIndex**
so that the full set of index formats will be supported.  \(Currently
only integer values are accepted\).

The error message produced by **TclGetIntForIndex** when parsing
an invalid index will be updated to give the advice
**must be integer?[+-]integer? or end?[+-]integer?**,
in agreement with the extended set of index formats.

# Implementation

Tcl Patch 1165695 is a draft implementation.  It accomplishes everything
proposed above except the update to the error message.  If this proposal
is accepted, that change, plus the large number of test suite updates
it would require, will be added.  Tests of the new functionality are
also still to come.

# Compatibility

Support for the index format end-_N_ where _N_ is an integer
with leading whitespace is removed by this proposal.  For example
the string **end- 1** will no longer be recognized as a valid index.
Most programmers are surprised to learn that this format is supported
currently, so this incompatibility is not expected to cause much
of a problem.

# Discussion Summary

This feature is added as a quick, simple convenience to having to always use a full-blown expression for a minor task.

It was briefly discussed that since indexes already allowed a space between the - and the N we should continue to support this, but it makes the implementation harder, and no one seemed to care that much.  The fact that it breaks backwards compatibility is a small issue since no one seems to use indexes in this manner anyway.

The idea of making indexes extend a list beyond its length by doing something like [linsert $list end+10 $elem] was discussed but tabled since it is much harder to implement and is really outside the scope of this TIP.  This may be something to discuss for a future TIP though.

# Copyright

This document has been placed in the public domain.

Name change from tip/177.tip to tip/177.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

TIP:		177
Title:		Add -stretch Option to panedwindow Widget
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Post-History:	
Version:	$Revision: 1.5 $
Author:		Brian Griffin <[email protected]>
Created:	17-Mar-2004
Keywords:	Tk


~ Abstract

This TIP proposes adding a '''paneconfigure''' option to
'''panedwindow'''s that will allow alternative fill behavior.

~ Rationale

The current behavior, although reasonable, is too limiting.  We should
give control to programmers so that they can specify the fill behavior
in a way that makes sense for their application.

~ Proposed Change

Currently, the '''panedwindow''' widget gives any remaining space (or
takes away space) from the last (right most or bottom most) pane only.
This proposal will add a per pane configure option so that any or all
panes may receive the additional space.

A '''-stretch''' option will be added to the paneconfigure list of
options.  The value will be an enumeration of "'''last'''",
"'''first'''", "'''middle'''", "'''always'''", and "'''never'''".  The
default value will be "'''last'''" which maintains the
'''panedwindow''''s current behavior.  The '''panedwindow''' will
calculate the required size of all its panes.  Any remaining (or
deficit) space will be distributed to those panes marked for
stretching.  The space will be distributed based on each panes current
ratio of the whole.  For example, given panes ''a'', ''b'', and ''c'',
where only ''b'' and ''c'' are marked for stretching and ''b'' is 25%
of the size of (''b''+''c''), then ''b'' will receive 25% of the
surplus or deficit space.

The '''-stretch''' enumeration values have the following meaning:

 last: Only if this pane is the last (right-most or bottom-most,
   depending on overall orientation) pane will it stretch.

 first: Only if this pane is the first (left-most or top-most,
   depending on overall orientation) pane will it be stretch.

 middle: Only if this pane is ''not'' the first or last pane will it
   stretch.

 always: This pane will always stretch.

 never: This pane will never stretch.

~ Draft Implmentation

An implementation of this enhancement is availble
[ftp://ftp.model.com/pub/tcl/pw_stretch_TIP.tgz].

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|

|
|

|





|

|
|



|
|
|
|
|
|
|

|
|
|


|

|
|

|
|

|






|




|


>

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

# TIP 177: Add -stretch Option to panedwindow Widget
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Post-History:	

	Author:		Brian Griffin <[email protected]>
	Created:	17-Mar-2004
	Keywords:	Tk
-----

# Abstract

This TIP proposes adding a **paneconfigure** option to
**panedwindow**s that will allow alternative fill behavior.

# Rationale

The current behavior, although reasonable, is too limiting.  We should
give control to programmers so that they can specify the fill behavior
in a way that makes sense for their application.

# Proposed Change

Currently, the **panedwindow** widget gives any remaining space \(or
takes away space\) from the last \(right most or bottom most\) pane only.
This proposal will add a per pane configure option so that any or all
panes may receive the additional space.

A **-stretch** option will be added to the paneconfigure list of
options.  The value will be an enumeration of "**last**",
"**first**", "**middle**", "**always**", and "**never**".  The
default value will be "**last**" which maintains the
**panedwindow**'s current behavior.  The **panedwindow** will
calculate the required size of all its panes.  Any remaining \(or
deficit\) space will be distributed to those panes marked for
stretching.  The space will be distributed based on each panes current
ratio of the whole.  For example, given panes _a_, _b_, and _c_,
where only _b_ and _c_ are marked for stretching and _b_ is 25%
of the size of \(_b_\+_c_\), then _b_ will receive 25% of the
surplus or deficit space.

The **-stretch** enumeration values have the following meaning:

 last: Only if this pane is the last \(right-most or bottom-most,
   depending on overall orientation\) pane will it stretch.

 first: Only if this pane is the first \(left-most or top-most,
   depending on overall orientation\) pane will it be stretch.

 middle: Only if this pane is _not_ the first or last pane will it
   stretch.

 always: This pane will always stretch.

 never: This pane will never stretch.

# Draft Implmentation

An implementation of this enhancement is availble
[ftp://ftp.model.com/pub/tcl/pw_stretch_TIP.tgz].

# Copyright

This document has been placed in the public domain.

Name change from tip/178.tip to tip/178.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

TIP:            178
Title:          [info pid] and [info tid] Subcommands
Version:        $Revision: 1.9 $
Author:         Joe Mistachkin <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        21-Mar-2004
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes two new '''info''' subcommands which are used to
obtain the current process and thread identifiers.

~ Rationale

In certain types of applications, it is important to know what thread
is currently executing.  This is especially true for multithreaded
applications or for scripts running in a threaded build of Tcl.

While the author realizes that there is already a '''pid''' command, the
addition of the '''info pid''' subcommand still makes sense for the
following reasons:

 * The '''pid''' command can also provide information totally unrelated
   to the ''current'' process identifier.  At one point ([88]) it was
   even suggested that the '''pid''' command be overloaded to provide
   process control related functionality.

 * To allow scripts that dynamically build other scripts (potentially
   for use with safe interpreters) using the '''info''' command and
   caller provided arguments.  Using the '''info''' command instead of
   the '''pid''' command limits the amount of information that can be
   obtained by the safe interpreter.

 * It is the opinion of the author that ''informational'' commands,
   such as '''pid''' should really be subcommands of '''info''' as we 
   start to move forward with the development of Tcl.

~ Justification

The '''info tid''' command should be in the core because the identity of
the currently executing thread is just as fundamental on all modern
operating systems as the current process identity.  Once the thread
identity is known, it can be used to communicate with other processes
and threads in useful ways that do not require the Thread package.
Loading the entire Thread package just to get the identity of the
currently executing thread is overkill and may not be a good solution
in application embedding scenarios.  This is especially true for the browser plugin where loading extra packages is not ideal.

~ Proposed Change

Two new subcommands, '''info pid''' and '''info tid''', would be added to
the '''info''' command with the following syntax:

 > '''info pid'''

This subcommand would return the process identifier for the current
process.

 > '''info tid'''

This subcommand would return the thread identifier for the current
thread.

~ Draft Implmentation

A complete implementation of this TIP is available
[http://sf.net/tracker/?func=detail&aid=920731&group_id=10894&atid=310894].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|


|





|
|


|
|
|


|
|
|
|


|
|


|

|








|

|
|

|




|




|


|

|


>

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

# TIP 178: [info pid] and [info tid] Subcommands

	Author:         Joe Mistachkin <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        21-Mar-2004
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes two new **info** subcommands which are used to
obtain the current process and thread identifiers.

# Rationale

In certain types of applications, it is important to know what thread
is currently executing.  This is especially true for multithreaded
applications or for scripts running in a threaded build of Tcl.

While the author realizes that there is already a **pid** command, the
addition of the **info pid** subcommand still makes sense for the
following reasons:

 * The **pid** command can also provide information totally unrelated
   to the _current_ process identifier.  At one point \([[88]](88.md)\) it was
   even suggested that the **pid** command be overloaded to provide
   process control related functionality.

 * To allow scripts that dynamically build other scripts \(potentially
   for use with safe interpreters\) using the **info** command and
   caller provided arguments.  Using the **info** command instead of
   the **pid** command limits the amount of information that can be
   obtained by the safe interpreter.

 * It is the opinion of the author that _informational_ commands,
   such as **pid** should really be subcommands of **info** as we 
   start to move forward with the development of Tcl.

# Justification

The **info tid** command should be in the core because the identity of
the currently executing thread is just as fundamental on all modern
operating systems as the current process identity.  Once the thread
identity is known, it can be used to communicate with other processes
and threads in useful ways that do not require the Thread package.
Loading the entire Thread package just to get the identity of the
currently executing thread is overkill and may not be a good solution
in application embedding scenarios.  This is especially true for the browser plugin where loading extra packages is not ideal.

# Proposed Change

Two new subcommands, **info pid** and **info tid**, would be added to
the **info** command with the following syntax:

 > **info pid**

This subcommand would return the process identifier for the current
process.

 > **info tid**

This subcommand would return the thread identifier for the current
thread.

# Draft Implmentation

A complete implementation of this TIP is available
<http://sf.net/tracker/?func=detail&aid=920731&group_id=10894&atid=310894> .

# Copyright

This document has been placed in the public domain.

Name change from tip/179.tip to tip/179.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

TIP:		179
Title:		Add -hide Option to panedwindow Widget
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Post-History:	
Version:	$Revision: 1.5 $
Author:		Brian Griffin <[email protected]>
Created:	22-Mar-2004
Keywords:	Tk


~ Abstract

This TIP proposes adding a '''paneconfigure''' option to
'''panedwindow'''s that will control pane visibility.

~ Rationale

Adding control over individual pane visibility to the '''panedwindow'''
widget would simplify the construction and control of complex user
interfaces.  For example, look at applications such as Komodo, or MS
Visual Studio, where the U/I contains 4-7 panes in 2 or more nested
panedwindows.  Both of these applications as well as many others allow
user controlled visibility of individual panes.  Trying to manage the
visibility and placement of these panes requires much additional code
and adds complexity to the U/I implementation.  Alternatively, if the
panedwindow allowed control of visibility while maintaining pane
position and configure options (as does the '''grid remove''' method),
the U/I code is essentially reduced to a simple one line [[''$w''
'''configure -hide''']].

~ Proposed Change

This TIP will add a '''-hide''' option to the '''paneconfigure''' for
individual panes.  The option will control the visibility of the pane.
When set to true (as interpreted by ''Tcl_GetBooleanFromObj()''), the
pane will be unmapped and will not be considered when arranging the
remaining panes for display.  Hidden panes will still be reported by
the [[''$w'' '''panes''']] method and can be referenced when adding panes with
the '''-after''' or '''-before''' options.

The advantage of a '''paneconfigure''' option over the '''remove'''
method of the '''grid''' command is that the pane is still query-able
and configurable.

~ Draft Implementation

An implementation of this enhancement is available
[ftp://ftp.model.com/pub/tcl/pw_hide_TIP.tgz].

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|

|
|

|

|








|
|
|

|

|

|


|
|

|
|


|




|


>

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

# TIP 179: Add -hide Option to panedwindow Widget
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Post-History:	

	Author:		Brian Griffin <[email protected]>
	Created:	22-Mar-2004
	Keywords:	Tk
-----

# Abstract

This TIP proposes adding a **paneconfigure** option to
**panedwindow**s that will control pane visibility.

# Rationale

Adding control over individual pane visibility to the **panedwindow**
widget would simplify the construction and control of complex user
interfaces.  For example, look at applications such as Komodo, or MS
Visual Studio, where the U/I contains 4-7 panes in 2 or more nested
panedwindows.  Both of these applications as well as many others allow
user controlled visibility of individual panes.  Trying to manage the
visibility and placement of these panes requires much additional code
and adds complexity to the U/I implementation.  Alternatively, if the
panedwindow allowed control of visibility while maintaining pane
position and configure options \(as does the **grid remove** method\),
the U/I code is essentially reduced to a simple one line [_$w_
**configure -hide**].

# Proposed Change

This TIP will add a **-hide** option to the **paneconfigure** for
individual panes.  The option will control the visibility of the pane.
When set to true \(as interpreted by _Tcl\_GetBooleanFromObj\(\)_\), the
pane will be unmapped and will not be considered when arranging the
remaining panes for display.  Hidden panes will still be reported by
the [_$w_ **panes**] method and can be referenced when adding panes with
the **-after** or **-before** options.

The advantage of a **paneconfigure** option over the **remove**
method of the **grid** command is that the pane is still query-able
and configurable.

# Draft Implementation

An implementation of this enhancement is available
[ftp://ftp.model.com/pub/tcl/pw_hide_TIP.tgz].

# Copyright

This document has been placed in the public domain.

Name change from tip/18.tip to tip/18.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
TIP:            18
Title:          Add Labels to Frames
Version:        $Revision: 2.3 $
Author:         Peter Spjuth <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        12-Dec-2000
Post-History:   
Tcl-Version:    8.4


~ Abstract

This TIP proposes to add a labelled frame widget to Tk.

~ Introduction

Labelled frames are a common thing in a GUI and the need for them are
rather clear by the fact that practically every widget package
implements some version of it.

This proposal wants to add simple labelled frames to Tk. Even though a
labelled frame can be built by three frames and label,
this requires some skill and a bit work.  I believe such a basic thing
should be easier and this change would make creating a labelled frame
as simple as it deserves to be.

Below is an example of what I mean with a labelled frame.

#image:18labframe Example of labelled frame

~ Specification

A new widget class, labelframe, is added. It works like a frame, with
the following changes.

These options are added:

 -text: Standard option.  Default value "".
<
|
<
|
|
|
|
|
|
|
>

|



|













|

|








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

# TIP 18: Add Labels to Frames

	Author:         Peter Spjuth <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        12-Dec-2000
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

This TIP proposes to add a labelled frame widget to Tk.

# Introduction

Labelled frames are a common thing in a GUI and the need for them are
rather clear by the fact that practically every widget package
implements some version of it.

This proposal wants to add simple labelled frames to Tk. Even though a
labelled frame can be built by three frames and label,
this requires some skill and a bit work.  I believe such a basic thing
should be easier and this change would make creating a labelled frame
as simple as it deserves to be.

Below is an example of what I mean with a labelled frame.

![Example of labelled frame](../assets/18labframe.png)

# Specification

A new widget class, labelframe, is added. It works like a frame, with
the following changes.

These options are added:

 -text: Standard option.  Default value "".
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
-borderwidth, new default value 2.
-relief, new default value groove.

-padx and -pady are useful in frames and toplevels too, and since
it is easy and cheap to add them at the same time, this TIP proposes
to add them there too.

~ Rationale

My main approach has been to make a simple but still general
solution.  The most typical usage should be really easy, more advanced usage
possible, and more features should be possible to add later if needed.

Trying to mimic all the abilities of a label widget is rather
futile.  It leads to code duplication and future updates to the label
widget would need to be copied too to keep up.  Since the most common label
is a simple text, the labelframe only mimics options -text, -font and -fg
to be able to handle that case in a simple manner.  If you want a more
advanced label, e.g. with an image or with a checkbutton, you can get
it with -labelwidget.

For placement of the label I chose a style I found in IWidget's
"labeledframe" widget.  It's the most general solution I can see since
it allows access to all twelve obvious positions in an easy way.

Options -padx and -pady does not have anything directly to do with
labels, but are a generally nice addition to frames that I
have missed a lot in the past.  Such padding is not possible without
part of the changes to geometry management (see Implementing section)
that are required for displaying the label.

The thing about raising the -labelwidget in the stacking order comes
from this:

With the most simple implementation, using -labelwidget could be done
in two ways:

|# Way #1
|labelframe .f
|label .f.l -text Mupp
|.f configure -labelwidget .f.l

|# Way #2
|label .l -text Mupp
|labelframe .f -labelwidget .l
|raise .l .f

In the first you want the label to be a child but since it has to
exist, the -labelwidget can't be used on the labelframe creation line.

In the second you try to circumvent it by creating the label first,
but then you have to raise it above the labelframe to be visible.

Even though it's just one extra line of code I find it a bit awkward
when it's so easy to do something about.  The first can be fixed by
not trying to do anything with the label widget until idle time when
it has had a chance to be created.  This is not a good solution though
since it leads to some rather awkward things in implementation.  The
second can be fixed by automatically raising the label in the stacking
order when used as -labelwidget.  If this is documented clearly I
don't have a problem with it, and that is why I chose it.

~ Alternatives to this TIP

An alternative way to implement a labelled frame is using mega widget
style with a subframe where children are placed.  This is how current
widget packages do it.  I think that is an awkward and unnatural way
to handle such a simple thing as a labelled frame.  The only reason
to do so is that current limitations in geometry management prevents
a simpler solution.

I believe that a labelled frame should work like a normal frame.  That
it displays a label should not matter more than displaying a border
or a blue background.  A labelled frame megawidget would be different
from a frame, the most noticeable difference being that you can't
pack/grid things directly into the labelled frame,
instead you have to go via a subframe.  Having the labelled frame work
like a normal frame is more consistent and easier for the programmer
at Tcl level.

~ Implementing

Implementing this is mostly rather straightforward.  The labelframe
will share most code with the frame, just like toplevel and frame
share code today, and like the spinbox was built on the entry.  The
tricky part is that limitations in geometry management does not
leave room for displaying a label.  The changes needed in geometry
management are simple but introduces a slight backward incompatibility.

The problem is this.  Today a widget can set an internal border
width.  This defines a uniform width area around the edge of the
widget that geometry managers should stay away from.  This is not enough 
though, since to display a label the frame needs to get more space on
one side where it will put the label.  Also, there is no way for a widget
to affect its own size (anything it says is overridden by pack/grid), so 
the labelframe cannot make sure that enough size is requested to make
room for the label.

By adding some more fields to the TkWindow structure, the
information needed can be transferred to the geometry manager.

First, the present internalBorderWidth field is split into
four fields, one for each side.

Second, minimum requested width/height fields are added.

This requires one macro per field for reading them and
two new APIs to set the fields:

|void Tk_SetInternalBorderWidthEx(tkwin, left, right, top, bottom)
|void Tk_SetMinimumRequestedSize(tkwin, minWidth, minHeight)

Geometry managers would need to be updated to take the new fields
into consideration, and here is where backwards compatibility comes
in.  Any extension implementing a geometry manager would need to be
updated in the same way as grid/pack/place will be.  The change is
trivial, and even if not done most things will work anyway.  An
updated Tk plus an old extension plus an old script will still
work and thus no one needs to worry about upgrading.

I consider this a minor thing since it wont break any existing
applications.  The only thing that will break is if someone would try
to use a geometry manager that is not updated within a labelframe.  And
even in that case you can work around it with an extra frame.

~ Rejected alternatives

The ability to display a label could have been given to the normal
frame by adding the options above to it. Having a new widget class
has the following advantages:

The separate widget class can have its own default values, and the
user can control it separately from the frame in the option database.







|




















|








|
|
|
|

|
|
|
|
















|

















|













|














|
|














|







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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
-borderwidth, new default value 2.
-relief, new default value groove.

-padx and -pady are useful in frames and toplevels too, and since
it is easy and cheap to add them at the same time, this TIP proposes
to add them there too.

# Rationale

My main approach has been to make a simple but still general
solution.  The most typical usage should be really easy, more advanced usage
possible, and more features should be possible to add later if needed.

Trying to mimic all the abilities of a label widget is rather
futile.  It leads to code duplication and future updates to the label
widget would need to be copied too to keep up.  Since the most common label
is a simple text, the labelframe only mimics options -text, -font and -fg
to be able to handle that case in a simple manner.  If you want a more
advanced label, e.g. with an image or with a checkbutton, you can get
it with -labelwidget.

For placement of the label I chose a style I found in IWidget's
"labeledframe" widget.  It's the most general solution I can see since
it allows access to all twelve obvious positions in an easy way.

Options -padx and -pady does not have anything directly to do with
labels, but are a generally nice addition to frames that I
have missed a lot in the past.  Such padding is not possible without
part of the changes to geometry management \(see Implementing section\)
that are required for displaying the label.

The thing about raising the -labelwidget in the stacking order comes
from this:

With the most simple implementation, using -labelwidget could be done
in two ways:

	# Way #1
	labelframe .f
	label .f.l -text Mupp
	.f configure -labelwidget .f.l

	# Way #2
	label .l -text Mupp
	labelframe .f -labelwidget .l
	raise .l .f

In the first you want the label to be a child but since it has to
exist, the -labelwidget can't be used on the labelframe creation line.

In the second you try to circumvent it by creating the label first,
but then you have to raise it above the labelframe to be visible.

Even though it's just one extra line of code I find it a bit awkward
when it's so easy to do something about.  The first can be fixed by
not trying to do anything with the label widget until idle time when
it has had a chance to be created.  This is not a good solution though
since it leads to some rather awkward things in implementation.  The
second can be fixed by automatically raising the label in the stacking
order when used as -labelwidget.  If this is documented clearly I
don't have a problem with it, and that is why I chose it.

# Alternatives to this TIP

An alternative way to implement a labelled frame is using mega widget
style with a subframe where children are placed.  This is how current
widget packages do it.  I think that is an awkward and unnatural way
to handle such a simple thing as a labelled frame.  The only reason
to do so is that current limitations in geometry management prevents
a simpler solution.

I believe that a labelled frame should work like a normal frame.  That
it displays a label should not matter more than displaying a border
or a blue background.  A labelled frame megawidget would be different
from a frame, the most noticeable difference being that you can't
pack/grid things directly into the labelled frame,
instead you have to go via a subframe.  Having the labelled frame work
like a normal frame is more consistent and easier for the programmer
at Tcl level.

# Implementing

Implementing this is mostly rather straightforward.  The labelframe
will share most code with the frame, just like toplevel and frame
share code today, and like the spinbox was built on the entry.  The
tricky part is that limitations in geometry management does not
leave room for displaying a label.  The changes needed in geometry
management are simple but introduces a slight backward incompatibility.

The problem is this.  Today a widget can set an internal border
width.  This defines a uniform width area around the edge of the
widget that geometry managers should stay away from.  This is not enough 
though, since to display a label the frame needs to get more space on
one side where it will put the label.  Also, there is no way for a widget
to affect its own size \(anything it says is overridden by pack/grid\), so 
the labelframe cannot make sure that enough size is requested to make
room for the label.

By adding some more fields to the TkWindow structure, the
information needed can be transferred to the geometry manager.

First, the present internalBorderWidth field is split into
four fields, one for each side.

Second, minimum requested width/height fields are added.

This requires one macro per field for reading them and
two new APIs to set the fields:

	void Tk_SetInternalBorderWidthEx(tkwin, left, right, top, bottom)
	void Tk_SetMinimumRequestedSize(tkwin, minWidth, minHeight)

Geometry managers would need to be updated to take the new fields
into consideration, and here is where backwards compatibility comes
in.  Any extension implementing a geometry manager would need to be
updated in the same way as grid/pack/place will be.  The change is
trivial, and even if not done most things will work anyway.  An
updated Tk plus an old extension plus an old script will still
work and thus no one needs to worry about upgrading.

I consider this a minor thing since it wont break any existing
applications.  The only thing that will break is if someone would try
to use a geometry manager that is not updated within a labelframe.  And
even in that case you can work around it with an extra frame.

# Rejected alternatives

The ability to display a label could have been given to the normal
frame by adding the options above to it. Having a new widget class
has the following advantages:

The separate widget class can have its own default values, and the
user can control it separately from the frame in the option database.
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

1.1 of this TIP has also been discarded because it was too complex.

It would be possible to do without the minimum requested size fields
if you give the responsibility to make sure the label has room to
the GUI programmer. This could be rather awkward though, e.g. when
making an internationalized application where labels can vary a lot.

~ Reference Implementation

An almost finished implementation exists, and it's just a matter of
polishing the last bits to create a patch for this proposal if it
is accepted.

At http://www.dtek.chalmers.se/~d1peter/labframe.tcl you can find a
pure Tcl demo of labelled frames.  Even though it uses sub-frames and
thus do not live up to what I want to accomplish here it implements
all new options as specified here and can be played with if you want
to know more.

~ Copyright

This document has been placed in the public domain.








|





|





|


>
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
1.1 of this TIP has also been discarded because it was too complex.

It would be possible to do without the minimum requested size fields
if you give the responsibility to make sure the label has room to
the GUI programmer. This could be rather awkward though, e.g. when
making an internationalized application where labels can vary a lot.

# Reference Implementation

An almost finished implementation exists, and it's just a matter of
polishing the last bits to create a patch for this proposal if it
is accepted.

At <http://www.dtek.chalmers.se/~d1peter/labframe.tcl> you can find a
pure Tcl demo of labelled frames.  Even though it uses sub-frames and
thus do not live up to what I want to accomplish here it implements
all new options as specified here and can be played with if you want
to know more.

# Copyright

This document has been placed in the public domain.

Name change from tip/180.tip to tip/180.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
TIP:		180
Title:		Add a Megawidget Support Core Package
Author:		Damon Courtney <[email protected]>
Tcl-Version:	8.7
Created:	22-Mar-2003
Version:	$Revision: 1.5 $
Type:		Project
State:		Draft
Vote:		Pending
Post-History:	
Keywords:	Tk


~Abstract

This TIP proposes the addition of a "megawidget" package to Tk as a
core package which contains a set of functions useful for building
megawidgets with standard script-level behaviour in Tk.

~Rationale

It's obvious (to me at least) from the (growing) number of pure-Tcl
megawidget packages that it would be very helpful for Tk to provide
some mechanism to help all these various packages do things in some
standard way.

For example, there is a base set of options and commands that are
supported by all Tk core widgets that should also be supported in any
megawidget.  Now, most of the packages do their job at supporting
<
|
|
|
|
<
|
|
|
|
|
>

|





|

|








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

# TIP 180: Add a Megawidget Support Core Package
	Author:		Damon Courtney <[email protected]>
	Tcl-Version:	8.7
	Created:	22-Mar-2003

	Type:		Project
	State:		Draft
	Vote:		Pending
	Post-History:	
	Keywords:	Tk
-----

# Abstract

This TIP proposes the addition of a "megawidget" package to Tk as a
core package which contains a set of functions useful for building
megawidgets with standard script-level behaviour in Tk.

# Rationale

It's obvious \(to me at least\) from the \(growing\) number of pure-Tcl
megawidget packages that it would be very helpful for Tk to provide
some mechanism to help all these various packages do things in some
standard way.

For example, there is a base set of options and commands that are
supported by all Tk core widgets that should also be supported in any
megawidget.  Now, most of the packages do their job at supporting
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

mostly meant for the developer's developer.

This TIP does not seek to tell megawidget extension writers how they
should write their widgets.  Eveyone has their own ideas of how that
should be done.  This package merely provides some helper functions to
try and speed up the most common widget functions.

~Specification

The commands for this package are all written in C for speed reasons.
After testing different megawidget packages, I find that most of them
are very slow at the most basic widget functions like '''cget''' and
'''configure'''.  That was why I set out to write all of the standard
functions in C and provide the hooks for various packages to use them
instead of all the homegrown solutions that have been used.

The following commands would be part of the package:

'''::megawidget::class''' ''widgetClass''

 > Define a new megawidget class.

'''::megawidget::commands''' ''widgetClass'' ?''command ...''?

 > Define a list of subcommands available to widgets of
   ''widgetClass''.

'''::megawidget::options''' ''widgetClass'' ?''optionList ...''?

 > Define the options available to widgets of ''widgetClass''.  An
   ''optionList'' is a list describing the option:

 > ''type option dbClass dbName defValue''

 > The ''type'' value can be '''boolean''', '''int''', '''double''',
   '''string''', '''enum''', '''color''', '''font''', '''bitmap''',
   '''border''', '''relief''', '''cursor''', '''justify''',
   '''anchor''', '''synonym''', '''pixels''', or '''window'''.  The
   other values should be familiar to users of Tk's standard
   '''configure''' subcommand.

'''::megawidget::create''' ''widgetName widgetClass commandName''

 > Create a new megawidget of class ''widgetClass'' from
   ''widgetName''.  ''widgetName'' must already exist as a widget, and
   its widget command will be renamed to ''commandName'' and replaced
   by a new command that will handle the defined subcommands for the
   widget class.

'''::megawidget::cget''' ''pathName option''

 > Get the value of a megawidget option for ''pathName''.  This
   function is also called as a result of [''pathName'' '''cget'''].

'''::megawidget::configure''' ''pathName'' ?''option''? ?''value
option value ...''?

 > Configure or query option values for the megawidget ''pathName''.
   This function is also called as a result of [''pathName''
   '''configure'''].

The options of a widget are stored and retrieved in dictionaries.  The
'''configure''' and '''cget''' commands are handled by the widget
command after a widget is created, and all other commands are passed
to the author to handle.

Some options (like '''-cursor''', '''-background''',
'''-borderwidth''', '''-bg''', '''-bd''') should probably be created
for all megawidgets, but that has yet to be decided and is open for
discussion.

~Author's Note

I have completed work on this package with all the functions written
in C and with great care to keep them as fast and efficient as
possible.

Porting the BWidget ButtonBox to SNIT and doing some test is what got
me to this point.  I was simply trying to create a widget and do a
'''cget'''.  The results were pretty disappointing considering the
very basic '''cget''' command.

| Native Tk widget: 2 microseconds
| BWidget widget:   60 microseconds
| SNIT widget:      260 microseconds

With '''::megawidget::cget''', I get around 4 microseconds, which is
pretty close to native Tk widgets.

~Copyright

This document has been placed in the public domain.








|



|
|





|



|


|

|

|
|

|

|
|
|
|

|

|

|
|
|



|

|
|

|
|

|
|
|


|



|
|



|







|
|

|
|
|

|


|


>
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
mostly meant for the developer's developer.

This TIP does not seek to tell megawidget extension writers how they
should write their widgets.  Eveyone has their own ideas of how that
should be done.  This package merely provides some helper functions to
try and speed up the most common widget functions.

# Specification

The commands for this package are all written in C for speed reasons.
After testing different megawidget packages, I find that most of them
are very slow at the most basic widget functions like **cget** and
**configure**.  That was why I set out to write all of the standard
functions in C and provide the hooks for various packages to use them
instead of all the homegrown solutions that have been used.

The following commands would be part of the package:

**::megawidget::class** _widgetClass_

 > Define a new megawidget class.

**::megawidget::commands** _widgetClass_ ?_command ..._?

 > Define a list of subcommands available to widgets of
   _widgetClass_.

**::megawidget::options** _widgetClass_ ?_optionList ..._?

 > Define the options available to widgets of _widgetClass_.  An
   _optionList_ is a list describing the option:

 > _type option dbClass dbName defValue_

 > The _type_ value can be **boolean**, **int**, **double**,
   **string**, **enum**, **color**, **font**, **bitmap**,
   **border**, **relief**, **cursor**, **justify**,
   **anchor**, **synonym**, **pixels**, or **window**.  The
   other values should be familiar to users of Tk's standard
   **configure** subcommand.

**::megawidget::create** _widgetName widgetClass commandName_

 > Create a new megawidget of class _widgetClass_ from
   _widgetName_.  _widgetName_ must already exist as a widget, and
   its widget command will be renamed to _commandName_ and replaced
   by a new command that will handle the defined subcommands for the
   widget class.

**::megawidget::cget** _pathName option_

 > Get the value of a megawidget option for _pathName_.  This
   function is also called as a result of [_pathName_ **cget**].

**::megawidget::configure** _pathName_ ?_option_? ?_value
option value ..._?

 > Configure or query option values for the megawidget _pathName_.
   This function is also called as a result of [_pathName_
   **configure**].

The options of a widget are stored and retrieved in dictionaries.  The
**configure** and **cget** commands are handled by the widget
command after a widget is created, and all other commands are passed
to the author to handle.

Some options \(like **-cursor**, **-background**,
**-borderwidth**, **-bg**, **-bd**\) should probably be created
for all megawidgets, but that has yet to be decided and is open for
discussion.

# Author's Note

I have completed work on this package with all the functions written
in C and with great care to keep them as fast and efficient as
possible.

Porting the BWidget ButtonBox to SNIT and doing some test is what got
me to this point.  I was simply trying to create a widget and do a
**cget**.  The results were pretty disappointing considering the
very basic **cget** command.

	 Native Tk widget: 2 microseconds
	 BWidget widget:   60 microseconds
	 SNIT widget:      260 microseconds

With **::megawidget::cget**, I get around 4 microseconds, which is
pretty close to native Tk widgets.

# Copyright

This document has been placed in the public domain.

Name change from tip/181.tip to tip/181.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

TIP:            181
Title:          Add a [namespace unknown] Command
Version:        $Revision: 1.33 $
Author:         Neil Madden <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        23-Mar-2004
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposing adding a new '''namespace''' subcommand,
'''unknown''', which would register a per-namespace procedure for
dealing with unknown commands.

~ Rationale

There is an occassional need within Tcl scripts to change the way in
which command names are resolved, for instance when implementing
language constructs such as object systems or lexically-scoped
commands. Many of these issues are addressed by the newly-accepted
'''namespace path''' command [229]. However, there are still a few
situations where more customized behaviour is required. For instance,
implementing custom per-namespace command auto-loading, or to use
auto-expansion of leading word as in TOOT [http://wiki.tcl.tk/11543].
Currently, the only way to perform such customized command resolution
behaviour is to override the global '''::unknown''' proc to install your
custom handler. There are several drawbacks with this mechanism.

Firstly, it is difficult to override the global '''::unknown''' proc
if you are writing a package, as good style dictates that you shouldn't
override commands outside your package namespace without being explicitly
asked to do so.

Secondly, as Tcl searches for a hard-coded fallback procedure name
('''::unknown'''), in order to override it's functionality you have to
rename it and then install your own replacement - and the new version
becomes the default fallback behaviour for the entire application.  In
the case of implementing custom auto-loading behaviour, you may only
want to override the behaviour for your namespace, and not for the
entire interpreter.  Currently, the only way to do this is to define a
new '''::unknown''' procedure which does pattern matching on the
command name it is passed.

Finally, if a package does override the '''::unknown''' procedure it
has to be careful to save the old handler, and then invoke it for
commands which it is not interested in.  This is an error-prone
approach, and results in a cascade of procedure calls, often with each
one only interested in a subset of the commands being searched for.

~ Related TIPs

There have been two previous attempts at modifying Tcl's command
resolution process.  [52] proposed that the search order be changed to
traverse the complete namespace hierachy from most specific namespace
to the most general (the global namespace).  This TIP was withdrawn as
it was not backwards compatible.  [142] proposed a global variable
which would hold a namespace search path.  This TIP was also withdrawn
as it does not allow different namespaces to have different search
paths.  [229] proposed the '''namespace path''' command as a way of
specifying a per-namespace search path for command resolution.  This
TIP was accepted, and provides a good general mechanism for custom
command resolution.  The current TIP is complementary to [229] and can
be used to handle cases where more flexible behaviour is required.

~ Proposed Change

This TIP proposes that the handling of unknown commands be done on a
per-namespace basis through the introduction of an '''unknown'''
subcommand of the '''namespace''' command.

 > '''namespace unknown''' ?''commandPrefix''?

The subcommand would accept either zero or one argument(s), and is similar
in interface to the '''interp bgerror''' command added by [221].  If no 
arguments are given, the command returns the handler for the current
namespace. The optional argument ''commandPrefix'' is a
command (strictly a prefix list consisting of a command and optional
arguments) to execute if normal command lookup from the current namespace fails.
The command will be concatenated with the full invocation line of the
command being searched for (i.e. the command name and all arguments),
and evaluated in the scope of the current namespace.  The first word in the
list given must be a command name which
must be able to be resolved without resorting to the unknown
mechanism (i.e. it must either be a command in the current or global namespace,
or be fully-qualified).  If this cannot be done, a stock error message will
be generated referring to the original unknown command (and ''not'' the
missing handler) - this is how Tcl currently behaves if no '''::unknown'''
procedure exists.

The command resolution procedure would be altered from this:

   1. Lookup command in current namespace.

   2. If that fails, use path supplied by '''namespace path'''.

   3. If that fails, lookup command in global namespace.

   4. If that fails, call global '''::unknown''' procedure.

to this:

   1. Lookup command in current namespace.

   2. If that fails, use path supplied by '''namespace path'''.

   3. If that fails, lookup command in global namespace.

   4. If that fails, call the unknown handler for the namespace in
which the unknown command was invoked.

Note that this TIP does not change (or allow changing) the default
command resolution procedure - the current, namespace path, and global
namespaces are always searched before the unknown handler is called. This is
so that resolution of the unknown handler itself can be performed, and so
that the handler can be implemented without resorting to fully qualifying
every command in it (e.g. having to use ::set).

It also should be noted that the unknown handler that is called is for
the namespace that ''invoked'' the unknown command, rather than the
namespace which is the ''target'' of the call. There are a number of
reasons for this decision: Firstly, there is no guarantee that the
target namespace actually exists (this might be a reason why the command
was not found). In that case, there would be no target namespace unknown
handler, and we would be forced to fallback on the global default.
Secondly, the mechanism is designed mainly for namespace authors who
wish to implement some custom behaviour that affects the operation of
their own code, e.g., custom auto-loading of missing commands, or more
sophisticated command lookup procedures, etc. This suggests that the
responsibility for dealing with unknown commands should fall on the
originating namespace, rather than being placed on arbitrary other
namespaces. It is believed that this is the most sensible, and the most
predictable, behaviour for an unknown command mechanism. In addition,
with the introduction of '''namespace ensemble''' [112] there now exists
a flexible mechanism for handling the opposite behaviour, allowing the
target namespace to handle requests for unknown commands (e.g.,
forwarding requests). The author of the present TIP considers this to be
the right division of responsibility, as ensembles should become the
default mechanism for accessing public operations of external
namespaces, and also an ensemble command can be guaranteed that the
target namespace does indeed exist.

The default unknown handler for the global namespace is a
handler called '''::unknown'''.  The default handler for other namespaces
calls the global unknown handler.  This means that by default, we have
exactly the same mechanism that exists currently in Tcl.  In order to
change the mechanism for an individual namespace, you may register a
new unknown handler for that namespace.  When no handler is registered
for a namespace, then a call to '''namespace unknown''' will return an
empty string (for non-global namespaces) or '''::unknown''' for the
global namespace. This is so that a distinction can be made between
namespaces which have no handler set, and namespaces which have
had an unknown handler called '''::unknown''' deliberately registered for
them.  With this scheme it is possible to set a global per-interpreter
unknown command handler by setting the unknown handler for the
global namespace. This can then be overridden on a per-namespace
basis, if required.

The calling of unknown handlers registered with '''namespace
unknown''' would be identical to the current calling of the
'''::unknown''' procedure - the handler will be called with the
command name and all of its arguments, as it was originally invoked.
The handler should be a valid Tcl list representing a command and 
possible initial arguments. For instance, a single handler proc could
be used for several namespaces with the namespace passed as an
argument:

| proc handleunknown {ns cmd args} { ... }
| namespace eval foo { namespace unknown [list ::handleunknown ::foo] }
| namespace eval bar { namespace unknown [list ::handleunknown ::bar] }

Setting the unknown handler to {} (an empty list) restores the default
handler ('''::unknown''' for global namespace, global unknown handler
for all other namespaces).

~~ C API

Additionally, this TIP proposes adding two new public functions to the
Tcl C-API to expose this functionality at the C-level. The proposed
new functions are:

| Tcl_Obj *Tcl_GetNamespaceUnknownHandler(Tcl_Interp *interp,
|                                         Tcl_Namespace *nsPtr);

Returns the current unknown command handler registered for the given
namespace, or NULL if none is.

| int Tcl_SetNamespaceUnknownHandler(Tcl_Interp *interp,
|                                    Tcl_Namespace *nsPtr,
|                                    Tcl_Obj *handlerPtr);

Sets the unknown command handler for the namespace, or resets it to the
default if ''handlerPtr'' is NULL or an empty list.

~~ Consequences

As a final note, there is a useful side-effect to always resolving the
unknown handler itself in the current namespace, in that an unknown
handler can be registered for the global namespace which is not
fully qualified, and it will be resolved relative to the namespace in
which an unknown command is invoked. To illustrate:

| # Set global unknown handler to unqualified name
| namespace unknown unknown
| namespace eval foo { proc unknown {args} { puts "FOO" } }
| proc unknown {args} { puts "GLOBAL" }
| 
| bar ;# prints GLOBAL
| namespace eval foo { bar } ;# prints FOO
| namespace eval other { bar } ;# prints GLOBAL

~ Reference Implementation

A reference implementation is available attached to Patch 958222 on the Tcl project at SourceForge
[http://sf.net/tracker/?func=detail&aid=958222&group_id=10894&atid=310894].

The current patch is called tip181-4.patch

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|


|





|


|

|


|





|





|


|





|


|

|
|


|


|


|


|
|

|

|
|

|
|
|

|



|
|
|
|






|



|





|






|




|


|
|

|
|









|

|
|






|




|
|


|





|
|
|






|
|
|

|
|
|

|





|
|




|
|
|


|

|







|
|
|
|
|
|
|
|

|


|



|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

# TIP 181: Add a [namespace unknown] Command

	Author:         Neil Madden <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        23-Mar-2004
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposing adding a new **namespace** subcommand,
**unknown**, which would register a per-namespace procedure for
dealing with unknown commands.

# Rationale

There is an occassional need within Tcl scripts to change the way in
which command names are resolved, for instance when implementing
language constructs such as object systems or lexically-scoped
commands. Many of these issues are addressed by the newly-accepted
**namespace path** command [[229]](229.md). However, there are still a few
situations where more customized behaviour is required. For instance,
implementing custom per-namespace command auto-loading, or to use
auto-expansion of leading word as in TOOT <http://wiki.tcl.tk/11543> .
Currently, the only way to perform such customized command resolution
behaviour is to override the global **::unknown** proc to install your
custom handler. There are several drawbacks with this mechanism.

Firstly, it is difficult to override the global **::unknown** proc
if you are writing a package, as good style dictates that you shouldn't
override commands outside your package namespace without being explicitly
asked to do so.

Secondly, as Tcl searches for a hard-coded fallback procedure name
\(**::unknown**\), in order to override it's functionality you have to
rename it and then install your own replacement - and the new version
becomes the default fallback behaviour for the entire application.  In
the case of implementing custom auto-loading behaviour, you may only
want to override the behaviour for your namespace, and not for the
entire interpreter.  Currently, the only way to do this is to define a
new **::unknown** procedure which does pattern matching on the
command name it is passed.

Finally, if a package does override the **::unknown** procedure it
has to be careful to save the old handler, and then invoke it for
commands which it is not interested in.  This is an error-prone
approach, and results in a cascade of procedure calls, often with each
one only interested in a subset of the commands being searched for.

# Related TIPs

There have been two previous attempts at modifying Tcl's command
resolution process.  [[52]](52.md) proposed that the search order be changed to
traverse the complete namespace hierachy from most specific namespace
to the most general \(the global namespace\).  This TIP was withdrawn as
it was not backwards compatible.  [[142]](142.md) proposed a global variable
which would hold a namespace search path.  This TIP was also withdrawn
as it does not allow different namespaces to have different search
paths.  [[229]](229.md) proposed the **namespace path** command as a way of
specifying a per-namespace search path for command resolution.  This
TIP was accepted, and provides a good general mechanism for custom
command resolution.  The current TIP is complementary to [[229]](229.md) and can
be used to handle cases where more flexible behaviour is required.

# Proposed Change

This TIP proposes that the handling of unknown commands be done on a
per-namespace basis through the introduction of an **unknown**
subcommand of the **namespace** command.

 > **namespace unknown** ?_commandPrefix_?

The subcommand would accept either zero or one argument\(s\), and is similar
in interface to the **interp bgerror** command added by [[221]](221.md).  If no 
arguments are given, the command returns the handler for the current
namespace. The optional argument _commandPrefix_ is a
command \(strictly a prefix list consisting of a command and optional
arguments\) to execute if normal command lookup from the current namespace fails.
The command will be concatenated with the full invocation line of the
command being searched for \(i.e. the command name and all arguments\),
and evaluated in the scope of the current namespace.  The first word in the
list given must be a command name which
must be able to be resolved without resorting to the unknown
mechanism \(i.e. it must either be a command in the current or global namespace,
or be fully-qualified\).  If this cannot be done, a stock error message will
be generated referring to the original unknown command \(and _not_ the
missing handler\) - this is how Tcl currently behaves if no **::unknown**
procedure exists.

The command resolution procedure would be altered from this:

   1. Lookup command in current namespace.

   2. If that fails, use path supplied by **namespace path**.

   3. If that fails, lookup command in global namespace.

   4. If that fails, call global **::unknown** procedure.

to this:

   1. Lookup command in current namespace.

   2. If that fails, use path supplied by **namespace path**.

   3. If that fails, lookup command in global namespace.

   4. If that fails, call the unknown handler for the namespace in
which the unknown command was invoked.

Note that this TIP does not change \(or allow changing\) the default
command resolution procedure - the current, namespace path, and global
namespaces are always searched before the unknown handler is called. This is
so that resolution of the unknown handler itself can be performed, and so
that the handler can be implemented without resorting to fully qualifying
every command in it \(e.g. having to use ::set\).

It also should be noted that the unknown handler that is called is for
the namespace that _invoked_ the unknown command, rather than the
namespace which is the _target_ of the call. There are a number of
reasons for this decision: Firstly, there is no guarantee that the
target namespace actually exists \(this might be a reason why the command
was not found\). In that case, there would be no target namespace unknown
handler, and we would be forced to fallback on the global default.
Secondly, the mechanism is designed mainly for namespace authors who
wish to implement some custom behaviour that affects the operation of
their own code, e.g., custom auto-loading of missing commands, or more
sophisticated command lookup procedures, etc. This suggests that the
responsibility for dealing with unknown commands should fall on the
originating namespace, rather than being placed on arbitrary other
namespaces. It is believed that this is the most sensible, and the most
predictable, behaviour for an unknown command mechanism. In addition,
with the introduction of **namespace ensemble** [[112]](112.md) there now exists
a flexible mechanism for handling the opposite behaviour, allowing the
target namespace to handle requests for unknown commands \(e.g.,
forwarding requests\). The author of the present TIP considers this to be
the right division of responsibility, as ensembles should become the
default mechanism for accessing public operations of external
namespaces, and also an ensemble command can be guaranteed that the
target namespace does indeed exist.

The default unknown handler for the global namespace is a
handler called **::unknown**.  The default handler for other namespaces
calls the global unknown handler.  This means that by default, we have
exactly the same mechanism that exists currently in Tcl.  In order to
change the mechanism for an individual namespace, you may register a
new unknown handler for that namespace.  When no handler is registered
for a namespace, then a call to **namespace unknown** will return an
empty string \(for non-global namespaces\) or **::unknown** for the
global namespace. This is so that a distinction can be made between
namespaces which have no handler set, and namespaces which have
had an unknown handler called **::unknown** deliberately registered for
them.  With this scheme it is possible to set a global per-interpreter
unknown command handler by setting the unknown handler for the
global namespace. This can then be overridden on a per-namespace
basis, if required.

The calling of unknown handlers registered with **namespace
unknown** would be identical to the current calling of the
**::unknown** procedure - the handler will be called with the
command name and all of its arguments, as it was originally invoked.
The handler should be a valid Tcl list representing a command and 
possible initial arguments. For instance, a single handler proc could
be used for several namespaces with the namespace passed as an
argument:

	 proc handleunknown {ns cmd args} { ... }
	 namespace eval foo { namespace unknown [list ::handleunknown ::foo] }
	 namespace eval bar { namespace unknown [list ::handleunknown ::bar] }

Setting the unknown handler to \{\} \(an empty list\) restores the default
handler \(**::unknown** for global namespace, global unknown handler
for all other namespaces\).

## C API

Additionally, this TIP proposes adding two new public functions to the
Tcl C-API to expose this functionality at the C-level. The proposed
new functions are:

	 Tcl_Obj *Tcl_GetNamespaceUnknownHandler(Tcl_Interp *interp,
	                                         Tcl_Namespace *nsPtr);

Returns the current unknown command handler registered for the given
namespace, or NULL if none is.

	 int Tcl_SetNamespaceUnknownHandler(Tcl_Interp *interp,
	                                    Tcl_Namespace *nsPtr,
	                                    Tcl_Obj *handlerPtr);

Sets the unknown command handler for the namespace, or resets it to the
default if _handlerPtr_ is NULL or an empty list.

## Consequences

As a final note, there is a useful side-effect to always resolving the
unknown handler itself in the current namespace, in that an unknown
handler can be registered for the global namespace which is not
fully qualified, and it will be resolved relative to the namespace in
which an unknown command is invoked. To illustrate:

	 # Set global unknown handler to unqualified name
	 namespace unknown unknown
	 namespace eval foo { proc unknown {args} { puts "FOO" } }
	 proc unknown {args} { puts "GLOBAL" }
	 
	 bar ;# prints GLOBAL
	 namespace eval foo { bar } ;# prints FOO
	 namespace eval other { bar } ;# prints GLOBAL

# Reference Implementation

A reference implementation is available attached to Patch 958222 on the Tcl project at SourceForge
<http://sf.net/tracker/?func=detail&aid=958222&group_id=10894&atid=310894> .

The current patch is called tip181-4.patch

# Copyright

This document has been placed in the public domain.

Name change from tip/182.tip to tip/182.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
136
137
138
139
140
141

TIP:            182
Title:          Add [expr bool] Math Function
Version:        $Revision: 1.16 $
Author:         Joe Mistachkin <[email protected]>
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        23-Mar-2004
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes a new '''expr''' math function '''bool()'''.

~ Background

Several of the Tcl/Tk built-in commands make use of the
notion of a Boolean value, a value that can be either true or
false.  Boolean values show up in control commands like '''if'''
and '''while''', and they also are used to enable/disable
certain features, as in '''tcltest::singleProcess $bool'''
and '''namespace ensemble configure $ens -prefixes $bool'''.

There have long been two distinct notions of the set
of string values that are recognized as boolean values.

The '''Tcl_GetBoolean()''' routine recognizes the following
strings and their unique prefixes, in all case variations,
and ''nothing else'' as
valid boolean values: '''0''', '''1''', '''yes''', '''no''',
'''true''', '''false''', '''on''', '''off'''.  Several
script-level commands are implemented by calls to
'''Tcl_GetBoolean''', and also recognize only this limited
set of string values as boolean values.  Examples include
'''string is boolean''', '''string is true''', '''string is false''',
and '''fconfigure $chan -blocking'''.  Examples from Tk
include configuration options of the '''canvas''', '''text''',
and '''scrollbar''' that expect boolean values.

The '''Tcl_ExprBoolean()''' routine interprets the result of
an expression evaluation as a boolean.  It recognizes all the
values recognized by '''Tcl_GetBoolean()''', but it also 
recognizes all numeric values as booleans as well.  Any string
which Tcl can interpret as any kind of number is a boolean
according to '''Tcl_ExprBoolean()''' with the non-zero numbers
seen as true, and others seen as false.  Script-level commands
such as '''if''' and '''while''' have adopted this view of booleans,
so a script like '''while {[incr x -1]} {}''' works as expected.
It also means the script '''if 0x1 {}''' is perfectly acceptable,
even though '''string is boolean 0x1''' reports that '''0x1'''
is not a boolean.

The '''Tcl_GetBooleanFromObj()''' routine arrived in Tcl 8.0,
and contrary to what its name might suggest, it was and is 
not an Obj-ified form of '''Tcl_GetBoolean'''.  Instead, 
'''Tcl_GetBooleanFromObj()''' adopted the '''Tcl_ExprBoolean'''
understanding of what was and was not a boolean value.  Over time
as more Tcl and Tk commands were Obj-ified, it was natural to
replace '''Tcl_GetBoolean''' calls with '''Tcl_GetBooleanFromObj'''
and in the process several commands have come to accept a 
broader class of boolean values than they once did.  For example,

| % info patch
| 7.6p2
| % clock format 0 -gmt 0x1
| expected boolean value but got "0x1"

| % info patch
| 8.0.5
| % clock format 0 -gmt 0x1
| Thu Jan 01 00:00:00 GMT 1970

Another (accidental?) change in behavior in '''Tcl_LinkVar()'''
sneaked in with the [72] changes between Tcl 8.3 and Tcl 8.4.
A linked variable of type '''TCL_LINK_BOOLEAN''' now allows the
Tcl variable to hold any numeric value, while in pre-8.4 releases
of Tcl, only those values acceptable to '''Tcl_GetBoolean''' were
permitted.

Tcl's built-in math functions include three that are devoted to
"casting" operations, '''int()''', '''double()''', and '''wide()'''.
In each case, the result of the function is a string that passes
the corresponding '''string is''' test.  For example,

| string is integer [expr {int($x)}]

will either return '''1''', or raise an error; it will never
return '''0'''.

~ Proposed Change

Add a new built-in unary math function '''bool()''' that accepts
all values accepted by '''Tcl_GetBooleanFromObj()''' and returns
one of the boolean values '''0''' or '''1''', which are acceptable to
'''Tcl_GetBoolean'''.

With that definition in place,

| string is boolean [expr {bool($x)}]

will either return '''1''', or raise an error; it will never
return '''0'''.

~ Reference Implementation

A "quick and dirty" implementation would be (see [232]):

| proc ::tcl::matchfunc::bool x {expr {!!$x}}

A preferred implementation is at Tcl Patch 1165062.
[http://sourceforge.net/support/tracker.php?aid=1165062]
The preferred implementation has somewhat nicer error message
reporting, and has greater potential for bytecode performance
improvements.

~ Rationale

First, this simply makes a nice parallel with the existing "casting"
functions.  It does away with the surprise expressed by some that
a language making use of doubles, integers, and booleans provides
'''double()''' and '''int()''', but not '''bool()'''.

Second, because we have this bifurcated opinion about what
values really count as boolean values, the proposed math
function provides to the script level a way to safely
accept booleans in the broader sense, even if using an
interface that may be narrow.

| fconfigure $chan -blocking [expr {bool($value)}]

This is, of course, equivalent to

| fconfigure $chan -blocking [expr {!!$value}]

but should be easier on the code-reading eyes.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|

|



|
|
|
|




|

|
|
|

|

|
|
|
|

|

|


|

|
|
|
|


|

|
|


|



|
|
|
|

|
|
|
|

|
|
|

|



|

|

|

|
|

|

|
|
|
|



|

|
|

|

|

|


|




|




|







|



|



|


>

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
136
137
138
139
140
141

# TIP 182: Add [expr bool] Math Function

	Author:         Joe Mistachkin <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        23-Mar-2004
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes a new **expr** math function **bool\(\)**.

# Background

Several of the Tcl/Tk built-in commands make use of the
notion of a Boolean value, a value that can be either true or
false.  Boolean values show up in control commands like **if**
and **while**, and they also are used to enable/disable
certain features, as in **tcltest::singleProcess $bool**
and **namespace ensemble configure $ens -prefixes $bool**.

There have long been two distinct notions of the set
of string values that are recognized as boolean values.

The **Tcl\_GetBoolean\(\)** routine recognizes the following
strings and their unique prefixes, in all case variations,
and _nothing else_ as
valid boolean values: **0**, **1**, **yes**, **no**,
**true**, **false**, **on**, **off**.  Several
script-level commands are implemented by calls to
**Tcl\_GetBoolean**, and also recognize only this limited
set of string values as boolean values.  Examples include
**string is boolean**, **string is true**, **string is false**,
and **fconfigure $chan -blocking**.  Examples from Tk
include configuration options of the **canvas**, **text**,
and **scrollbar** that expect boolean values.

The **Tcl\_ExprBoolean\(\)** routine interprets the result of
an expression evaluation as a boolean.  It recognizes all the
values recognized by **Tcl\_GetBoolean\(\)**, but it also 
recognizes all numeric values as booleans as well.  Any string
which Tcl can interpret as any kind of number is a boolean
according to **Tcl\_ExprBoolean\(\)** with the non-zero numbers
seen as true, and others seen as false.  Script-level commands
such as **if** and **while** have adopted this view of booleans,
so a script like **while \{[incr x -1]\} \{\}** works as expected.
It also means the script **if 0x1 \{\}** is perfectly acceptable,
even though **string is boolean 0x1** reports that **0x1**
is not a boolean.

The **Tcl\_GetBooleanFromObj\(\)** routine arrived in Tcl 8.0,
and contrary to what its name might suggest, it was and is 
not an Obj-ified form of **Tcl\_GetBoolean**.  Instead, 
**Tcl\_GetBooleanFromObj\(\)** adopted the **Tcl\_ExprBoolean**
understanding of what was and was not a boolean value.  Over time
as more Tcl and Tk commands were Obj-ified, it was natural to
replace **Tcl\_GetBoolean** calls with **Tcl\_GetBooleanFromObj**
and in the process several commands have come to accept a 
broader class of boolean values than they once did.  For example,

	 % info patch
	 7.6p2
	 % clock format 0 -gmt 0x1
	 expected boolean value but got "0x1"

	 % info patch
	 8.0.5
	 % clock format 0 -gmt 0x1
	 Thu Jan 01 00:00:00 GMT 1970

Another \(accidental?\) change in behavior in **Tcl\_LinkVar\(\)**
sneaked in with the [[72]](72.md) changes between Tcl 8.3 and Tcl 8.4.
A linked variable of type **TCL\_LINK\_BOOLEAN** now allows the
Tcl variable to hold any numeric value, while in pre-8.4 releases
of Tcl, only those values acceptable to **Tcl\_GetBoolean** were
permitted.

Tcl's built-in math functions include three that are devoted to
"casting" operations, **int\(\)**, **double\(\)**, and **wide\(\)**.
In each case, the result of the function is a string that passes
the corresponding **string is** test.  For example,

	 string is integer [expr {int($x)}]

will either return **1**, or raise an error; it will never
return **0**.

# Proposed Change

Add a new built-in unary math function **bool\(\)** that accepts
all values accepted by **Tcl\_GetBooleanFromObj\(\)** and returns
one of the boolean values **0** or **1**, which are acceptable to
**Tcl\_GetBoolean**.

With that definition in place,

	 string is boolean [expr {bool($x)}]

will either return **1**, or raise an error; it will never
return **0**.

# Reference Implementation

A "quick and dirty" implementation would be \(see [[232]](232.md)\):

	 proc ::tcl::matchfunc::bool x {expr {!!$x}}

A preferred implementation is at Tcl Patch 1165062.
<http://sourceforge.net/support/tracker.php?aid=1165062> 
The preferred implementation has somewhat nicer error message
reporting, and has greater potential for bytecode performance
improvements.

# Rationale

First, this simply makes a nice parallel with the existing "casting"
functions.  It does away with the surprise expressed by some that
a language making use of doubles, integers, and booleans provides
**double\(\)** and **int\(\)**, but not **bool\(\)**.

Second, because we have this bifurcated opinion about what
values really count as boolean values, the proposed math
function provides to the script level a way to safely
accept booleans in the broader sense, even if using an
interface that may be narrow.

	 fconfigure $chan -blocking [expr {bool($value)}]

This is, of course, equivalent to

	 fconfigure $chan -blocking [expr {!!$value}]

but should be easier on the code-reading eyes.

# Copyright

This document has been placed in the public domain.

Name change from tip/183.tip to tip/183.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
136
137
138
139
140

TIP:            183
Title:          Add a Binary Flag to [open]
Version:        $Revision: 1.10 $
Author:         Andreas Leitgeb <[email protected]>
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        24-Mar-2004
Post-History:   
Keywords:       Tcl
Tcl-Version:    8.5


~ Abstract

To handle binary files, one currently has to open the file, and then
in a second step '''fconfigure''' it with '''-translation binary'''.
This TIP proposes to add a flag "b" to open's ''access''-argument to
set initial translation to binary (rather than auto).

~ Rationale

ANSI-C ''fopen()'' supports an additional flag "b" in the ''mode''
parameter especially for non-POSIX platforms, where it makes sure that
no conversion takes place at reading or writing.  The manual page for
open mentions that '''fconfigure''' should be used as a substitute for
the missing "b"-flag but I don't see anything wrong with a "b" flag as
a possible shortcut for this '''fconfigure'''-call, so this TIP proposes
that the ''access'' argument to '''open''' should support '''b''' as
an additional letter (anywhere within the argument when used in the
first form documented on the manual page) which will cause the initial
configuration of the channel to be suitable for reading and/or writing
binary data.

Thus, for an expectedly very little implementation effort, we can
simplify:

|  set fd [open $fname "w"]; fconfigure $fd -translation binary

to:

|  set fd [open $fname "wb"]

which looks much more concise for such a common task.

This extra flag would only affect the initial translation state.

~ Enhancement

Tcl's '''open''' also tries to adopt the POSIX ''open()'' parameters
(i.e. the second form documented for the ''access'' parameter on the
manual page.)  POSIX's ''open()'' doesn't know about binary or
non-binary files, but Tcl does, so a new keyword "BINARY" could be
introduced to offer this feature also to those who prefer
list-of-flags syntax.

~ Implementation

A patch attached to Tcl Feature Request 577093 implements
this proposal.  The public Tcl C routine
'''Tcl_FSOpenFileChannel''' is amended to accept the
'''b''' and '''BINARY''' substrings in its parsing
of the ''modeString'' argument.  If this proposal
is accepted, additional work will be performed to
add the required test and documentation changes to the
patch.

~ Compatibility

Any remaining callers of the obsolete private interface
'''TclOpenFileChannelInsertProc''' need to be aware
that the ''(TclOpenFileChannelProc_ *)'' function(s)
it registers will now possibly be passed a ''modeString''
argument that includes the newly supported '''b'''
and '''BINARY''' substrings.  Some updating will be
required to handle this situation.  Ideally, the updating
will take the form of leaving behind use of this obsolete,
unsupported, private interface, and migrating to the
public support for virtual filesystems.

Other than that, this proposal is a completely
compatible extension of existing interfaces.

~ Discussion

There have been comments that the C-like version of access is
just legacy, hard to grok/remember and other general bad things
about even the existing things. Those who don't like/use "r","w",
"r+", anyway, (and who always use {WRITE CREAT TRUNC} instead of 
just "w") are not affected by any additional "b". There is no
'''need''' to use it that way.  fconfigure still remains.
(Partially I agree with them, the "r+" and "w+" are indeed
lousy, and "a" is just a legacy design-bug -- seeks to end
just once instead of before each write. Using that is like begging
for race-conditions to bite. -- On the other hand "r" and "w", with
or without "b" are unbeatably concise and still self-explaining.)

Some proposed adding -options for all kinds of things. Specifying
the access-options as -read or -write ...   My comment to this:
If you like it verbose, use list-syntax for access-flags. This
TIP is '''not''' about getting rid of legacy-C-syntax for flags.

Some said, that if "b" (BINARY) is added, then sooner or 
later every fconfigure option would have to be added to "open",
(and some even proposed that). Thats beside the point. Does
anybody really doubt that "-translation binary" is by far
the most common option used with fconfigure? And open does
really ask for that but not for any other one (at least not 
as loudly :-).

Another comment was about difficulties to implement "b", because
lower-level functions (Tcl_FSOpenFileChannelProc was mentioned)
would have to be changed for that.  That is not true, because 
the "b" could be recognized at top level (Tcl_OpenObjCmd)
and trigger the call to Tcl_SetChannelOption after returning
from the lower levels. ("b" is valid already, just currently 
ignored at all levels).

"open binaryfile r -translation binary" is not really any convenience.
It's almost as verbose as calling fconfigure explicitly.

Two positive comments appeared: First by Vince Darley: Having
the Tcl C-Api for open accept the "b" makes it easier for foreign
libraries (that open binary files) to be integrated as far as
exposing them to Tcl's VFS, by #define'ing fopen to the 
Tcl-C-Api function.

Another, by DKF: The reasons of the current status quo are 
historical: the flags-argument for open was defined when Tcl
was only (officially) available on Unix-platforms (where "b"
is ignored) and didn't even support binary data (nor any
translations). Both of these historical reasons are obsolete
by now.

To sum up: yes, "b" is a C-ism, but open is, too. Also it's
not a feature that someone would be required to use.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|


|
|
|

|

|


|

|
|
|
|






|



|





|

|
|
|




|



|
|
|




|


|
|
|
|
|








|




|
|
|
|



|




|

|

|


|
|


|

|
|
|
|






|
|




|
|
|





|


>

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
136
137
138
139
140

# TIP 183: Add a Binary Flag to [open]

	Author:         Andreas Leitgeb <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        24-Mar-2004
	Post-History:   
	Keywords:       Tcl
	Tcl-Version:    8.5
-----

# Abstract

To handle binary files, one currently has to open the file, and then
in a second step **fconfigure** it with **-translation binary**.
This TIP proposes to add a flag "b" to open's _access_-argument to
set initial translation to binary \(rather than auto\).

# Rationale

ANSI-C _fopen\(\)_ supports an additional flag "b" in the _mode_
parameter especially for non-POSIX platforms, where it makes sure that
no conversion takes place at reading or writing.  The manual page for
open mentions that **fconfigure** should be used as a substitute for
the missing "b"-flag but I don't see anything wrong with a "b" flag as
a possible shortcut for this **fconfigure**-call, so this TIP proposes
that the _access_ argument to **open** should support **b** as
an additional letter \(anywhere within the argument when used in the
first form documented on the manual page\) which will cause the initial
configuration of the channel to be suitable for reading and/or writing
binary data.

Thus, for an expectedly very little implementation effort, we can
simplify:

	  set fd [open $fname "w"]; fconfigure $fd -translation binary

to:

	  set fd [open $fname "wb"]

which looks much more concise for such a common task.

This extra flag would only affect the initial translation state.

# Enhancement

Tcl's **open** also tries to adopt the POSIX _open\(\)_ parameters
\(i.e. the second form documented for the _access_ parameter on the
manual page.\)  POSIX's _open\(\)_ doesn't know about binary or
non-binary files, but Tcl does, so a new keyword "BINARY" could be
introduced to offer this feature also to those who prefer
list-of-flags syntax.

# Implementation

A patch attached to Tcl Feature Request 577093 implements
this proposal.  The public Tcl C routine
**Tcl\_FSOpenFileChannel** is amended to accept the
**b** and **BINARY** substrings in its parsing
of the _modeString_ argument.  If this proposal
is accepted, additional work will be performed to
add the required test and documentation changes to the
patch.

# Compatibility

Any remaining callers of the obsolete private interface
**TclOpenFileChannelInsertProc** need to be aware
that the _\(TclOpenFileChannelProc\_ \*\)_ function\(s\)
it registers will now possibly be passed a _modeString_
argument that includes the newly supported **b**
and **BINARY** substrings.  Some updating will be
required to handle this situation.  Ideally, the updating
will take the form of leaving behind use of this obsolete,
unsupported, private interface, and migrating to the
public support for virtual filesystems.

Other than that, this proposal is a completely
compatible extension of existing interfaces.

# Discussion

There have been comments that the C-like version of access is
just legacy, hard to grok/remember and other general bad things
about even the existing things. Those who don't like/use "r","w",
"r\+", anyway, \(and who always use \{WRITE CREAT TRUNC\} instead of 
just "w"\) are not affected by any additional "b". There is no
**need** to use it that way.  fconfigure still remains.
\(Partially I agree with them, the "r\+" and "w\+" are indeed
lousy, and "a" is just a legacy design-bug -- seeks to end
just once instead of before each write. Using that is like begging
for race-conditions to bite. -- On the other hand "r" and "w", with
or without "b" are unbeatably concise and still self-explaining.\)

Some proposed adding -options for all kinds of things. Specifying
the access-options as -read or -write ...   My comment to this:
If you like it verbose, use list-syntax for access-flags. This
TIP is **not** about getting rid of legacy-C-syntax for flags.

Some said, that if "b" \(BINARY\) is added, then sooner or 
later every fconfigure option would have to be added to "open",
\(and some even proposed that\). Thats beside the point. Does
anybody really doubt that "-translation binary" is by far
the most common option used with fconfigure? And open does
really ask for that but not for any other one \(at least not 
as loudly :-\).

Another comment was about difficulties to implement "b", because
lower-level functions \(Tcl\_FSOpenFileChannelProc was mentioned\)
would have to be changed for that.  That is not true, because 
the "b" could be recognized at top level \(Tcl\_OpenObjCmd\)
and trigger the call to Tcl\_SetChannelOption after returning
from the lower levels. \("b" is valid already, just currently 
ignored at all levels\).

"open binaryfile r -translation binary" is not really any convenience.
It's almost as verbose as calling fconfigure explicitly.

Two positive comments appeared: First by Vince Darley: Having
the Tcl C-Api for open accept the "b" makes it easier for foreign
libraries \(that open binary files\) to be integrated as far as
exposing them to Tcl's VFS, by \#define'ing fopen to the 
Tcl-C-Api function.

Another, by DKF: The reasons of the current status quo are 
historical: the flags-argument for open was defined when Tcl
was only \(officially\) available on Unix-platforms \(where "b"
is ignored\) and didn't even support binary data \(nor any
translations\). Both of these historical reasons are obsolete
by now.

To sum up: yes, "b" is a C-ism, but open is, too. Also it's
not a feature that someone would be required to use.

# Copyright

This document has been placed in the public domain.

Name change from tip/184.tip to tip/184.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

TIP:		184
Title:		Avoid Creating Unusable Variables
Version:	$Revision: 1.4 $
Author:		Miguel Sofer <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	27-Mar-2004
Post-History:	
Keywords:	Tcl, upvar, global
Tcl-Version:	8.5


~ Abstract

Both '''upvar''' and '''global''' can create unreachable variables:
scalar variables whose name looks like an array element, e.g.,
a(b). This behaviour is documented in the '''upvar''' manpage.  This
TIP proposes that both '''upvar''' and '''global''' raise errors
instead of creating such variables.

~ Rationale

As detailed in [[Bug #600812]]
[http://sf.net/tracker/?func=detail&aid=600812&group_id=10894&atid=110894],
both '''upvar''' and '''global''' can create unreachable variables:
scalar variables whose names looks like an array element.

One example is:

|   upvar 0 x(1) y(1)

which creates a ''scalar'' variable named y(1) that is linked to the
element 1 of the array x. However, there is no way for a tcl script to
read or write such scalar variables, the parser will interpret that
name as referring to an element of the array named y.

Another example is:

|   proc a {} {
|       global x(1)
|       ...
|   }


which will create a scalar local variable named 'x(1)', linked to the
element 1 of theglobal array x. Again, this variable is unreachable.

This TIP proposes '''upvar''' and '''global''' raise an error rather
than creating such a variable, mimicking in this respect the behaviour
of '''variable'''.

Note that a TIP is required because the behaviour of '''upvar''' is
documented in the manual page, so that it cannot really be described
as a bug:

 > MyVar is always treated as the name of a variable, not an array
   element. Even if the name looks like an array element, such as
   a(b), a regular variable is created.


~ Reference Implementation

There is a patch attached to the bug ticket
[http://sf.net/tracker/?func=detail&aid=600812&group_id=10894&atid=110894]
that implements this TIP.

~ Copyright

This TIP is in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|

|
|


|

|
|
|




|

|






|
|
|
<
|
>
|


|

|

|





|


|


|


|


>

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

# TIP 184: Avoid Creating Unusable Variables

	Author:		Miguel Sofer <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	27-Mar-2004
	Post-History:	
	Keywords:	Tcl, upvar, global
	Tcl-Version:	8.5
-----

# Abstract

Both **upvar** and **global** can create unreachable variables:
scalar variables whose name looks like an array element, e.g.,
a\(b\). This behaviour is documented in the **upvar** manpage.  This
TIP proposes that both **upvar** and **global** raise errors
instead of creating such variables.

# Rationale

As detailed in [Bug #600812]
<http://sf.net/tracker/?func=detail&aid=600812&group_id=10894&atid=110894> ,
both **upvar** and **global** can create unreachable variables:
scalar variables whose names looks like an array element.

One example is:

	   upvar 0 x(1) y(1)

which creates a _scalar_ variable named y\(1\) that is linked to the
element 1 of the array x. However, there is no way for a tcl script to
read or write such scalar variables, the parser will interpret that
name as referring to an element of the array named y.

Another example is:

	   proc a {} {
	       global x(1)
	       ...

	   }

which will create a scalar local variable named 'x\(1\)', linked to the
element 1 of theglobal array x. Again, this variable is unreachable.

This TIP proposes **upvar** and **global** raise an error rather
than creating such a variable, mimicking in this respect the behaviour
of **variable**.

Note that a TIP is required because the behaviour of **upvar** is
documented in the manual page, so that it cannot really be described
as a bug:

 > MyVar is always treated as the name of a variable, not an array
   element. Even if the name looks like an array element, such as
   a\(b\), a regular variable is created.


# Reference Implementation

There is a patch attached to the bug ticket
<http://sf.net/tracker/?func=detail&aid=600812&group_id=10894&atid=110894> 
that implements this TIP.

# Copyright

This TIP is in the public domain.

Name change from tip/185.tip to tip/185.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252

253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287

288
289
290
291

292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330

331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451

TIP:		185
Title:		Null Handling
Version:	$Revision: 1.8 $
Tcl-Version:	8.6
Author:		John H. Harris <[email protected]>
Created:	08-Apr-2004
Type:		Project
State:		Rejected
Vote:		Done
Post-History:	
Keywords:	Tcl, absent value


~ Abstract

Tcl lacks the ability to handle ''nulls'', data with missing or
unknown values.  In this TIP I suggest a means for representing and
propagating nulls, and command modifications for manipulating them.

~ Rationale

Tcl deals with strings, the universal medium for representing data.
It lacks, however, the intrinsic ability to represent ''missing''
data, or ''nulls''.  A null datum (or just "null") is very different
from an empty string.  A database may represent Prince's last name as
"" -- his name is know and it is an empty string, but if a respondent
forgets to give his weight on a questionnaire, he is not weightless;
his weight is not ""; it is unknown, or ''null''.  Nulls are common in
real-world data, particularly data obtained from interviews or
questionnaires. Because of this, most modern database engines and
statistics tools recognize nulls.  A large fraction of the
applications we are writing are client programs to such databases,
though the user is not always aware of it.

The programmer can use whatever is provided with the database
application program interface (API) he is using, but most Tcl APIs
provide none, probably because Tcl itself lacks nulls.

A Tcl programmer writing an interface to a database must improvise
something to deal with nulls. If the data representation domain does
not include an empty string, as for an integer or date, then an empty
string may suffice, but arbitrary-string data is common, so something
fancier is often needed.

For example, here is an approach I used in a current project built on
SQLite [[1]].  I prepend each nonnull string with an apostrophe.
Thus, nulls are universally represented by an empty string.  I
accomplish this using the ''coalesce()'' function provided by SQLite,
e.g., if I want

|  select id, name from persons

I must ask for

|  select id, coalesce(''||name,'') as name from persons

I wrote a layer that automates this ugly mess.  To keep it simple (and
because SQLite is untyped) it prepends ''all'' fields with an
apostrophe, even ones that do not need it.  I deal with the
apostrophes later -- testing for nullness is easy, but the apostrophe
gets in the way for most other I/O and processing.

This is more than you wanted to know about my personal problems, but
you can be sure this kind of thing is happening over and over with
hundreds of programmers and applications.

Now let us imagine how it might be simplified, assuming Tcl null
support and a revamped SQLite API:

|  set result [ db eval {select id, name from person}
|  foreach -null <unknown> { id name } $result {
|     puts "$id: $name" }

I will explain more later, but basically, the database returns null
information on ''every'' query, so there is no fancy SQL code.  The
'''-null''' option tells '''foreach''' how to represent a null when it
assigns ''id'' and ''name''.

~ Specification

It would be nice if null handling could be added to, or with, a single
command suite.  If we could just extend, say, the '''dict''' command,
these objects would be ideal media for database APIs.  Unfortunately,
it seems impossible to implement any change with out involving Tcl's
string implementation, list syntax, and command interpreter.

~~ Representing Nulls

Not all commands will understand nulls.  We will speak of null-smart
and null-dumb commands.  All commands follow these rules:

   1. Nulls represent a lack of information.
   
   2. An empty string is not null.
   
   3. Nulls can not be made "unnull", merely by being processed.  This
      is equivalent to creating information out of thin air.
      Substituting a nonnull value for a null must programmed
      explicitly.
   
   4. For null-smart commands, nulls propagate.  A null combined with
      any nonnull is null. Appending a null to a string, or
      substituting a null into a string nulls the entire string.

   5. Logical comparisons with nulls with respect to magnitude or
      identity evaluate to null (i.e., ''unknown'').

   6. Null-dumb commands must treat nulls as empty strings.

~~~ Strings Objects

An empty string is not a null.  We have the further constraint that we
must be able to handle any arbitrary binary string, including null (in
the sense of 0x00) bytes.  Clearly the implementation must be
augmented; we must add a null flag.  In implementation, null strings
would probably have their string part set to an empty string, to
accommodate null-dumb commands, as in rule 6 above.  Thus, dumb
commands can simply ignore the null flag.

~~~ List Syntax

It is easy to add a null flag to the string class.  To be of any use,
however, we need to pass a null string to commands, which means
embedding nulls in lists.  We can indicate this much in the same way
the ''{expand}{}'' syntax [157] works, by exploiting otherwise illegal
list syntax.  I propose using '''{null}!''' as null representation for
lists.  (Perhaps new syntax could be a rider on the ''{expand}{}''
rule. I fear that increasing the number of rules could scuttle this
TIP.) At present this syntax (like {expand}{}) produces an "extra
characters after close-brace" error.

Note that the string "{null}!" is ''not'' interpreted as a null
string, instead it is a nonnull string that is also a well-formed list
with one null element.

~~~ Interpreter Behavior

If the command interpreter encounters the word "{null}!" in a list,
this element is replaced by a null string in the array of strings
passed to the command.

When the Tcl command interpreter encounters a word that contains a
variable substitution, if the variable contains a null, the
interpreter will behave as if the entire word were replaced with
"{null}!", and pass a null string to the command in its place.

Command substitutions behave the same way when a command returns a
null.

~~ Manipulating Nulls

We need not be decided how commands should respond to nulls all at
once.  Indeed, it would be better to let this evolve as we gain
experience with this new dimension of data.  At first we will need at
least some basic support to create, copy and test nulls.

~~~ The String Command

The simplest approach is simply to test for nullness.  The obvious
candidate for this test would be an addition to the ''string is''
command suite:

|  if { [ string is null $s ] } {
|     error {Missing data for s.} }

The string command could also be used to generate nulls:

|  set null [ string null ]

~~~ The Set Command

We can use ''set'' to create a variable that contains a null string:

|   % set s {null}!

Now ''s'' exists and has its null flag set.  This is such a natural
syntax that it probably make ''string null'' unnecessary.

We can retrieve a null value with ''set'' -- suppose ''puts'' is dumb
and sees the null as an empty string:

|  % puts "s equals [ set s ]"

'''Set''' returns a null.  In this case, the null is in a command
substitution, and it nulls the entire string being passed to
'''puts''', which, being null-dumb, outputs an empty string and
newline.  This may be unsatisfactory.  We would rather substitute a
nonnull, perhaps an empty string, or "<NULL>".

When and what to substitute is an ad hoc programming choice, so should
be an option.  Here is the ''set'' command with an option that tells
how to represent a null:

|  % set s {null}!
|  % set -null <NULL> s
|  <NULL>
|  % set -null huh? s
|  huh?

The default value for this option is a null, so '''[[set s]]''' can be
used as a direct substitution for '''$s''', as you would expect.

While we must allow for the worst case of representing a null amidst
the set of arbitrary binary strings, in practical data this seldom
occurs.  When it does, we must resort to an explicit test and
conditional execution, but more often there is some gap in the domain
of valid data that can be used to represent a null.  We have already
seen the example of using and empty string for a null integer or date.
For other data types there are better choices.  The programmer knows
these gaps and can choose a string that fits in the gap and is also
easily understood by humans or other software.

The '''-null''' option should have the same meaning when applied to
any null-smart command: if the return value is a null, change it to
the option value.

The set command can use a similar option to assign a null.  This time
the option '''-nullify''' tells what value, by exact match, should be
replaced by a null.

|  % set s NULL
|  NULL
|  % set -nullify NULL t $s
|  % puts '[ set -null Void t ]'
|  'Void'

Notice that string ''s'' above is ''not'' a null, it is the string
"NULL". The second command translates it to a true null, and the third
translates it to "Void".

The '''-nullify''' option provides a way of assigning a null to a
variable that is independent of list syntax:

|  % set -nullify {} s {}

The '''-nullify''' option should have the same meaning when applied to
any null-smart command: if an argument value is an exact match to the
options value, change it to a null.

~~~ List Commands

Most smart commands can just test the null flag of their arguments and
take appropriate action.  A few commands, such as '''lindex''',
'''lset''', '''join''', and '''split''' must understand list null
syntax.  Consider the string:

|  % set s {a {b0 {null}! b2} c}

This string represents a list whose second element is a list containing
a null.  We expect this behavior:

|  % lindex -null ~ $s 1 1 
|  ~

|  % lset -nullify {} s 1 2 {}
|  a {b0 {null}! {null}!} c
|  % lindex -null NUL $s 1 2
|  NUL

'''Join''' creates a string from a list and must understand
'''-null'''.  Notice that the second command below returns null, by
rule 4.

|  % join -null void {a {null}!}
|  a void
|  % join {a {null}!}

'''Split''' creates a list from a string and must understand
'''-nullify''':

|  % split {a {null}!}
|  a {{null}!}
|  % split -nullify NULL {a NULL}
|  a {null}!

~~~ Expr and Control-flow Commands

Nulls can be tested using '''string is null''', but testing occurs so
often in practice that we need to have '''expr''' and the control
commands behave properly, allowing three-valued logic -- true, false,
and null.  (In this context, a logic value of null is often called
"unknown".)  '''Expr''' should recognise the '''-null''' option.
These examples illustrate typical three-valued logic tautologies:

|  % set u {null}!
|  % expr -null unk { $u }
|  unk
|  % expr -null unk { $u && 1 }
|  1

|  % expr -null unk { $u && 0 }
|  unk
|  % expr -null unk { $u || 0 }
|  0

|  % expr -null unk { $u == $u }
|  unk
|  % expr -null unk { $u != 1 }
|  unk
|  % expr -null unk { $u eq {} }
|  unk
|  % expr -null unk { $u > 0 }
|  unk

Notice that, logic expressions containing nulls may may have nonnull
results.  This my seem like a violation of rule 5, but actually is is
just a special kind of lazy logic.  '''Expr''' can simply ignore the
null term because it is tautologously irrelevant.

The control commands '''if''', '''while''', and '''for''' all throw
errors if the expression evaluates to null.

We can also use nulls to represent undefined mathematical results, or
''NaN''s (not a number), in the terminology of IEEE 754 floating point
arithmetic [[2]]. This allows Tcl to give the programmer access to
hardware features that are currently hidden.  To do this we need a
'''-nocomplain''' option:

|  % expr -nocomplain -null nan { log(-1) }
|  nan

We can use the '''-null''' option to assign a usable value if ''a''
goes to zero:

|  % set INF 1e16
|  % set x [ expr -nocomplain -null $INF { 5 / $a } ]

Nulls can propagate sensibly through a computation and give a useful
result when, without them, the same expression would have throw an
exception.  Again, suppose ''a'' goes to zero:

|  % expr -nocomplain -null unk { $x / $a > 0.54 || $c < 0.042 }
|  1


~~~ Other Basic Commands

We need not make all commands null-smart immediately.  Old commands
can treat nulls as empty strings and function as before.  They may be
less useful than they could be, but nothing need break, because old
code contains nothing that would introduce nulls in the first place.
It is up to the programmer who decides to use Tcl's null facility to
be aware of which commands respond intelligently to nulls. Perhaps a
greater danger is that, once nulls are introduced, evolving commands
may break applications that use nulls.  Because of this, it would be
wise to choose the initial set of null-smart commands with care.

I propose modifying the following commands, if necessary, to respond
to nulls appropriately: '''lset''', '''foreach''', '''format''', the
list commands, '''return''', '''set''', '''subst''', '''string''',
'''switch'''.  Except as noted below, this means recognizing the
'''-null''' option.

Now let us discuss the modifications needed for these commands.

   String command suite: Except for '''string is''' commands, all
      '''string''' subcommands should return null if any argument is
      null, simply because the commands are meaningless when applied
      to a null string.

    > Note that a null string is not unequal to any given string.
      Batman may or may not be Bruce Wayne -- his identity is unknown.
      Similarly, two null strings are neither equal nor unequal to
      each other.  Batman may or may not be the same guy as the Lone
      Ranger.

   String is:  Except for '''string is null''', all '''string is'''
      subcommands return 0 with a null argument.

   Switch: The switch command should recognize the '''-null''' option.
      Having a switch leg that matches null is easy to imagine:

|  switch $s {
|     a { do this }
|     b { do that }
|     {null}! { punt } }

    > but by rule 5 it would never execute -- nothing matches a null.
      Instead, use '''-null''':

|  switch -null NULL $s {
|     a { do this }
|     b { do that }
|     NULL { punt } }

    > If you must match any other nonnull string separately from
      nulls, use '''-glob''' and catch the null with ''default'':

|  switch -glob -null NULL -- $s {
|     a { do this }
|     b { do that }
|     * { any other nonnull }
|     default { punt } }

   Foreach:   The '''Foreach''' command recognizes both '''-null''' and
      '''-nullify'''.

   Format: The '''format''' command should understand the '''-null'''
      option.

   The list commands: In general, all the list commands treat nulls as
      distinct elements. Nulls never disappear from a list.
      '''llength''' includes them in the count.  Commands that convert
      lists to or from strings ('''lappend''', '''lindex''',
      '''linsert''', '''list''', '''lset''', '''split''', '''join''')
      should understand the '''-null''' option.  Those that stay in
      the list domain ('''concat''', '''lrange''') should not.

   lsort: If a list contains a null it cannot be sorted -- '''lsort'''
      returns a null string.  With the '''-null''' option, it can be
      sorted after substituting the '''-null''' option value.

~ Issues and Extensions

In this section we discuss design issues that are either debatable or
not entirely resolved.

 * Null attributes.  It is common practice in statistics to have
   several distinct kinds of null. In the SAS language, a null datum
   can be represented by a period, '.', or a period followed by a
   letter, '.a'.  Different codes represent different reasons for the
   null, e.g., .a = "no response", .b = "doubly-entry error", .c =
   "out of range".

 > Another use of a null attribute would be to have a value carry its
   string representation.
   
 > I think both these ideas are of dubious value and violate rule 1,
   but if, in the future, we want to add this functionality, it could
   be added with the syntax {null}{}, where the second set of braces
   contain the attribute information.

 * Choice of symbol.

 > {null}! or NULL, void, nan, unk, unknown, {}!, 

 * SQL inconsistencies.  The various implementations of SQL are
   inconsistent in their treatment of nulls.  This is well documented
   on both the SQLite [[1]] and MySQL [[3]] web sites.  I prefer a
   conservative, consistent mathematical interpretation.  The
   '''-null''' and '''-nullify''' options go a long way toward
   simulating the inconsistencies of other systems, if necessary.

~ Discussion

~ References

 [[1]]: SQLite

 [[2]]: IEEE Floating point

 [[3]]: MySQL

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|


|
|



|







|









|

|


|



|

|
|











|
|
|


|
|
|

|


|




|


















|



|


|
|





|




|
|
|

|


|



|

|






|




|






|


|


|
|



|

|

|

|

|
|

|


|

|

|




|


|
|
|
|
|

|
|











|




|


|
|
|
|
|

|



|


|

|



|


|
|


|




|
<
>
|
|
|
|

|
|


|
|
|

|
|

|
|
|
|

|

|
|

|
|


|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
|
|
|
|



|


|



|
|

|

|
|

|


|
|



|

|
<
|
>
|












|
|
|
|



|
|









|


|


|
|
|
|


|

|
|
|
|


|

|
|
|
|
|

|
|

|




|
|
|
|
|

|
|
|

|











|


|

|




|



|

|


|

|

|

|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285

286
287
288
289

290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327

328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451

# TIP 185: Null Handling

	Tcl-Version:	8.6
	Author:		John H. Harris <[email protected]>
	Created:	08-Apr-2004
	Type:		Project
	State:		Rejected
	Vote:		Done
	Post-History:	
	Keywords:	Tcl, absent value
-----

# Abstract

Tcl lacks the ability to handle _nulls_, data with missing or
unknown values.  In this TIP I suggest a means for representing and
propagating nulls, and command modifications for manipulating them.

# Rationale

Tcl deals with strings, the universal medium for representing data.
It lacks, however, the intrinsic ability to represent _missing_
data, or _nulls_.  A null datum \(or just "null"\) is very different
from an empty string.  A database may represent Prince's last name as
"" -- his name is know and it is an empty string, but if a respondent
forgets to give his weight on a questionnaire, he is not weightless;
his weight is not ""; it is unknown, or _null_.  Nulls are common in
real-world data, particularly data obtained from interviews or
questionnaires. Because of this, most modern database engines and
statistics tools recognize nulls.  A large fraction of the
applications we are writing are client programs to such databases,
though the user is not always aware of it.

The programmer can use whatever is provided with the database
application program interface \(API\) he is using, but most Tcl APIs
provide none, probably because Tcl itself lacks nulls.

A Tcl programmer writing an interface to a database must improvise
something to deal with nulls. If the data representation domain does
not include an empty string, as for an integer or date, then an empty
string may suffice, but arbitrary-string data is common, so something
fancier is often needed.

For example, here is an approach I used in a current project built on
SQLite [[1]](1.md).  I prepend each nonnull string with an apostrophe.
Thus, nulls are universally represented by an empty string.  I
accomplish this using the _coalesce\(\)_ function provided by SQLite,
e.g., if I want

	  select id, name from persons

I must ask for

	  select id, coalesce(''||name,'') as name from persons

I wrote a layer that automates this ugly mess.  To keep it simple \(and
because SQLite is untyped\) it prepends _all_ fields with an
apostrophe, even ones that do not need it.  I deal with the
apostrophes later -- testing for nullness is easy, but the apostrophe
gets in the way for most other I/O and processing.

This is more than you wanted to know about my personal problems, but
you can be sure this kind of thing is happening over and over with
hundreds of programmers and applications.

Now let us imagine how it might be simplified, assuming Tcl null
support and a revamped SQLite API:

	  set result [ db eval {select id, name from person}
	  foreach -null <unknown> { id name } $result {
	     puts "$id: $name" }

I will explain more later, but basically, the database returns null
information on _every_ query, so there is no fancy SQL code.  The
**-null** option tells **foreach** how to represent a null when it
assigns _id_ and _name_.

# Specification

It would be nice if null handling could be added to, or with, a single
command suite.  If we could just extend, say, the **dict** command,
these objects would be ideal media for database APIs.  Unfortunately,
it seems impossible to implement any change with out involving Tcl's
string implementation, list syntax, and command interpreter.

## Representing Nulls

Not all commands will understand nulls.  We will speak of null-smart
and null-dumb commands.  All commands follow these rules:

   1. Nulls represent a lack of information.
   
   2. An empty string is not null.
   
   3. Nulls can not be made "unnull", merely by being processed.  This
      is equivalent to creating information out of thin air.
      Substituting a nonnull value for a null must programmed
      explicitly.
   
   4. For null-smart commands, nulls propagate.  A null combined with
      any nonnull is null. Appending a null to a string, or
      substituting a null into a string nulls the entire string.

   5. Logical comparisons with nulls with respect to magnitude or
      identity evaluate to null \(i.e., _unknown_\).

   6. Null-dumb commands must treat nulls as empty strings.

### Strings Objects

An empty string is not a null.  We have the further constraint that we
must be able to handle any arbitrary binary string, including null \(in
the sense of 0x00\) bytes.  Clearly the implementation must be
augmented; we must add a null flag.  In implementation, null strings
would probably have their string part set to an empty string, to
accommodate null-dumb commands, as in rule 6 above.  Thus, dumb
commands can simply ignore the null flag.

### List Syntax

It is easy to add a null flag to the string class.  To be of any use,
however, we need to pass a null string to commands, which means
embedding nulls in lists.  We can indicate this much in the same way
the _\{expand\}\{\}_ syntax [[157]](157.md) works, by exploiting otherwise illegal
list syntax.  I propose using **\{null\}!** as null representation for
lists.  \(Perhaps new syntax could be a rider on the _\{expand\}\{\}_
rule. I fear that increasing the number of rules could scuttle this
TIP.\) At present this syntax \(like \{expand\}\{\}\) produces an "extra
characters after close-brace" error.

Note that the string "\{null\}!" is _not_ interpreted as a null
string, instead it is a nonnull string that is also a well-formed list
with one null element.

### Interpreter Behavior

If the command interpreter encounters the word "\{null\}!" in a list,
this element is replaced by a null string in the array of strings
passed to the command.

When the Tcl command interpreter encounters a word that contains a
variable substitution, if the variable contains a null, the
interpreter will behave as if the entire word were replaced with
"\{null\}!", and pass a null string to the command in its place.

Command substitutions behave the same way when a command returns a
null.

## Manipulating Nulls

We need not be decided how commands should respond to nulls all at
once.  Indeed, it would be better to let this evolve as we gain
experience with this new dimension of data.  At first we will need at
least some basic support to create, copy and test nulls.

### The String Command

The simplest approach is simply to test for nullness.  The obvious
candidate for this test would be an addition to the _string is_
command suite:

	  if { [ string is null $s ] } {
	     error {Missing data for s.} }

The string command could also be used to generate nulls:

	  set null [ string null ]

### The Set Command

We can use _set_ to create a variable that contains a null string:

	   % set s {null}!

Now _s_ exists and has its null flag set.  This is such a natural
syntax that it probably make _string null_ unnecessary.

We can retrieve a null value with _set_ -- suppose _puts_ is dumb
and sees the null as an empty string:

	  % puts "s equals [ set s ]"

**Set** returns a null.  In this case, the null is in a command
substitution, and it nulls the entire string being passed to
**puts**, which, being null-dumb, outputs an empty string and
newline.  This may be unsatisfactory.  We would rather substitute a
nonnull, perhaps an empty string, or "<NULL>".

When and what to substitute is an ad hoc programming choice, so should
be an option.  Here is the _set_ command with an option that tells
how to represent a null:

	  % set s {null}!
	  % set -null <NULL> s
	  <NULL>
	  % set -null huh? s
	  huh?

The default value for this option is a null, so **[set s]** can be
used as a direct substitution for **$s**, as you would expect.

While we must allow for the worst case of representing a null amidst
the set of arbitrary binary strings, in practical data this seldom
occurs.  When it does, we must resort to an explicit test and
conditional execution, but more often there is some gap in the domain
of valid data that can be used to represent a null.  We have already
seen the example of using and empty string for a null integer or date.
For other data types there are better choices.  The programmer knows
these gaps and can choose a string that fits in the gap and is also
easily understood by humans or other software.

The **-null** option should have the same meaning when applied to
any null-smart command: if the return value is a null, change it to
the option value.

The set command can use a similar option to assign a null.  This time
the option **-nullify** tells what value, by exact match, should be
replaced by a null.

	  % set s NULL
	  NULL
	  % set -nullify NULL t $s
	  % puts '[ set -null Void t ]'
	  'Void'

Notice that string _s_ above is _not_ a null, it is the string
"NULL". The second command translates it to a true null, and the third
translates it to "Void".

The **-nullify** option provides a way of assigning a null to a
variable that is independent of list syntax:

	  % set -nullify {} s {}

The **-nullify** option should have the same meaning when applied to
any null-smart command: if an argument value is an exact match to the
options value, change it to a null.

### List Commands

Most smart commands can just test the null flag of their arguments and
take appropriate action.  A few commands, such as **lindex**,
**lset**, **join**, and **split** must understand list null
syntax.  Consider the string:

	  % set s {a {b0 {null}! b2} c}

This string represents a list whose second element is a list containing
a null.  We expect this behavior:

	  % lindex -null ~ $s 1 1 

	  ~
	  % lset -nullify {} s 1 2 {}
	  a {b0 {null}! {null}!} c
	  % lindex -null NUL $s 1 2
	  NUL

**Join** creates a string from a list and must understand
**-null**.  Notice that the second command below returns null, by
rule 4.

	  % join -null void {a {null}!}
	  a void
	  % join {a {null}!}

**Split** creates a list from a string and must understand
**-nullify**:

	  % split {a {null}!}
	  a {{null}!}
	  % split -nullify NULL {a NULL}
	  a {null}!

### Expr and Control-flow Commands

Nulls can be tested using **string is null**, but testing occurs so
often in practice that we need to have **expr** and the control
commands behave properly, allowing three-valued logic -- true, false,
and null.  \(In this context, a logic value of null is often called
"unknown".\)  **Expr** should recognise the **-null** option.
These examples illustrate typical three-valued logic tautologies:

	  % set u {null}!
	  % expr -null unk { $u }
	  unk
	  % expr -null unk { $u && 1 }

	  1
	  % expr -null unk { $u && 0 }
	  unk
	  % expr -null unk { $u || 0 }

	  0
	  % expr -null unk { $u == $u }
	  unk
	  % expr -null unk { $u != 1 }
	  unk
	  % expr -null unk { $u eq {} }
	  unk
	  % expr -null unk { $u > 0 }
	  unk

Notice that, logic expressions containing nulls may may have nonnull
results.  This my seem like a violation of rule 5, but actually is is
just a special kind of lazy logic.  **Expr** can simply ignore the
null term because it is tautologously irrelevant.

The control commands **if**, **while**, and **for** all throw
errors if the expression evaluates to null.

We can also use nulls to represent undefined mathematical results, or
_NaN_s \(not a number\), in the terminology of IEEE 754 floating point
arithmetic [[2]](2.md). This allows Tcl to give the programmer access to
hardware features that are currently hidden.  To do this we need a
**-nocomplain** option:

	  % expr -nocomplain -null nan { log(-1) }
	  nan

We can use the **-null** option to assign a usable value if _a_
goes to zero:

	  % set INF 1e16
	  % set x [ expr -nocomplain -null $INF { 5 / $a } ]

Nulls can propagate sensibly through a computation and give a useful
result when, without them, the same expression would have throw an
exception.  Again, suppose _a_ goes to zero:

	  % expr -nocomplain -null unk { $x / $a > 0.54 || $c < 0.042 }

	  1

### Other Basic Commands

We need not make all commands null-smart immediately.  Old commands
can treat nulls as empty strings and function as before.  They may be
less useful than they could be, but nothing need break, because old
code contains nothing that would introduce nulls in the first place.
It is up to the programmer who decides to use Tcl's null facility to
be aware of which commands respond intelligently to nulls. Perhaps a
greater danger is that, once nulls are introduced, evolving commands
may break applications that use nulls.  Because of this, it would be
wise to choose the initial set of null-smart commands with care.

I propose modifying the following commands, if necessary, to respond
to nulls appropriately: **lset**, **foreach**, **format**, the
list commands, **return**, **set**, **subst**, **string**,
**switch**.  Except as noted below, this means recognizing the
**-null** option.

Now let us discuss the modifications needed for these commands.

   String command suite: Except for **string is** commands, all
      **string** subcommands should return null if any argument is
      null, simply because the commands are meaningless when applied
      to a null string.

    > Note that a null string is not unequal to any given string.
      Batman may or may not be Bruce Wayne -- his identity is unknown.
      Similarly, two null strings are neither equal nor unequal to
      each other.  Batman may or may not be the same guy as the Lone
      Ranger.

   String is:  Except for **string is null**, all **string is**
      subcommands return 0 with a null argument.

   Switch: The switch command should recognize the **-null** option.
      Having a switch leg that matches null is easy to imagine:

	  switch $s {
	     a { do this }
	     b { do that }
	     {null}! { punt } }

    > but by rule 5 it would never execute -- nothing matches a null.
      Instead, use **-null**:

	  switch -null NULL $s {
	     a { do this }
	     b { do that }
	     NULL { punt } }

    > If you must match any other nonnull string separately from
      nulls, use **-glob** and catch the null with _default_:

	  switch -glob -null NULL -- $s {
	     a { do this }
	     b { do that }
	     * { any other nonnull }
	     default { punt } }

   Foreach:   The **Foreach** command recognizes both **-null** and
      **-nullify**.

   Format: The **format** command should understand the **-null**
      option.

   The list commands: In general, all the list commands treat nulls as
      distinct elements. Nulls never disappear from a list.
      **llength** includes them in the count.  Commands that convert
      lists to or from strings \(**lappend**, **lindex**,
      **linsert**, **list**, **lset**, **split**, **join**\)
      should understand the **-null** option.  Those that stay in
      the list domain \(**concat**, **lrange**\) should not.

   lsort: If a list contains a null it cannot be sorted -- **lsort**
      returns a null string.  With the **-null** option, it can be
      sorted after substituting the **-null** option value.

# Issues and Extensions

In this section we discuss design issues that are either debatable or
not entirely resolved.

 * Null attributes.  It is common practice in statistics to have
   several distinct kinds of null. In the SAS language, a null datum
   can be represented by a period, '.', or a period followed by a
   letter, '.a'.  Different codes represent different reasons for the
   null, e.g., .a = "no response", .b = "doubly-entry error", .c =
   "out of range".

	 > Another use of a null attribute would be to have a value carry its
   string representation.
   
	 > I think both these ideas are of dubious value and violate rule 1,
   but if, in the future, we want to add this functionality, it could
   be added with the syntax \{null\}\{\}, where the second set of braces
   contain the attribute information.

 * Choice of symbol.

	 > \{null\}! or NULL, void, nan, unk, unknown, \{\}!, 

 * SQL inconsistencies.  The various implementations of SQL are
   inconsistent in their treatment of nulls.  This is well documented
   on both the SQLite [[1]](1.md) and MySQL [[3]](3.md) web sites.  I prefer a
   conservative, consistent mathematical interpretation.  The
   **-null** and **-nullify** options go a long way toward
   simulating the inconsistencies of other systems, if necessary.

# Discussion

# References

 [[1]](1.md): SQLite

 [[2]](2.md): IEEE Floating point

 [[3]](3.md): MySQL

# Copyright

This document has been placed in the public domain.

Name change from tip/186.tip to tip/186.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

TIP:            186
Title:          Expose the Type and Modified-State of Widget Options
Version:        $Revision: 1.4 $
Author:         Peter MacDonald <[email protected]>
Author:         Peter MacDonald <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        16-Apr-2004
Post-History:   
Keywords:       Tk
Tcl-Version:    8.7


~ Abstract

This TIP adds a 6th (and 7th element) to each option in the output of
[[''path'' '''configure''']] for Tk widgets, indicating the type and
modified status of each option respectively.

~ Rationale

The configure subcommand of Tk widgets provides a powerful method for
introspection of widget state information.  Unfortunately, two
important pieces of information are currently unavailable.  Namely,
the type Tk is expecting for an option and the whether a user has
explicitly assigned a value.

The type field is valuable in automating interfaces for editing the
contents of widgets.

The modified field is useful in changing styles (such as in
'''tk_setPalette''') where we update all widgets that are currently
using default values.

~ Specification

The configure subcommand for Tk widgets, when invoked with no
arguments, currently dumps out all options as a list with 5 elements
per-option: optName, dbName, dbClass, defValue, optValue.  This TIP
proposes adding up to 2 additional values: '''optType''' and
'''optModified'''.

 * A 6th element, '''optType''', is a string representation of the
   type field of '''Tk_ConfigSpec''' and '''Tk_OptionSpec'''.

 * For widgets using the new '''Tk_OptionSpec''', a 7th appended
   element indicates whether an option has been set by the user.

~ Notes

Perhaps '''optModified''' should be specified as an enumeration.  For
example:

  * 1 = '''USER_MODIFIED'''

  * 2 = '''OPTION_DATABASE'''

  * 3 = '''SYSTEM_DEFAULT'''

  * 4 = '''TABLE_DEFAULT'''

In addition, as much of the Tk core is still using
'''Tk_ConfigSpec''', would some form of compatibility interface make
sense whereby a '''Tk_ConfigSpec''' could be used to dynamically
produce a '''Tk_OptionSpec'''?  (This last is out of the scope of this
TIP.)

Probably also need a way to change options such that the '''USER_MODIFIED''' flag does not get set. (eg. '''tk_setPalette''')

~ Changes

Threre are a couple of small changes to ''tkConfig.c'' and
''tkOldConfig.c'', plus a #define of '''TK_OPTION_VALUE_SET''' in
''tk.h''

~ Overhead/Impact

Scripts currently exploiting introspection and depending upon a list
length of 5 may break.

~ Reference Implementation

There is a simple implementation of the above available as a patch
against Tk 8.4.2[http://pdqi.com/configure.diff.gz].  It does not
implement a enumerated flag for '''optModified''', and the type string
lookup is rather crude.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|
|


|










|
|


|




|
|

|
|

|


|

|


|

|

|

|


|
|
|
|

|

|

|
|
|

|




|


|
|


|


>

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

# TIP 186: Expose the Type and Modified-State of Widget Options

	Author:         Peter MacDonald <[email protected]>
	Author:         Peter MacDonald <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        16-Apr-2004
	Post-History:   
	Keywords:       Tk
	Tcl-Version:    8.7
-----

# Abstract

This TIP adds a 6th \(and 7th element\) to each option in the output of
[_path_ **configure**] for Tk widgets, indicating the type and
modified status of each option respectively.

# Rationale

The configure subcommand of Tk widgets provides a powerful method for
introspection of widget state information.  Unfortunately, two
important pieces of information are currently unavailable.  Namely,
the type Tk is expecting for an option and the whether a user has
explicitly assigned a value.

The type field is valuable in automating interfaces for editing the
contents of widgets.

The modified field is useful in changing styles \(such as in
**tk\_setPalette**\) where we update all widgets that are currently
using default values.

# Specification

The configure subcommand for Tk widgets, when invoked with no
arguments, currently dumps out all options as a list with 5 elements
per-option: optName, dbName, dbClass, defValue, optValue.  This TIP
proposes adding up to 2 additional values: **optType** and
**optModified**.

 * A 6th element, **optType**, is a string representation of the
   type field of **Tk\_ConfigSpec** and **Tk\_OptionSpec**.

 * For widgets using the new **Tk\_OptionSpec**, a 7th appended
   element indicates whether an option has been set by the user.

# Notes

Perhaps **optModified** should be specified as an enumeration.  For
example:

  * 1 = **USER\_MODIFIED**

  * 2 = **OPTION\_DATABASE**

  * 3 = **SYSTEM\_DEFAULT**

  * 4 = **TABLE\_DEFAULT**

In addition, as much of the Tk core is still using
**Tk\_ConfigSpec**, would some form of compatibility interface make
sense whereby a **Tk\_ConfigSpec** could be used to dynamically
produce a **Tk\_OptionSpec**?  \(This last is out of the scope of this
TIP.\)

Probably also need a way to change options such that the **USER\_MODIFIED** flag does not get set. \(eg. **tk\_setPalette**\)

# Changes

Threre are a couple of small changes to _tkConfig.c_ and
_tkOldConfig.c_, plus a \#define of **TK\_OPTION\_VALUE\_SET** in
_tk.h_

# Overhead/Impact

Scripts currently exploiting introspection and depending upon a list
length of 5 may break.

# Reference Implementation

There is a simple implementation of the above available as a patch
against Tk 8.4.2<http://pdqi.com/configure.diff.gz> .  It does not
implement a enumerated flag for **optModified**, and the type string
lookup is rather crude.

# Copyright

This document has been placed in the public domain.

Name change from tip/187.tip to tip/187.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

TIP:            187
Title:          Procedures as Values
Version:        $Revision: 1.14 $
Author:         Salvatore Sanfilippo <[email protected]>
Author:         Miguel Sofer <[email protected]>
Author:         Paul Nash <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        20-Apr-2004
Post-History:   
Keywords:       Tcl,lambda,anonymous,command,function
Tcl-Version:    8.6


~ Abstract

This TIP describes a change in the semantics of Tcl to allow
procedures to be first class values, being represented as strings, and
in particular as three element lists.

~ Rationale

The Tcl programming language is an homoiconic-form language. Program
and data are both presented as strings. A Tcl procedure's arguments
list and body are not an exception to this rule, but the procedure
itself is handled as a name bound to a particular couple of arguments
list and body. This name lives in a separated namespace and does not
collide with variables names.

The first argument of every Tcl command should be the name of a
built-in command, or a procedure (actually a procedure is a user
defined command).  In the latter case, the Tcl interpreter performs a
lookup in a virtual table (that is indirectly accessible using
'''proc''' and '''info''' commands), in order to check if there is a
procedure with the specified name, and to call the procedure using the
associated arguments list and body. If a procedure with the specified
name is not present (nor a built-in command), the interpreter calls a
special procedure named unknown to handle the exception, or raises an
error if the unknown procedure does not exists.

This TIP proposes to modify the Tcl semantic in order to check if the
command name is a valid, three-elements Tcl list with the first
element of the list being the string '''lambda''', before to lookup
any built-in command or procedure. In such a case Tcl will call the
procedure that is represented by the arguments list and body that are
the second and third elements of the list.  Procedures represented as
three-elements lists are called ''anonymous procedures'' in this TIP,
and are first class values as any other Tcl list.

The storage of an anonymous procedure is handled like any other Tcl
object.  Memory management is one of the main problems of procedures
created "on the fly" in Tcl, so that to create anonymous procedures in
Tcl in order to emulate the lambda operator, was and is a problem.
With this TIP, anonymous procedures can be created just using the list
command. The following is an example:

|        set p [list lambda x {string length $x}]
|        $p foo

The above script evaluates to 3. Fast, reliable anonymous procedures
may allow Tcl to better support a functional approach that is very
interesting to use in a language where the list is the main data
structure.

~~Examples

The following Tcl scripts (based on the classic list combinators from
functional programming languages) should look very natural to most
experienced Tcl programmers:

~~~Example 1: Use of Anonymous Commands with a [map] Command

|    proc map {list proc} {
|        set res {}
|        foreach e $list {
|            lappend res [$proc $e]
|        }

|        return $res
|    }

|
|    set a [list one two three four five]
|    set b [map $a [list lambda x {string length $x}]]

This evaluates to [list 3 3 5 4 4]

~~~Example 2: Use of Anonymous Commands with a [filter] Command

|    proc filter {list proc} {
|        set res {}
|        foreach e $list {
|            if {![$proc $e]} {
|                lappend res $e
|            }
|        }


|        return $res
|    }

|
|    set a [list 1 10 100 4 5]
|    set b [filter $a [list lambda x {expr $x<10}]]

This evaluates to [list 10 100]

Note: In practice, defining an alias, '''lambda''', for '''list
lambda''' leads to more natural-looking code.

<PN> 

|    (bin) 20 % list lambda x {string length $x}
|    lambda x {string length $x}
|    (bin) 21 % lambda x {string length $x}
|    lambda x {string length $x}
|    (bin) 22 % 

No alias is required 
</PN>

The author of this TIP thinks that many Tcl programmers will enjoy the
ability to use this programming style. The Tcl folklore actually
implemented different versions of '''lambda''' in the past, but no one
is suitable for prime time.

Still, the ability to manipulate lists in a simpler way can make Tcl
more enjoyable.

The new semantic introduced by this TIP is not only needed to use
operators like ''map'' and ''filter'', but generally makes Tcl able to
address high-order programming in a clean way: procedures that returns
procedures, Currying, and functional composition are all possible
using the TIP's first class procedures in a straightforward way.

There are probably other interesting applications in the field of the
Object Oriented Programming.

~ Proposed Change

The proposed change is to check if the first argument of a command is
an anonymous procedure before to perform any other lookup.  This test
should be fast using the object's string representation because a Tcl
list having as first argument the string "lambda" must start in a
proper way that is easy to detect.

The procedure can be byte-compiled when it's called the first time,
the byte-compiled version can be referenced from the internal
representation of the ''Tcl_Obj'' representing the procedure. The
original string representation of the anonymous procedure can be
cached inside the ''Tcl_Obj'' in order to be able to recreate it when
needed as for ''Tcl_Obj'' semantic.

Actually the implementation may create a conventional Tcl procedure
associated and referenced by the anonymous procedure's object, that
can be released when the internal representation of the anonymous
procedure's ''Tcl_Obj'' is freed.

The real Tcl procedure may live in the '''::lambda''' namespace in
order to be self-introspective.

~ Reference Implementation

A reference implementation is being developed in Patch #940207 (superseeding the previous #939190) [https://sourceforge.net/tracker/index.php?func=detail&aid=940207&group_id=10894&atid=310894]

It follows this tip fairly closely in its effects, but diverges in the implementation strategy. It implements autocleaning procs, and defines lambda expressions as autocleaning procs in (for instance) the ::tcl::lambda namespace. The example above can be defined equivalently as

|   set p [lambda x {string length $x}]
|   set p [list ::tcl::lambda:: x {string length $x}]
|   set p {::tcl::lambda:: x {string length $x}}

although the last version will prevent autocleanup (due to the name being stored in a shared literal).

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|





|









|
|
|
|


|





|



|









|
|






|

|
|


|

|
|
|
|
<
>
|
<
>
|
|
|



|

|
|
|
|
|
<
<
>
>
|
<
>
|
|
|



|
|



|
|
|
|
|






|






|







|









|

|
|




|

|


|

|

|

|
|
|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

# TIP 187: Procedures as Values

	Author:         Salvatore Sanfilippo <[email protected]>
	Author:         Miguel Sofer <[email protected]>
	Author:         Paul Nash <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        20-Apr-2004
	Post-History:   
	Keywords:       Tcl,lambda,anonymous,command,function
	Tcl-Version:    8.6
-----

# Abstract

This TIP describes a change in the semantics of Tcl to allow
procedures to be first class values, being represented as strings, and
in particular as three element lists.

# Rationale

The Tcl programming language is an homoiconic-form language. Program
and data are both presented as strings. A Tcl procedure's arguments
list and body are not an exception to this rule, but the procedure
itself is handled as a name bound to a particular couple of arguments
list and body. This name lives in a separated namespace and does not
collide with variables names.

The first argument of every Tcl command should be the name of a
built-in command, or a procedure \(actually a procedure is a user
defined command\).  In the latter case, the Tcl interpreter performs a
lookup in a virtual table \(that is indirectly accessible using
**proc** and **info** commands\), in order to check if there is a
procedure with the specified name, and to call the procedure using the
associated arguments list and body. If a procedure with the specified
name is not present \(nor a built-in command\), the interpreter calls a
special procedure named unknown to handle the exception, or raises an
error if the unknown procedure does not exists.

This TIP proposes to modify the Tcl semantic in order to check if the
command name is a valid, three-elements Tcl list with the first
element of the list being the string **lambda**, before to lookup
any built-in command or procedure. In such a case Tcl will call the
procedure that is represented by the arguments list and body that are
the second and third elements of the list.  Procedures represented as
three-elements lists are called _anonymous procedures_ in this TIP,
and are first class values as any other Tcl list.

The storage of an anonymous procedure is handled like any other Tcl
object.  Memory management is one of the main problems of procedures
created "on the fly" in Tcl, so that to create anonymous procedures in
Tcl in order to emulate the lambda operator, was and is a problem.
With this TIP, anonymous procedures can be created just using the list
command. The following is an example:

	        set p [list lambda x {string length $x}]
	        $p foo

The above script evaluates to 3. Fast, reliable anonymous procedures
may allow Tcl to better support a functional approach that is very
interesting to use in a language where the list is the main data
structure.

## Examples

The following Tcl scripts \(based on the classic list combinators from
functional programming languages\) should look very natural to most
experienced Tcl programmers:

### Example 1: Use of Anonymous Commands with a [map] Command

	    proc map {list proc} {
	        set res {}
	        foreach e $list {
	            lappend res [$proc $e]

	        }
	        return $res

	    }
	
	    set a [list one two three four five]
	    set b [map $a [list lambda x {string length $x}]]

This evaluates to [list 3 3 5 4 4]

### Example 2: Use of Anonymous Commands with a [filter] Command

	    proc filter {list proc} {
	        set res {}
	        foreach e $list {
	            if {![$proc $e]} {
	                lappend res $e


	            }
	        }
	        return $res

	    }
	
	    set a [list 1 10 100 4 5]
	    set b [filter $a [list lambda x {expr $x<10}]]

This evaluates to [list 10 100]

Note: In practice, defining an alias, **lambda**, for **list
lambda** leads to more natural-looking code.

<PN> 

	    (bin) 20 % list lambda x {string length $x}
	    lambda x {string length $x}
	    (bin) 21 % lambda x {string length $x}
	    lambda x {string length $x}
	    (bin) 22 % 

No alias is required 
</PN>

The author of this TIP thinks that many Tcl programmers will enjoy the
ability to use this programming style. The Tcl folklore actually
implemented different versions of **lambda** in the past, but no one
is suitable for prime time.

Still, the ability to manipulate lists in a simpler way can make Tcl
more enjoyable.

The new semantic introduced by this TIP is not only needed to use
operators like _map_ and _filter_, but generally makes Tcl able to
address high-order programming in a clean way: procedures that returns
procedures, Currying, and functional composition are all possible
using the TIP's first class procedures in a straightforward way.

There are probably other interesting applications in the field of the
Object Oriented Programming.

# Proposed Change

The proposed change is to check if the first argument of a command is
an anonymous procedure before to perform any other lookup.  This test
should be fast using the object's string representation because a Tcl
list having as first argument the string "lambda" must start in a
proper way that is easy to detect.

The procedure can be byte-compiled when it's called the first time,
the byte-compiled version can be referenced from the internal
representation of the _Tcl\_Obj_ representing the procedure. The
original string representation of the anonymous procedure can be
cached inside the _Tcl\_Obj_ in order to be able to recreate it when
needed as for _Tcl\_Obj_ semantic.

Actually the implementation may create a conventional Tcl procedure
associated and referenced by the anonymous procedure's object, that
can be released when the internal representation of the anonymous
procedure's _Tcl\_Obj_ is freed.

The real Tcl procedure may live in the **::lambda** namespace in
order to be self-introspective.

# Reference Implementation

A reference implementation is being developed in Patch \#940207 \(superseeding the previous \#939190\) <https://sourceforge.net/tracker/index.php?func=detail&aid=940207&group_id=10894&atid=310894> 

It follows this tip fairly closely in its effects, but diverges in the implementation strategy. It implements autocleaning procs, and defines lambda expressions as autocleaning procs in \(for instance\) the ::tcl::lambda namespace. The example above can be defined equivalently as

	   set p [lambda x {string length $x}]
	   set p [list ::tcl::lambda:: x {string length $x}]
	   set p {::tcl::lambda:: x {string length $x}}

although the last version will prevent autocleanup \(due to the name being stored in a shared literal\).

# Copyright

This document has been placed in the public domain.

Name change from tip/188.tip to tip/188.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

TIP:            188
Title:          Add 'string is wideinteger' to the 'string is' Subcommand
Version:        $Revision: 1.7 $
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        23-Apr-2004
Post-History:   
Discussions-To: news:comp.lang.tcl
Keywords:       Tcl
Tcl-Version:    8.5


~ Abstract

The '''string''' command supports tests for a number of Tcl's basic
types, for example, integers, doubles, and booleans.  This TIP
proposes adding wide integers.

~ Rationale

The '''string''' command includes tests for the common Tcl types:
'''string is boolean''', '''string is double''' and '''string is
integer'''.  Unaccountably, '''string is wideinteger''' is missing from the
list, making it difficult for an input validation procedure to
determine whether, in fact, a string contains a valid wide integer.

~ Specification

This document proposes augmenting the '''string is''' command with a
'''string is wideinteger''' that functions the same as '''string is
integer''' in every respect except for the fact that it accepts any
string containing a substring that is valid as a wide integer (that
is, acceptable to ''Tcl_GetWideIntFromObj'') possibly surrounded by
whitespace.

~ Reference Implementation

Patches that implement '''string is wideinteger''', provide test cases for
it, and update ''doc/string.n'' to include it are available at
SourceForge as Tcl Patch
#940915[http://sf.net/tracker/?func=detail&atid=310894&aid=940915&group_id=10894].

~ Copyright

Copyright 2004, by Kevin B. Kenny.  Redistribution permitted under the
terms of the Open Publication License
[http://www.opencontent.org/openpub/].

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|



|

|
|
|



|

|
|
|
|
|


|

|
|

|

|



|
>

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

# TIP 188: Add 'string is wideinteger' to the 'string is' Subcommand

	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        23-Apr-2004
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Keywords:       Tcl
	Tcl-Version:    8.5
-----

# Abstract

The **string** command supports tests for a number of Tcl's basic
types, for example, integers, doubles, and booleans.  This TIP
proposes adding wide integers.

# Rationale

The **string** command includes tests for the common Tcl types:
**string is boolean**, **string is double** and **string is
integer**.  Unaccountably, **string is wideinteger** is missing from the
list, making it difficult for an input validation procedure to
determine whether, in fact, a string contains a valid wide integer.

# Specification

This document proposes augmenting the **string is** command with a
**string is wideinteger** that functions the same as **string is
integer** in every respect except for the fact that it accepts any
string containing a substring that is valid as a wide integer \(that
is, acceptable to _Tcl\_GetWideIntFromObj_\) possibly surrounded by
whitespace.

# Reference Implementation

Patches that implement **string is wideinteger**, provide test cases for
it, and update _doc/string.n_ to include it are available at
SourceForge as Tcl Patch
\#940915<http://sf.net/tracker/?func=detail&atid=310894&aid=940915&group_id=10894> .

# Copyright

Copyright 2004, by Kevin B. Kenny.  Redistribution permitted under the
terms of the Open Publication License
<http://www.opencontent.org/openpub/> .

Name change from tip/189.tip to tip/189.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
TIP:            189
Title:          Tcl Modules
Version:        $Revision: 1.13 $
Author:         Andreas Kupries <[email protected]>
Author:         Jean-Claude Wippler <[email protected]>
Author:         Jeff Hobbs <[email protected]>
Author:         Don Porter <[email protected]>
Author:         Larry W. Virden <[email protected]>
Author:         Daniel A. Steffen <[email protected]>
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        24-Mar-2004
Post-History:   
Tcl-Version:    8.5


~ Abstract

This document describes a new mechanism for the handling of packages
by the Tcl Core which differs from the existing system in important
details and makes different trade-offs with regard to flexibility of
package declarations and to access to the filesystem.  This mechanism
is called "Tcl Modules".

~ Background and Motivation

The current mechanism for locating and loading packages employed by
the Tcl core is very flexible, but suffers from a number of drawbacks
as well.  These are at least partially the result of the flexibility,
and thus not easily solved without giving up something.

One problem with the current mechanism is that it extensively searches
the filesystem for packages, and that it has to actually read a file
(''pkgIndex.tcl'') to get the full information for a prospective
package.  All of these operations take time.  The fact that
"index scripts" are able to extend the list of paths searched tends to
heighten this cost as it forces rescans of the filesystem.
Installations where directories in the ''auto_path'' are large or
mounted from remote hosts are hit especially hard by this (network
delays).  All of this together causes a slow startup of tclsh and
Tcl-based applications.

"'''Tcl Modules'''" on the other hand is designed with less
flexibility in mind and to allow implementations to glean as much
information as possible without having to perform lots of accesses to
the filesystem.

Additional benefits of the proposed design are a simplified deployment
of packages, akin to the way starkits made application deployment
simple, and from that an easier implementation and management of
repositories.

It does not come without penalties however.

 * The simplified design has no "index scripts".  While this does away
   with extending the list of paths for searching, it also does away with
   the ability of packages to check preconditions, like the version of
   the currently executing Tcl interpreter.  Dependencies of packages
   (in module form) on particular versions of Tcl have to be managed
   differently and outside of them.

 * "Tcl Modules" is defined to be an extension of the existing package
   mechanism and does ''not'' replace it.  This means that any failure
   to find a package as a module ''has to'' cause a fall back to the
   regular package mechanism.  It also sets a limit on how much of our
   goals we can reach: searching for packages which are not installed
   will stay relatively slow, and dominated by the filesystem scan of
   the regular search.  This implies that "Tcl Modules" will be best
   suited in installations where the number of regular packages is
   low, and contained in a small part of the overall filesystem.

 > On the gripping hand, the only regular packages required will be
   packages supporting the virtual filesystems employed by modules
   (more on that later), so a transformation of a installation based on
   a set of regular packages to the form above is quite feasible.

~ Specification

~~ Introduction

Modules are regular Tcl Packages, in a different guise.  To ease
explanations, first a summary of the existing mechanism:

 * Packages are identified through "''pkgIndex.tcl''" files and the "index
   script" they contain.  These files are read and define the "provide
   script", which tells Tcl how to actually load the package.  In
   other words, the provide script tells whether to use the "'''source'''" or "'''load'''" command, which
   file to specify as an argument to that command, etc.  However as
   "''pkgIndex.tcl''" contains a regular tcl script, it can do more than
   that and actually influence the environment, i.e., the package
   search itself, in several ways:

 > * It may choose to not register the package if conditions for the
     package are not met, like being run by a too old version of Tcl.

 > * It may extend the list of paths used to search for packages.
     This implies that a package is able to modify the behaviour of
     the package search (usually extending the search) even before it is
     loaded, and even if it will not be loaded at all.

The above is very flexible, but comes at a price.  The filesystem is
not only searched, but files have to be read as well to build up the
in-memory index of packages.  And this is iterated if index
files change/extend the list of paths to search.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
|
|
>

|







|








|



|
|
|


|















|



|
|







|

|


|

|




|


|

|



|


|

|








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

# TIP 189: Tcl Modules

	Author:         Andreas Kupries <[email protected]>
	Author:         Jean-Claude Wippler <[email protected]>
	Author:         Jeff Hobbs <[email protected]>
	Author:         Don Porter <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	Author:         Daniel A. Steffen <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        24-Mar-2004
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This document describes a new mechanism for the handling of packages
by the Tcl Core which differs from the existing system in important
details and makes different trade-offs with regard to flexibility of
package declarations and to access to the filesystem.  This mechanism
is called "Tcl Modules".

# Background and Motivation

The current mechanism for locating and loading packages employed by
the Tcl core is very flexible, but suffers from a number of drawbacks
as well.  These are at least partially the result of the flexibility,
and thus not easily solved without giving up something.

One problem with the current mechanism is that it extensively searches
the filesystem for packages, and that it has to actually read a file
\(_pkgIndex.tcl_\) to get the full information for a prospective
package.  All of these operations take time.  The fact that
"index scripts" are able to extend the list of paths searched tends to
heighten this cost as it forces rescans of the filesystem.
Installations where directories in the _auto\_path_ are large or
mounted from remote hosts are hit especially hard by this \(network
delays\).  All of this together causes a slow startup of tclsh and
Tcl-based applications.

"**Tcl Modules**" on the other hand is designed with less
flexibility in mind and to allow implementations to glean as much
information as possible without having to perform lots of accesses to
the filesystem.

Additional benefits of the proposed design are a simplified deployment
of packages, akin to the way starkits made application deployment
simple, and from that an easier implementation and management of
repositories.

It does not come without penalties however.

 * The simplified design has no "index scripts".  While this does away
   with extending the list of paths for searching, it also does away with
   the ability of packages to check preconditions, like the version of
   the currently executing Tcl interpreter.  Dependencies of packages
   \(in module form\) on particular versions of Tcl have to be managed
   differently and outside of them.

 * "Tcl Modules" is defined to be an extension of the existing package
   mechanism and does _not_ replace it.  This means that any failure
   to find a package as a module _has to_ cause a fall back to the
   regular package mechanism.  It also sets a limit on how much of our
   goals we can reach: searching for packages which are not installed
   will stay relatively slow, and dominated by the filesystem scan of
   the regular search.  This implies that "Tcl Modules" will be best
   suited in installations where the number of regular packages is
   low, and contained in a small part of the overall filesystem.

	 > On the gripping hand, the only regular packages required will be
   packages supporting the virtual filesystems employed by modules
   \(more on that later\), so a transformation of a installation based on
   a set of regular packages to the form above is quite feasible.

# Specification

## Introduction

Modules are regular Tcl Packages, in a different guise.  To ease
explanations, first a summary of the existing mechanism:

 * Packages are identified through "_pkgIndex.tcl_" files and the "index
   script" they contain.  These files are read and define the "provide
   script", which tells Tcl how to actually load the package.  In
   other words, the provide script tells whether to use the "**source**" or "**load**" command, which
   file to specify as an argument to that command, etc.  However as
   "_pkgIndex.tcl_" contains a regular tcl script, it can do more than
   that and actually influence the environment, i.e., the package
   search itself, in several ways:

	 > \* It may choose to not register the package if conditions for the
     package are not met, like being run by a too old version of Tcl.

	 > \* It may extend the list of paths used to search for packages.
     This implies that a package is able to modify the behaviour of
     the package search \(usually extending the search\) even before it is
     loaded, and even if it will not be loaded at all.

The above is very flexible, but comes at a price.  The filesystem is
not only searched, but files have to be read as well to build up the
in-memory index of packages.  And this is iterated if index
files change/extend the list of paths to search.

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545


 * What constitutes a Tcl Module ?

 * How are they found ?

 * How are they indexed, i.e. entered into the package database ?

~~ Module Definition

A Tcl Module is a Tcl Package contained in a ''single'' file, and no
other files required by it.  This file has to be '''source'''able.  In other words, a Tcl Module is always imported via:

| source module_file

The "load" command is not directly used.  This restriction is not an
actual limitation, as we may believe.  Ever since 8.4 the Tcl
'''source''' command reads only until the first ^Z character.  This
allows us to combine an arbitrary Tcl script with arbitrary binary
data into one file, where the script processes the attached data in
any it chooses to fully import and activate the package.  Please read
[190] "Implementation Choices for Tcl Modules" for more explanations
of the various choices which are possible.

The name of a module file has to match the regular expression

| ([[:alpha:]_][:[:alnum:]_]*)-([[:digit:]].*)\.tm

The first capturing parentheses provides the name of the package, the
second clause its version.  In addition to matching the pattern, the
extracted version number must not raise an error when used in the
command

| package vcompare $version 0

This additional check has several benefits.  The regular expression pattern is a
bit simpler, and the full version check is based on the official
definition of version numbers used by the Tcl core itself.

~~ Finding Modules

Remember the check for a valid module in last section, and notice that
any filename matching this name pattern is going to be treated by the
TM system as if it's a Tcl module, whether it really is or not.  This
means it's a bad idea for any non-Tcl module files that might match
that pattern to end up in a directory where TM will be scanning.  This
suggests that the directory tree for storing Tcl modules ought to be
something separate from other parts of the filesystem.  This further
implies that a new search path over just these separate storage areas
would be better than Yet Another Use of ''$::auto_path''.

Therefore: Modules are searched for in all directories listed in the
result of the command "'''::tcl::tm::path list'''" (See also section 'API to
"Tcl Modules"').  This is called the "Module path".  Neither
"''auto_path''" nor "''tcl_pkgPath''" are used.

All directories on the module path have to obey one restriction:

 * For any two directories, neither is an ancestor directory of the
   other.

This is required to avoid ambiguities in package naming.  If for
example the two directories

| foo/
| foo/cool

were on the path a package named 'cool::ice' could be found via the
names 'cool::ice' or 'ice', the latter potentially obscuring a package
named 'ice', unqualified.

Before the search is started, the name of the requested package is
translated into a partial path, using the following algorithm:

 * All occurrences of '::' in the package name are replaced by the
   appropriate directory separator character for the platform we are
   on.  On Unix, for example, this is '/'.

Example:

 * The requested package is ''encoding::base64''.  The generated
   partial path is

| encoding/base64

After this translation the package is looked for in all module paths,
by combining them one-by-one, first to last with the partial path to
form a complete search pattern.  The exact pattern and mechanism is
left unspecified, giving the implementation freedom of choice as to what
glob searches to perform, how much of them, and when.

Independent of that, the implemented algorithm has to reject all files
where the filename does not match the regular expression given in the
previous section.  For the remaining files "provide scripts" are
generated and added to the '''package ifneeded''' database.

The algorithm has to fall back to the previous unknown handler when
none of the found module files satisfy the request.  If the request
was satisfied no fall-back is required.

~~ Provide and Index Scripts

Packages in module form have no control over the "index" and "provide
script"s entered into the package database for them.  For a module
file ''MF'' the "index script" is

| package ifneeded PNAME PVERSION [list source MF]

and the "provide script" embedded in the above is

| source MF

Both package name '''PNAME''' and package version '''PVERSION''' are
extracted from the filename '''MF''' according to the definition
below:

| MF = /module_path/PNAME'-PVERSION.tm

Where '''PNAME' '''is the partial path of the module as defined in
section 'Finding Modules' before, and translated into '''PNAME''' by
changing all directory separators to '::', and '''module_path''' is the
 path (from the list of paths to search) that we found the module file under.

''Note'' that we are here creating a connection between package names
and paths.  Tcl is case-sensitive when it comes to comparing package
names, but there are filesystems which are not, like NTFS.  Luckily
these filesystems do store the case of the name, despite not using the
information when comparing.

Given the above we allow the names for packages in Tcl modules to have
mixed-case, but also require that there are no collisions when
comparing names in a case-insensitive manner.  In other words, if a
package 'Foo' is deployed in the form of a Tcl Module, packages like
'foo', 'fOo', etc. are not allowed anymore.

Regular packages have no problem with the names of their files, as
their entry point has a standard name ("''pkgIndex.tcl''") and its
contents can be adjusted according to the filesystem they are stored
in.

~~ API to "Tcl Modules"

"Tcl Modules" is implemented in Tcl, as a new handler command for
'''package unknown'''.  This command calls the previously installed
handler when its own search fails, thereby ensuring proper fall-back to
the regular package search.

All code and data structures implementing "Tcl Modules" reside in the
namespace "''::tcl::tm''".

A namespace variable holds the list of paths to search for modules,
but is not officially exported.  All access to this variable is done
through the following public commands:

 * '''::tcl::tm::path add''' ''PATH''

 > The path is added at the head to the list of module paths.

 > The command enforces the restriction that no path may be an
   ancestor directory of any other path on the list.  If the new path
   violates this restriction an error will be raised.

 > If the path is already present as is, no error will be raised and no
   action will be taken.

 > Paths are searched in the order of their appearance in the list.
   As they are added to the front of the list they are searched in
   reverse order of addition.  In other words, the paths added last
   are looked at first.

 * '''::tcl::tm::path remove''' ''PATH''

 > Removes the path from the list of module paths.  The command is
   silently ignored if the path is not on the list.

 * '''::tcl::tm::path list'''

 > Returns a list containing all registered module paths, in the order
   that they are searched for modules.

 * '''::tcl::tm::roots''' ''PATH_LIST''

 > Similar to ''path add'', and layered on top of it. This command
   takes a list of paths, extends each with ''tclX/site-tcl'', and
   ''tclX/X.y'', for major version X of the tcl interpreter and minor
   version y less than or equal to the minor version of the
   interpreter, and adds the resulting set of paths to the list of
   paths to search.

 > This command is used internally by the system to set up the
   system-specific default paths. See section ''Defaults'' for their
   definition, and that their structure matches what this command
   does.

 > The command has been exposed to allow a buildsystem to define
   additional root paths beyond those defined by this document.

We do ''not'' provide APIs for rescanning directories, clearing
internal state and such.  The official interface to this functionality
is "package forget" and special interfaces are neither required nor
desirable.

~ Discussion

~~ Restriction to "source"

This has already been discussed in the specification above.

For more discussion I again refer to [190] "Implementation Choices for
Tcl Modules" which explains the various implementation choices in much
more detail.

~~ Preconditions

It has already been mentioned in section 'Background and Motivation'
that preconditions in "index scripts" are lost, one of the penalties
of the simplified scheme specified here.

Their existence was most important to installations with multiple
versions of Tcl coexisting with each other as they could share the
directory hierarchy containing packages between the various Tcl cores.
This is not possible anymore, at least not in a simple manner.

For the majority of installations however, i.e. those without only one
version of Tcl installed, or controlled environments like the inside
of starkits and starpacks, this loss is irrelevant and of no
consequence.

For more discussion please see [191] "Managing Tcl Package and Modules
in a Multi-Version Environment" which explains the various choices a
sysadmin has in much more detail.

~~ Package Metadata

An area possibly made harder by Tcl Modules is the storage and query
of package metadata.  [59] was one way of handling such information,
by storing them in the binary library of packages which have such.
Another approach was to store them in the package index script, using
a hypothetical '''package about''' command.

The latter approach has the definite advantage that it was possible to
query the database of metadata for a particular package without
having to actually load said package, as a load may fail if the Tcl
shell used to query the database does not fulfil the preconditions
for that package.

Both approaches listed above assume that it makes sense to query the
database of metadata for all installed packages from a plain Tcl
shell.  In other words, to use the standard Tcl shell also as the tool
to directly manage an installation.

It is possible to extend the proposal made in this document to handle
metadata as well.  We already reserved the namespace '''::tcl::tm'''
for use by us, so it is no problem to extend the public API with
commands to locate all installed packages, their metadata, and to
perform queries based on this.  This will require an additional
specification as to how metadata is stored in/by Tcl Modules, and it will
have to be understood that these extended management operations can
take considerably more time than a '''package require''', as they will
have to scan all defined search paths and all their sub directories
for Tcl Modules, and have to extract the metadata itself as well.

~~ Deployment

The fact that a Tcl Module consists only of a single file makes its
deployment quite easy.  We only have to ensure correct placement in
one of the searched directories when installing it locally, but
nothing more.

Regarding the usage of Tcl Modules in a wrapped application, please see
[190] "Implementation Choices for Tcl Modules".  This is highly
dependent on the implementation chosen for a specific Tcl Module and
thus not discussed here, but in the referred document.

~~ Package Repositories

At a very basic level, the physical storage, any directory tree
containing properly placed files for a number of modules can serve as
a package repository for the modules in it.  In other words, from that
point of view an installation is virtually indistinguishable from a
repository, and their creation and maintenance is very easy

Note however that the higher levels of a repository, like indexing
package metadata in general, or dependence tracking in particular,
licensing, documentation, etc. are not addressed here and by this.

This requires standards for package metadata, format and content,
topics with which this document will not deal.

~~ Defaults

The default list of paths on the module path is computed by a tclsh as
follows, where ''X'' is the major version of the Tcl interpreter and
''y'' is less than or equal to the minor version of the Tcl
interpreter.

 * System specific paths

 > * '''file normalize''' [['''info library''']]/../tcl''X''/''X''.''y''

 > > In other words, the interpreter will look into a directory
     specified by its major version and whose minor versions are less
     than or equal to the minor version of the interpreter.

 > > Example: For Tcl 8.4 the paths searched are

 > > * [['''info library''']]/../tcl8/8.4

 > > * [['''info library''']]/../tcl8/8.3

 > > * [['''info library''']]/../tcl8/8.2

 > > * [['''info library''']]/../tcl8/8.1

 > > * [['''info library''']]/../tcl8/8.0

 > > This definition assumes that a package defined for Tcl ''X.y'' can
     also be used by all interpreters which have the same major number
     ''X'' and a minor number greater than ''y''.

 > * '''file normalize''' ''EXEC''/tcl''X''/''X''.''y''

 > > Where ''EXEC'' is [['''file normalize''' [['''info
     nameofexecutable''']]/../lib]] or [['''file normalize'''
     [['''::tcl::pkgconfig get''' libdir,runtime]]]]

 > > This sets of paths is handled equivalently to the set coming
     before, except that it is anchored in ''EXEC_PREFIX''.  For a
     build with ''PREFIX'' = ''EXEC_PREFIX'' the two sets are
     identical.

 * Site specific paths.

 > * '''file normalize''' [['''info library''']]/../tcl''X''/site-tcl

 * User specific paths.

 > * '''$::env'''(TCL''X''.''y''_TM_PATH)

 > > A list of paths, separated by either ''':''' (Unix) or ''';'''
     (Windows).  This is user and site specific as this environment
     variable can be set not only by the user's profile, but by system
     configuration scripts as well.

 > > These paths are seen and therefore shared by all Tcl shells in
     the '''$::env'''(PATH) of the user.

 > > Note that ''X'' and ''y'' follow the general rules set out above.
     In other words, Tcl 8.4, for example, will look at these 5
     environment variables

 > > * '''$::env'''(TCL8.4_TM_PATH)

 > > * '''$::env'''(TCL8.3_TM_PATH)

 > > * '''$::env'''(TCL8.2_TM_PATH)

 > > * '''$::env'''(TCL8.1_TM_PATH)

 > > * '''$::env'''(TCL8.0_TM_PATH)

''All'' the default paths are added to the module path, even those
paths which do not exist.  Non-existent paths are filtered out during
actual searches.  This enables a user to create one of the paths
searched when needed and all running applications will automatically
pick up any modules placed in them.

The paths are added in the order as they are listed above, and for
lists of paths defined by an environment variable in the order they
are found in the variable.

~~ Installation

The installation of a Tcl module for a particular interpreter is
basically done like this:

| #! /path/to/chosen/tclsh
| # First argument is the name of the module.
| # Second argument is the base filename
| set mpaths [::tcl::tm::path list]
| ... remove all paths the user has no write permissions for.
| ... throw an error if there are no paths left.
| ... provide the user with some UI if more than one path is left
| ... so that she can select the path to use.
| set selmpath [ui_select $mpaths]
| file copy [lindex $argv 1] \
|     [file join $selmpath \
|     [file dirname [string map {:: /} \
|     [lindex $argv 0]]]]

~ Glossary

The following terms and definitions are used throughout the document

 * ''index script''

 > A script used to index a package, or not.  Usually contained in a
   file named "''pkgIndex.tcl''".  Can check preconditions for a
   package and contains package specific code for setting up the
   package specific ''provide script''.

 * ''provide script''

 > This is a package specific script and tells Tcl exactly how to
   import it.  In the existing package system it is generated and
   registered by the ''index script''.  Tcl Modules on the other hand
   generates it based on information gleaned from filenames.

~ Reference Implementation

A reference implementation is available in Patch 942881
[http://sf.net/tracker/?func=detail&aid=942881&group_id=10894&atid=310894]

~ Questions

~ Comments

[[ Add comments on the document here ]]

A feature asked for during discussion is to allow a directory as
a Tcl Module. I am opposed to this, because behind Tcl Modules is
the same idea/vision as for starkit and starpacks, namely that of
deploying something in the simplest possible manner, without any
overhead. Sometimes I call Tcl Modules package kits, short pakits
(and then twist that then spoken into 'packet' :).
[http://groups.google.ca/groups?hl=en&lr=&ie=UTF-8&frame=right&th=78764d499cc4e4a&seekm=c6tshf030c6%40news4.newsguy.com#link19]

~ Copyright

This document has been placed in the public domain.








|

|
|

|



|



|




|






|





|









|


|
|
|









|
|














|


|










|





|



|

|



|

|
|


|

|
|
|
|

|












|



|


|




|





|

|

|



|


|




|

|


|

|


|

|
|
|




|
|



|


|




|

|



|



|















|



|


|


|













|





|



|







|



|














|


|
|




|

|



|

|

|

|

|

|

|

|

|

|
|
|

|
|
|




|



|

|
|



|
|

|



|

|

|

|

|

|









|




|
|
|
|
|
|
|
|
|
|
|
|
|

|



|

|
|

|

|

|

|


|


|

|

|

|






|
|

|


>
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545

 * What constitutes a Tcl Module ?

 * How are they found ?

 * How are they indexed, i.e. entered into the package database ?

## Module Definition

A Tcl Module is a Tcl Package contained in a _single_ file, and no
other files required by it.  This file has to be **source**able.  In other words, a Tcl Module is always imported via:

	 source module_file

The "load" command is not directly used.  This restriction is not an
actual limitation, as we may believe.  Ever since 8.4 the Tcl
**source** command reads only until the first ^Z character.  This
allows us to combine an arbitrary Tcl script with arbitrary binary
data into one file, where the script processes the attached data in
any it chooses to fully import and activate the package.  Please read
[[190]](190.md) "Implementation Choices for Tcl Modules" for more explanations
of the various choices which are possible.

The name of a module file has to match the regular expression

	 ([[:alpha:]_][:[:alnum:]_]*)-([[:digit:]].*)\.tm

The first capturing parentheses provides the name of the package, the
second clause its version.  In addition to matching the pattern, the
extracted version number must not raise an error when used in the
command

	 package vcompare $version 0

This additional check has several benefits.  The regular expression pattern is a
bit simpler, and the full version check is based on the official
definition of version numbers used by the Tcl core itself.

## Finding Modules

Remember the check for a valid module in last section, and notice that
any filename matching this name pattern is going to be treated by the
TM system as if it's a Tcl module, whether it really is or not.  This
means it's a bad idea for any non-Tcl module files that might match
that pattern to end up in a directory where TM will be scanning.  This
suggests that the directory tree for storing Tcl modules ought to be
something separate from other parts of the filesystem.  This further
implies that a new search path over just these separate storage areas
would be better than Yet Another Use of _$::auto\_path_.

Therefore: Modules are searched for in all directories listed in the
result of the command "**::tcl::tm::path list**" \(See also section 'API to
"Tcl Modules"'\).  This is called the "Module path".  Neither
"_auto\_path_" nor "_tcl\_pkgPath_" are used.

All directories on the module path have to obey one restriction:

 * For any two directories, neither is an ancestor directory of the
   other.

This is required to avoid ambiguities in package naming.  If for
example the two directories

	 foo/
	 foo/cool

were on the path a package named 'cool::ice' could be found via the
names 'cool::ice' or 'ice', the latter potentially obscuring a package
named 'ice', unqualified.

Before the search is started, the name of the requested package is
translated into a partial path, using the following algorithm:

 * All occurrences of '::' in the package name are replaced by the
   appropriate directory separator character for the platform we are
   on.  On Unix, for example, this is '/'.

Example:

 * The requested package is _encoding::base64_.  The generated
   partial path is

		 encoding/base64

After this translation the package is looked for in all module paths,
by combining them one-by-one, first to last with the partial path to
form a complete search pattern.  The exact pattern and mechanism is
left unspecified, giving the implementation freedom of choice as to what
glob searches to perform, how much of them, and when.

Independent of that, the implemented algorithm has to reject all files
where the filename does not match the regular expression given in the
previous section.  For the remaining files "provide scripts" are
generated and added to the **package ifneeded** database.

The algorithm has to fall back to the previous unknown handler when
none of the found module files satisfy the request.  If the request
was satisfied no fall-back is required.

## Provide and Index Scripts

Packages in module form have no control over the "index" and "provide
script"s entered into the package database for them.  For a module
file _MF_ the "index script" is

	 package ifneeded PNAME PVERSION [list source MF]

and the "provide script" embedded in the above is

	 source MF

Both package name **PNAME** and package version **PVERSION** are
extracted from the filename **MF** according to the definition
below:

	 MF = /module_path/PNAME'-PVERSION.tm

Where **PNAME' **is the partial path of the module as defined in
section 'Finding Modules' before, and translated into **PNAME** by
changing all directory separators to '::', and **module\_path** is the
 path \(from the list of paths to search\) that we found the module file under.

_Note_ that we are here creating a connection between package names
and paths.  Tcl is case-sensitive when it comes to comparing package
names, but there are filesystems which are not, like NTFS.  Luckily
these filesystems do store the case of the name, despite not using the
information when comparing.

Given the above we allow the names for packages in Tcl modules to have
mixed-case, but also require that there are no collisions when
comparing names in a case-insensitive manner.  In other words, if a
package 'Foo' is deployed in the form of a Tcl Module, packages like
'foo', 'fOo', etc. are not allowed anymore.

Regular packages have no problem with the names of their files, as
their entry point has a standard name \("_pkgIndex.tcl_"\) and its
contents can be adjusted according to the filesystem they are stored
in.

## API to "Tcl Modules"

"Tcl Modules" is implemented in Tcl, as a new handler command for
**package unknown**.  This command calls the previously installed
handler when its own search fails, thereby ensuring proper fall-back to
the regular package search.

All code and data structures implementing "Tcl Modules" reside in the
namespace "_::tcl::tm_".

A namespace variable holds the list of paths to search for modules,
but is not officially exported.  All access to this variable is done
through the following public commands:

 * **::tcl::tm::path add** _PATH_

	 > The path is added at the head to the list of module paths.

	 > The command enforces the restriction that no path may be an
   ancestor directory of any other path on the list.  If the new path
   violates this restriction an error will be raised.

	 > If the path is already present as is, no error will be raised and no
   action will be taken.

	 > Paths are searched in the order of their appearance in the list.
   As they are added to the front of the list they are searched in
   reverse order of addition.  In other words, the paths added last
   are looked at first.

 * **::tcl::tm::path remove** _PATH_

	 > Removes the path from the list of module paths.  The command is
   silently ignored if the path is not on the list.

 * **::tcl::tm::path list**

	 > Returns a list containing all registered module paths, in the order
   that they are searched for modules.

 * **::tcl::tm::roots** _PATH\_LIST_

	 > Similar to _path add_, and layered on top of it. This command
   takes a list of paths, extends each with _tclX/site-tcl_, and
   _tclX/X.y_, for major version X of the tcl interpreter and minor
   version y less than or equal to the minor version of the
   interpreter, and adds the resulting set of paths to the list of
   paths to search.

	 > This command is used internally by the system to set up the
   system-specific default paths. See section _Defaults_ for their
   definition, and that their structure matches what this command
   does.

	 > The command has been exposed to allow a buildsystem to define
   additional root paths beyond those defined by this document.

We do _not_ provide APIs for rescanning directories, clearing
internal state and such.  The official interface to this functionality
is "package forget" and special interfaces are neither required nor
desirable.

# Discussion

## Restriction to "source"

This has already been discussed in the specification above.

For more discussion I again refer to [[190]](190.md) "Implementation Choices for
Tcl Modules" which explains the various implementation choices in much
more detail.

## Preconditions

It has already been mentioned in section 'Background and Motivation'
that preconditions in "index scripts" are lost, one of the penalties
of the simplified scheme specified here.

Their existence was most important to installations with multiple
versions of Tcl coexisting with each other as they could share the
directory hierarchy containing packages between the various Tcl cores.
This is not possible anymore, at least not in a simple manner.

For the majority of installations however, i.e. those without only one
version of Tcl installed, or controlled environments like the inside
of starkits and starpacks, this loss is irrelevant and of no
consequence.

For more discussion please see [[191]](191.md) "Managing Tcl Package and Modules
in a Multi-Version Environment" which explains the various choices a
sysadmin has in much more detail.

## Package Metadata

An area possibly made harder by Tcl Modules is the storage and query
of package metadata.  [[59]](59.md) was one way of handling such information,
by storing them in the binary library of packages which have such.
Another approach was to store them in the package index script, using
a hypothetical **package about** command.

The latter approach has the definite advantage that it was possible to
query the database of metadata for a particular package without
having to actually load said package, as a load may fail if the Tcl
shell used to query the database does not fulfil the preconditions
for that package.

Both approaches listed above assume that it makes sense to query the
database of metadata for all installed packages from a plain Tcl
shell.  In other words, to use the standard Tcl shell also as the tool
to directly manage an installation.

It is possible to extend the proposal made in this document to handle
metadata as well.  We already reserved the namespace **::tcl::tm**
for use by us, so it is no problem to extend the public API with
commands to locate all installed packages, their metadata, and to
perform queries based on this.  This will require an additional
specification as to how metadata is stored in/by Tcl Modules, and it will
have to be understood that these extended management operations can
take considerably more time than a **package require**, as they will
have to scan all defined search paths and all their sub directories
for Tcl Modules, and have to extract the metadata itself as well.

## Deployment

The fact that a Tcl Module consists only of a single file makes its
deployment quite easy.  We only have to ensure correct placement in
one of the searched directories when installing it locally, but
nothing more.

Regarding the usage of Tcl Modules in a wrapped application, please see
[[190]](190.md) "Implementation Choices for Tcl Modules".  This is highly
dependent on the implementation chosen for a specific Tcl Module and
thus not discussed here, but in the referred document.

## Package Repositories

At a very basic level, the physical storage, any directory tree
containing properly placed files for a number of modules can serve as
a package repository for the modules in it.  In other words, from that
point of view an installation is virtually indistinguishable from a
repository, and their creation and maintenance is very easy

Note however that the higher levels of a repository, like indexing
package metadata in general, or dependence tracking in particular,
licensing, documentation, etc. are not addressed here and by this.

This requires standards for package metadata, format and content,
topics with which this document will not deal.

## Defaults

The default list of paths on the module path is computed by a tclsh as
follows, where _X_ is the major version of the Tcl interpreter and
_y_ is less than or equal to the minor version of the Tcl
interpreter.

 * System specific paths

	 > \* **file normalize** [**info library**]/../tcl_X_/_X_._y_

	 > > In other words, the interpreter will look into a directory
     specified by its major version and whose minor versions are less
     than or equal to the minor version of the interpreter.

	 > > Example: For Tcl 8.4 the paths searched are

	 > > \* [**info library**]/../tcl8/8.4

	 > > \* [**info library**]/../tcl8/8.3

	 > > \* [**info library**]/../tcl8/8.2

	 > > \* [**info library**]/../tcl8/8.1

	 > > \* [**info library**]/../tcl8/8.0

	 > > This definition assumes that a package defined for Tcl _X.y_ can
     also be used by all interpreters which have the same major number
     _X_ and a minor number greater than _y_.

	 > \* **file normalize** _EXEC_/tcl_X_/_X_._y_

	 > > Where _EXEC_ is [**file normalize** [**info
     nameofexecutable**]/../lib] or [**file normalize**
     [**::tcl::pkgconfig get** libdir,runtime]]

	 > > This sets of paths is handled equivalently to the set coming
     before, except that it is anchored in _EXEC\_PREFIX_.  For a
     build with _PREFIX_ = _EXEC\_PREFIX_ the two sets are
     identical.

 * Site specific paths.

	 > \* **file normalize** [**info library**]/../tcl_X_/site-tcl

 * User specific paths.

	 > \* **$::env**\(TCL_X_._y_\_TM\_PATH\)

	 > > A list of paths, separated by either **:** \(Unix\) or **;**
     \(Windows\).  This is user and site specific as this environment
     variable can be set not only by the user's profile, but by system
     configuration scripts as well.

	 > > These paths are seen and therefore shared by all Tcl shells in
     the **$::env**\(PATH\) of the user.

	 > > Note that _X_ and _y_ follow the general rules set out above.
     In other words, Tcl 8.4, for example, will look at these 5
     environment variables

	 > > \* **$::env**\(TCL8.4\_TM\_PATH\)

	 > > \* **$::env**\(TCL8.3\_TM\_PATH\)

	 > > \* **$::env**\(TCL8.2\_TM\_PATH\)

	 > > \* **$::env**\(TCL8.1\_TM\_PATH\)

	 > > \* **$::env**\(TCL8.0\_TM\_PATH\)

_All_ the default paths are added to the module path, even those
paths which do not exist.  Non-existent paths are filtered out during
actual searches.  This enables a user to create one of the paths
searched when needed and all running applications will automatically
pick up any modules placed in them.

The paths are added in the order as they are listed above, and for
lists of paths defined by an environment variable in the order they
are found in the variable.

## Installation

The installation of a Tcl module for a particular interpreter is
basically done like this:

	 #! /path/to/chosen/tclsh
	 # First argument is the name of the module.
	 # Second argument is the base filename
	 set mpaths [::tcl::tm::path list]
	 ... remove all paths the user has no write permissions for.
	 ... throw an error if there are no paths left.
	 ... provide the user with some UI if more than one path is left
	 ... so that she can select the path to use.
	 set selmpath [ui_select $mpaths]
	 file copy [lindex $argv 1] \
	     [file join $selmpath \
	     [file dirname [string map {:: /} \
	     [lindex $argv 0]]]]

# Glossary

The following terms and definitions are used throughout the document

 * _index script_

	 > A script used to index a package, or not.  Usually contained in a
   file named "_pkgIndex.tcl_".  Can check preconditions for a
   package and contains package specific code for setting up the
   package specific _provide script_.

 * _provide script_

	 > This is a package specific script and tells Tcl exactly how to
   import it.  In the existing package system it is generated and
   registered by the _index script_.  Tcl Modules on the other hand
   generates it based on information gleaned from filenames.

# Reference Implementation

A reference implementation is available in Patch 942881
<http://sf.net/tracker/?func=detail&aid=942881&group_id=10894&atid=310894> 

# Questions

# Comments

[ Add comments on the document here ]

A feature asked for during discussion is to allow a directory as
a Tcl Module. I am opposed to this, because behind Tcl Modules is
the same idea/vision as for starkit and starpacks, namely that of
deploying something in the simplest possible manner, without any
overhead. Sometimes I call Tcl Modules package kits, short pakits
\(and then twist that then spoken into 'packet' :\).
<http://groups.google.ca/groups?hl=en&lr=&ie=UTF-8&frame=right&th=78764d499cc4e4a&seekm=c6tshf030c6%40news4.newsguy.com#link19> 

# Copyright

This document has been placed in the public domain.

Name change from tip/19.tip to tip/19.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

TIP:		19
Title:		Add a Text Changed Flag to Tk's Text Widget
Version:	$Revision: 1.6 $
Author:		Neil McKay <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	03-Jan-2001
Tcl-Version:	8.4a2
Obsoleted-By:	26
Post-History:


~Abstract

This TIP adds a ''text changed'' flag to the Tk text widget.  The flag
would initially be reset, but would be set whenever the contents of
the text widget changes.

~Rationale

When creating a text editor, it is often useful to know when the
contents of the edit buffer have changed, e.g. in order to ask the
user whether or not to save changes on exit. It is possible to create
key bindings in Tk's text widget that will set a flag whenever the
user changes the widget's contents; however, this is awkward, and it
still requires that the programmer set the flag whenever text is
changed programmatically.  A better solution is to include a ''text
changed'' flag in the code for the text widget itself; this can be
accomplished with a relatively small amount of code.

~Flag Behavior

The ''text changed'' flag should behave as follows:

 * It should be reset when the text widget is created

 * It should be set whenever characters are inserted into or deleted
   from the widget

 * It must be resettable programmatically via a Tcl command

~Reference Implementation

At the Tcl level, one possible implementation is to add a ''changed''
widget command to the text widget. One possible syntax for this
command is:

|    .txt changed ?boolean?

where .txt is a text widget.  With no ''boolean'' argument, the
command returns the state of the text-changed flag; with an argument,
it sets the state of the text-changed flag to the value of the
argument.

~Example

A typical sequence of commands in a text editor would be

 1. Create a text widget

 2. Read a file and put its contents into the text widget

 3. Mark the text as unchanged

 4. Edit the text

 5. Write the text out, if it has changed.

This could be accomplished by the following Tcl code fragment:

| grid [button .b -text Quit -command EndEdit]
| grid [text .t]
|
| proc EndEdit {} {
|     if {[.t changed]} {
|         set result [tk_messageBox -type yesno -message "Save changes?"]
|         if {[string compare $result "yes"] == 0} {
|             set fh [open $fileName "w"]
|             puts -nonewline $fh [.t get 1.0 end-1c]
|             close $fh
|         }
|     }


|     exit
| }

|
| set fh [open $fileName "r"]
| .t insert end [read $fh]
| close $fh
| .t changed false

~Copyright

This document is in the public domain.

~Patch

The ''changed'' text widget command, as described above, may be added
to Tk8.4a2 by applying the patch at
http://www.cs.man.ac.uk/fellowsd-bin/TIP/19.patch

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|







|
|


|

|








|

|



|

|




|















|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
<
>
|
|
|
|
|

|



|

|

|
>

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

# TIP 19: Add a Text Changed Flag to Tk's Text Widget

	Author:		Neil McKay <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	03-Jan-2001
	Tcl-Version:	8.4a2
	Obsoleted-By:	26
	Post-History:
-----

# Abstract

This TIP adds a _text changed_ flag to the Tk text widget.  The flag
would initially be reset, but would be set whenever the contents of
the text widget changes.

# Rationale

When creating a text editor, it is often useful to know when the
contents of the edit buffer have changed, e.g. in order to ask the
user whether or not to save changes on exit. It is possible to create
key bindings in Tk's text widget that will set a flag whenever the
user changes the widget's contents; however, this is awkward, and it
still requires that the programmer set the flag whenever text is
changed programmatically.  A better solution is to include a _text
changed_ flag in the code for the text widget itself; this can be
accomplished with a relatively small amount of code.

# Flag Behavior

The _text changed_ flag should behave as follows:

 * It should be reset when the text widget is created

 * It should be set whenever characters are inserted into or deleted
   from the widget

 * It must be resettable programmatically via a Tcl command

# Reference Implementation

At the Tcl level, one possible implementation is to add a _changed_
widget command to the text widget. One possible syntax for this
command is:

	    .txt changed ?boolean?

where .txt is a text widget.  With no _boolean_ argument, the
command returns the state of the text-changed flag; with an argument,
it sets the state of the text-changed flag to the value of the
argument.

# Example

A typical sequence of commands in a text editor would be

 1. Create a text widget

 2. Read a file and put its contents into the text widget

 3. Mark the text as unchanged

 4. Edit the text

 5. Write the text out, if it has changed.

This could be accomplished by the following Tcl code fragment:

	 grid [button .b -text Quit -command EndEdit]
	 grid [text .t]
	
	 proc EndEdit {} {
	     if {[.t changed]} {
	         set result [tk_messageBox -type yesno -message "Save changes?"]
	         if {[string compare $result "yes"] == 0} {
	             set fh [open $fileName "w"]
	             puts -nonewline $fh [.t get 1.0 end-1c]
	             close $fh


	         }
	     }
	     exit

	 }
	
	 set fh [open $fileName "r"]
	 .t insert end [read $fh]
	 close $fh
	 .t changed false

# Copyright

This document is in the public domain.

# Patch

The _changed_ text widget command, as described above, may be added
to Tk8.4a2 by applying the patch at
<http://www.cs.man.ac.uk/fellowsd-bin/TIP/19.patch>

Name change from tip/190.tip to tip/190.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
TIP:            190
Title:          Implementation Choices for Tcl Modules
Version:        $Revision: 1.3 $
Author:         Andreas Kupries <[email protected]>
Author:         Jean-Claude Wippler <[email protected]>
Author:         Jeff Hobbs <[email protected]>
State:          Draft
Type:           Informative
Vote:           Pending
Created:        24-Mar-2004
Post-History:   


~ Abstract

This document is an informational adjunct to [189] "Tcl Modules",
describing a number of choices for the implementation of Tcl Modules,
pure-Tcl, binary, or mixed.  It lists these choices and then discusses
their relative merits and problems, especially their interaction with
wrapping, i.e. when used in a wrapped application.  The main point of
the document is to dispel the illusion that the restriction to the
"source" command for the loading Tcl Modules is an actual limitation.
A secondary point is to make recommendations regarding preferred
implementations, based the merits and weaknesses of the various
possibilities.

~ Implementation Choices

A small recap first: Tcl Modules are Packages in a single file, and
only '''source''' is used to import them into the running interpreter.
These restrictions are the backdrop to all implementations discussed
here.

~~ Packages Written in Tcl

These are easy.

 * A package which is implemented in a single file is already in the
   form required for a Tcl Module and nothing has to be done at all.

|   +--------------+
|   | Tcl File     |
|   +--------------+

 > Most packages in Tcllib[http://tcllib.sf.net] can be of this form.

 * In the case of a package whose implementation is spread over
   multiple .tcl files the solution is equally simple.  Just
   concatenate all the files into one file when generating the
   distribution.  This is a trivial operation.

|   +--------------++--------------+...+--------------+
|   | Tcl File 1      Tcl File 2         Tcl File n   |
|   +--------------++--------------+...+--------------+

 > Some packages in Tcllib[http://tcllib.sf.net] can be of this form,
   or rewritten into it.

 * The usage of an compiler/obfuscater like TclPro/Tcl Dev Kit on such
   Tcl Modules is also no problem.  While the result of these
   compilers contains binary, it is in encoded form, and the file is
   still a proper Tcl script which can be handled by '''source'''.
   The encoded binary is decoded by an adjunct package, '''tbcload''',
   whose import is the first action done by the script.

 > This also points us already to the general solution for binary
   packages, i.e. usage of supporting packages to handle arbitrary
   data embedded or attached in some way in/to an initialization
   script.

The usage of pure-Tcl Modules within wrapped applications poses no
problems at all.

Also note that all of the choices available to binary packages, as
explained in the next section, are available to pure-Tcl packages as
well.

~ Binary Packages

A binary package consists of a shared library, possibly with adjunct
Tcl and data files.  These have to be bundled into a single file to be
a Tcl Module.

The general approach to this is to combine an init script written in
Tcl with binary data attached to it, both sections separated by a ^Z
character.  This is possible since 8.4, where '''source''' was changed
to read only up to the first ^Z and ignore the remainder of the file,
whereas other '''file''' and channel operations will see it.

~~ Embedding a Virtual Filesystem

The most obvious way of doing this is the any-kit approach: a small
initialization script in front which loads all required supporting
packages and then uses them to mount an attached virtual filesystem
containing all the other files.  After the mount any package specific
initialization can be performed, either in the initialization script
itself, or in a separate script file stored in filesystem.  The latter
is the recommended form as it keeps the main initialization script
small and package neutral i.e. it will be only filesystem specific,
and not package specific.  These two tasks are kept separate, which is
good design in general, and becomes more important later on as well.

|   +-------------||------------------------------------+
|   | Init header ^Z VFS +------------+ +-----...-----+ |
|   |             ^Z     | Shared lib | | Other files | |
|   |             ^Z     +------------+ +-----...-----+ |
|   +-------------||------------------------------------+

A concrete example of this are starkits, except that they use this
technique to wrap an application into a single file, and not a
package.

When interacting with wrapping this approach runs into problems.  It
is not possible to simply copy the module file into the wrapped
application and then use it.  The problem is a limitation in most
implementations of alternate filesystem: they are not able to mount a
virtual file again as a directory, i.e. ''nested'' mounting.  This
however is required when a Tcl Module using the any-kit approach is
placed into a wrapped application.  It was thought for a while that
this could be a limitation in the VFS core of Tcl itself, but further investigation proved this to be wrong. This proof came in the form of TROFS, the ''Tcl Read Only Filesystem'', by Don Porter. This filesystem supports nesting and thus shows that the Tcl core is strong enough for this as well. It is the implementation of a filesystem which determines if nesting is possible or not, and most do not support this.

See also SF bug report ''[[941872]] path<->FS function limitations''
[http://sf.net/tracker/?func=detail&aid=941872&group_id=10894&atid=110894]
for more details on this and other problems.

There are two ways to work around this limitation, while it exists.
These are explained below.  However note that even if the limitation
is removed we may still run into performance problems because of a
file accessed through several layers of file systems, each with its
own overhead.  The workarounds we are about to discuss will help with
<
|
<
|
|
|
|
|
|
|
|
>

|

|










|


|



|






|
|
|

|






|
|
|

|





|
|


|











|







|

|

|












|
|
|
|
|









|


|

|
|








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

# TIP 190: Implementation Choices for Tcl Modules

	Author:         Andreas Kupries <[email protected]>
	Author:         Jean-Claude Wippler <[email protected]>
	Author:         Jeff Hobbs <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        24-Mar-2004
	Post-History:   
-----

# Abstract

This document is an informational adjunct to [[189]](189.md) "Tcl Modules",
describing a number of choices for the implementation of Tcl Modules,
pure-Tcl, binary, or mixed.  It lists these choices and then discusses
their relative merits and problems, especially their interaction with
wrapping, i.e. when used in a wrapped application.  The main point of
the document is to dispel the illusion that the restriction to the
"source" command for the loading Tcl Modules is an actual limitation.
A secondary point is to make recommendations regarding preferred
implementations, based the merits and weaknesses of the various
possibilities.

# Implementation Choices

A small recap first: Tcl Modules are Packages in a single file, and
only **source** is used to import them into the running interpreter.
These restrictions are the backdrop to all implementations discussed
here.

## Packages Written in Tcl

These are easy.

 * A package which is implemented in a single file is already in the
   form required for a Tcl Module and nothing has to be done at all.

		   +--------------+
		   | Tcl File     |
		   +--------------+

	 > Most packages in Tcllib<http://tcllib.sf.net>  can be of this form.

 * In the case of a package whose implementation is spread over
   multiple .tcl files the solution is equally simple.  Just
   concatenate all the files into one file when generating the
   distribution.  This is a trivial operation.

		   +--------------++--------------+...+--------------+
		   | Tcl File 1      Tcl File 2         Tcl File n   |
		   +--------------++--------------+...+--------------+

	 > Some packages in Tcllib<http://tcllib.sf.net>  can be of this form,
   or rewritten into it.

 * The usage of an compiler/obfuscater like TclPro/Tcl Dev Kit on such
   Tcl Modules is also no problem.  While the result of these
   compilers contains binary, it is in encoded form, and the file is
   still a proper Tcl script which can be handled by **source**.
   The encoded binary is decoded by an adjunct package, **tbcload**,
   whose import is the first action done by the script.

	 > This also points us already to the general solution for binary
   packages, i.e. usage of supporting packages to handle arbitrary
   data embedded or attached in some way in/to an initialization
   script.

The usage of pure-Tcl Modules within wrapped applications poses no
problems at all.

Also note that all of the choices available to binary packages, as
explained in the next section, are available to pure-Tcl packages as
well.

# Binary Packages

A binary package consists of a shared library, possibly with adjunct
Tcl and data files.  These have to be bundled into a single file to be
a Tcl Module.

The general approach to this is to combine an init script written in
Tcl with binary data attached to it, both sections separated by a ^Z
character.  This is possible since 8.4, where **source** was changed
to read only up to the first ^Z and ignore the remainder of the file,
whereas other **file** and channel operations will see it.

## Embedding a Virtual Filesystem

The most obvious way of doing this is the any-kit approach: a small
initialization script in front which loads all required supporting
packages and then uses them to mount an attached virtual filesystem
containing all the other files.  After the mount any package specific
initialization can be performed, either in the initialization script
itself, or in a separate script file stored in filesystem.  The latter
is the recommended form as it keeps the main initialization script
small and package neutral i.e. it will be only filesystem specific,
and not package specific.  These two tasks are kept separate, which is
good design in general, and becomes more important later on as well.

	   +-------------||------------------------------------+
	   | Init header ^Z VFS +------------+ +-----...-----+ |
	   |             ^Z     | Shared lib | | Other files | |
	   |             ^Z     +------------+ +-----...-----+ |
	   +-------------||------------------------------------+

A concrete example of this are starkits, except that they use this
technique to wrap an application into a single file, and not a
package.

When interacting with wrapping this approach runs into problems.  It
is not possible to simply copy the module file into the wrapped
application and then use it.  The problem is a limitation in most
implementations of alternate filesystem: they are not able to mount a
virtual file again as a directory, i.e. _nested_ mounting.  This
however is required when a Tcl Module using the any-kit approach is
placed into a wrapped application.  It was thought for a while that
this could be a limitation in the VFS core of Tcl itself, but further investigation proved this to be wrong. This proof came in the form of TROFS, the _Tcl Read Only Filesystem_, by Don Porter. This filesystem supports nesting and thus shows that the Tcl core is strong enough for this as well. It is the implementation of a filesystem which determines if nesting is possible or not, and most do not support this.

See also SF bug report _[[941872]](941872.md) path<->FS function limitations_
<http://sf.net/tracker/?func=detail&aid=941872&group_id=10894&atid=110894> 
for more details on this and other problems.

There are two ways to work around this limitation, while it exists.
These are explained below.  However note that even if the limitation
is removed we may still run into performance problems because of a
file accessed through several layers of file systems, each with its
own overhead.  The workarounds we are about to discuss will help with
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235

   the necessary scripts, like "pkgIndex.tcl".  Here the separation of
   filesystem specific from package specific initialization comes into
   play as well as it makes the unbundling much easier.  The generated
   package index file can simply refer to the same package
   initialization script as the filesystem specific header of the
   bundled module.

 > It should be noted that unbundling is limited to the filesystems
   which are recognized by the wrapper application.  Because of this a
   combination of this and the previous approach might be best, as it
   allows the module to function even if the wrapper application was
   not able to unbundle it.

More a problem of taste might be that Tcl Modules in this form require
additional packages which implement the filesystem they use.  This can
be remedied in the future by adding additional reflection capabilities
to the Tcl core which would allow the implementation of channel
drivers, channels transformations, and filesystems in pure Tcl, and
then implementing simple filesystems based on that.  This would also
allow the Tcl core itself to make use of filesystems attached to its
shared libraries and executables.

~~ Appending a Shared Library

Should the binary package consist of only one shared library we can
forgo the use of a full-blown virtual filesystem and simply attach the
shared library to the init script as is.  Instead of mounting anything
the init script just has to copy the library to a temporary place and
then "load" it.

|   +------------------------------||----------------+
|   | Init script (p name, p size) ^Z Shared library |
|   +------------------------------||----------------+

Tcl Modules implemented in this way will have no problems when used in
a wrapped application as they will always copy their relevant file to
the native filesystem before using it.

The disadvantage is that this is not a very general scheme.  There are
not that much packages which consist of only one shared library and
nothing else.

Note: Should we ever get loading of a shared library directly from
memory or from a location in another file, then copying the library to
the filesystem won't be necessary anymore either.

~~ Appending a Library and a VFS

An extension of the last approach is to attach the virtual file system
not to the init script, but the shared library.

|   +-------------||----------------++---------------------+
|   | Init script ^Z Shared library // VFS +-----...-----+ |
|   |             ^Z                //     | Other files | |
|   |             ^Z                //     +-----...-----+ |
|   +-------------||----------------++---------------------+

This approach has the same advantages as the last with regard to its
interaction with wrapping, i.e no problems, and additionally handles
additional files coming with the shared library.  The initialization
of the VFS happens in the init script, but after the shared library
has been loaded.

I have to admit that I am not sure if this will truly work.  In
essence the library will have to be told about the directory for its
files after its C level initialization has been run.

If the VFS is required during the C level initialization then the VFS
has to be initialized and mounted from within the shared library,
i.e. at the C level.  This is not very convenient as we need an
embedded Tcl script for this, and that makes the code of the library
more complicated than required.

~ Recommendations

We currently recommend usage of the any-kit approach for binary
packages, despite its problem with nested mounting.  This approach has
an existing implementation in the metakit-based starkits and is thus
well tested in general.  The other two approaches are currently purely
theoretical, with neither any implementation, nor testing.

Regarding Tcl packages no recommendation is necessary as we have in
essence only one possibility for the more complex case, the simple
concatenation of multiple files into a single one.

~ Questions

~ Comments

[[ Add comments on the document here ]]

~ Copyright

This document has been placed in the public domain.








|














|







|
|
|













|




|
|
|
|
|

















|











|

|

|

|


>
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
   the necessary scripts, like "pkgIndex.tcl".  Here the separation of
   filesystem specific from package specific initialization comes into
   play as well as it makes the unbundling much easier.  The generated
   package index file can simply refer to the same package
   initialization script as the filesystem specific header of the
   bundled module.

	 > It should be noted that unbundling is limited to the filesystems
   which are recognized by the wrapper application.  Because of this a
   combination of this and the previous approach might be best, as it
   allows the module to function even if the wrapper application was
   not able to unbundle it.

More a problem of taste might be that Tcl Modules in this form require
additional packages which implement the filesystem they use.  This can
be remedied in the future by adding additional reflection capabilities
to the Tcl core which would allow the implementation of channel
drivers, channels transformations, and filesystems in pure Tcl, and
then implementing simple filesystems based on that.  This would also
allow the Tcl core itself to make use of filesystems attached to its
shared libraries and executables.

## Appending a Shared Library

Should the binary package consist of only one shared library we can
forgo the use of a full-blown virtual filesystem and simply attach the
shared library to the init script as is.  Instead of mounting anything
the init script just has to copy the library to a temporary place and
then "load" it.

	   +------------------------------||----------------+
	   | Init script (p name, p size) ^Z Shared library |
	   +------------------------------||----------------+

Tcl Modules implemented in this way will have no problems when used in
a wrapped application as they will always copy their relevant file to
the native filesystem before using it.

The disadvantage is that this is not a very general scheme.  There are
not that much packages which consist of only one shared library and
nothing else.

Note: Should we ever get loading of a shared library directly from
memory or from a location in another file, then copying the library to
the filesystem won't be necessary anymore either.

## Appending a Library and a VFS

An extension of the last approach is to attach the virtual file system
not to the init script, but the shared library.

	   +-------------||----------------++---------------------+
	   | Init script ^Z Shared library // VFS +-----...-----+ |
	   |             ^Z                //     | Other files | |
	   |             ^Z                //     +-----...-----+ |
	   +-------------||----------------++---------------------+

This approach has the same advantages as the last with regard to its
interaction with wrapping, i.e no problems, and additionally handles
additional files coming with the shared library.  The initialization
of the VFS happens in the init script, but after the shared library
has been loaded.

I have to admit that I am not sure if this will truly work.  In
essence the library will have to be told about the directory for its
files after its C level initialization has been run.

If the VFS is required during the C level initialization then the VFS
has to be initialized and mounted from within the shared library,
i.e. at the C level.  This is not very convenient as we need an
embedded Tcl script for this, and that makes the code of the library
more complicated than required.

# Recommendations

We currently recommend usage of the any-kit approach for binary
packages, despite its problem with nested mounting.  This approach has
an existing implementation in the metakit-based starkits and is thus
well tested in general.  The other two approaches are currently purely
theoretical, with neither any implementation, nor testing.

Regarding Tcl packages no recommendation is necessary as we have in
essence only one possibility for the more complex case, the simple
concatenation of multiple files into a single one.

# Questions

# Comments

[ Add comments on the document here ]

# Copyright

This document has been placed in the public domain.

Name change from tip/191.tip to tip/191.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
TIP:            191
Title:          Managing Tcl Packages and Modules in a Multi-Version Environment
Version:        $Revision: 1.3 $
Author:         Andreas Kupries <[email protected]>
Author:         Joe English <[email protected]>
Author:         Larry Virden <[email protected]>
State:          Draft
Type:           Informative
Vote:           Pending
Created:        24-Mar-2004
Post-History:   


~ Abstract

This document is an informational adjunct to [189] "Tcl Modules",
describing a number of choices for the management of Tcl Modules in
environments with more than one version of the Tcl core installed.  It
lists these choices and then discusses their relative merits and
problems.

~ Background and Motivation

A regular package can perform checks in its "pkgIndex.tcl" file
regarding the environment the package would be loaded into should it
be requested, and make the creation of its "provide script" dependent
on the result.  In other words, it is able to prevent its
registration, making it invisible to the Tcl interpreter in question
if the environment is not right (for example, if the interpreter is too old a version of Tcl).

A Tcl module cannot do this as its "provide script" is generated by
the module system.

In a controlled environment, like wrapped applications of any form
this is a complete non-issue as we can assume that only those modules
are installed which are not only required, but needed.
<
|
<
|
|
|
|
|
|
|
|
>

|

|





|






|








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

# TIP 191: Managing Tcl Packages and Modules in a Multi-Version Environment

	Author:         Andreas Kupries <[email protected]>
	Author:         Joe English <[email protected]>
	Author:         Larry Virden <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        24-Mar-2004
	Post-History:   
-----

# Abstract

This document is an informational adjunct to [[189]](189.md) "Tcl Modules",
describing a number of choices for the management of Tcl Modules in
environments with more than one version of the Tcl core installed.  It
lists these choices and then discusses their relative merits and
problems.

# Background and Motivation

A regular package can perform checks in its "pkgIndex.tcl" file
regarding the environment the package would be loaded into should it
be requested, and make the creation of its "provide script" dependent
on the result.  In other words, it is able to prevent its
registration, making it invisible to the Tcl interpreter in question
if the environment is not right \(for example, if the interpreter is too old a version of Tcl\).

A Tcl module cannot do this as its "provide script" is generated by
the module system.

In a controlled environment, like wrapped applications of any form
this is a complete non-issue as we can assume that only those modules
are installed which are not only required, but needed.
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

version may not work anymore with the new version, or a different
version of the package has to be selected from among the installed
versions.  This situation can be viewed as having multiple version of Tcl, however over time instead of space.

For the environments with multiple versions of Tcl in space a number
of possible solutions are explained in the next section.

~ Choices

All solutions are done outside of the Tcl interpreter, in the
filesystem.

 * Each interpreter has its own part of the filesystem.  Modules
   required in several of them are copied around.  Modules not
   required are not copied.  This is easy.  It requires
   more disk space; however that is cheap.

 * Same as above, but use hard- and/or soft-links instead of copying.
   Modules not eligible somewhere are not linked.

 > This schema can also be used to maintain a central repository,
   which is just a directory tree containing all module files in their
   proper locations.  Then link the packages which should be visible
   to an interpreter into their respective directory trees.

 > This makes the creation of test environments with a known set
   of packages very easy as well.

 * Keep the modules in several directory trees as wanted and/or needed
   by sharing requirements and then set the list of search paths used
   by an interpreter to exactly those trees which have the modules
   required/usable by it.

~~ Changes over Time

Note that the default paths set down in [189] ease the management, as
each Tcl shell will not only have its own space, but also access to
extensions for all minor versions which came before it.  This means
that placing an extension into the directory for the smallest version
of Tcl supporting it will make this extension available to this minor
version and all the versions which come after and share the major
version.  This is the right thing almost all of the time.

Only extensions using internal interfaces will have to be dealt with
separately.

~ Questions

~ Comments

[[ Add comments on the document here ]]

According to Don Porter the given solutions will not scale.

~ Copyright

This document has been placed in the public domain.








|












|




|







|

|










|

|

|



|


>
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
version may not work anymore with the new version, or a different
version of the package has to be selected from among the installed
versions.  This situation can be viewed as having multiple version of Tcl, however over time instead of space.

For the environments with multiple versions of Tcl in space a number
of possible solutions are explained in the next section.

# Choices

All solutions are done outside of the Tcl interpreter, in the
filesystem.

 * Each interpreter has its own part of the filesystem.  Modules
   required in several of them are copied around.  Modules not
   required are not copied.  This is easy.  It requires
   more disk space; however that is cheap.

 * Same as above, but use hard- and/or soft-links instead of copying.
   Modules not eligible somewhere are not linked.

	 > This schema can also be used to maintain a central repository,
   which is just a directory tree containing all module files in their
   proper locations.  Then link the packages which should be visible
   to an interpreter into their respective directory trees.

	 > This makes the creation of test environments with a known set
   of packages very easy as well.

 * Keep the modules in several directory trees as wanted and/or needed
   by sharing requirements and then set the list of search paths used
   by an interpreter to exactly those trees which have the modules
   required/usable by it.

## Changes over Time

Note that the default paths set down in [[189]](189.md) ease the management, as
each Tcl shell will not only have its own space, but also access to
extensions for all minor versions which came before it.  This means
that placing an extension into the directory for the smallest version
of Tcl supporting it will make this extension available to this minor
version and all the versions which come after and share the major
version.  This is the right thing almost all of the time.

Only extensions using internal interfaces will have to be dealt with
separately.

# Questions

# Comments

[ Add comments on the document here ]

According to Don Porter the given solutions will not scale.

# Copyright

This document has been placed in the public domain.

Name change from tip/192.tip to tip/192.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182

TIP:            192
Title:          Lazy Lists
Version:        $Revision: 1.2 $
Author:         Salvatore Sanfilippo <[email protected]>
Author:         Theo Verelst <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        27-Mar-2004
Post-History:   
Keywords:       Tcl
Tcl-Version:    9.0


~ Abstract

This TIP proposes to add a new command to generate lists of ''N''
elements, where the ''i''-th element is computed as the result of
an unary Tcl procedure with ''i'' as itsargument. Implementing special
handling for this kind of lists inside the Tcl core will allow
generation of lists in a ''lazy'' way.  This TIP's goal is not to
change the semantics of Tcl, but just to provide a different space
complexity for an (often interesting) subset of Tcl lists.

~ Rationale

A subset of Tcl lists can be generated mapping an unary function to an
integer sequence in the range [[0,n), where ''n'' is the length of the
list. The following procedure implements this concept:

|proc lgen {len func} {
|    set l {}
|    for {set i 0} {$i < $len} {incr i} {
|        lappend l [uplevel 1 [list $func $i]]
|    }

|    return $l
|}

and the following (using the '''lambda''' from [187]) is an example of

usage:

|proc lambda {argl body} {
|    set name [info level 0]
|    proc $name $argl $body
|    set name
|}

|
|set mylist [lgen 10 [lambda x {incr x; expr $x*$x}]]

The above code will evaluate to the same as [[list 1 4 9 16 25 36 49
64 81 100]].  '''lgen''' can be used in order to build a particularly
useful Tcl procedure named '''range''', returning a sequence of
integers with given ''start'' ''end'' and (optionally) ''step''
paramenters. The '''range''' function is convenient for rewriting many
'''for''' loops in terms of '''foreach''' iterating over an integer
range. So instead of writing:

|for {set i 0} {$i < 20} {incr i 2} {
|    puts $i
|}


It is possible to write:

|foreach i [range 0 20 2] {
|    puts $i
|}


That is more convenient to write and to read for the programmer.  Of
course it's possible to use '''foreach''' to iterate any sequence that
'''lgen''' is able to generate, but '''range''' is probably one of the
more common of the possible usages.

The TIP proposes to implement the ability to handle this kind of lists
in a special way directly inside the ''List'' object implementation.
This allows these common usage patterns of the list object to not need
to hold the real sequence but just the length and the unary element
generator function.

The interface to the Tcl programmer is a single command similar in
semantics to '''lgen''', but possibly with a more suitable name.

~ Proposed Change

The ''List'' object should be modified in order to have the lazy-list
as subtype or alternate internal implementation. All the core should
use the proper ''List'' object API instead to access to the ''List''
object via the internal representation.

The two calls that should be guaranteed to not alter the ''lazyness''
of the list are '''Tcl_ListObjLength()''' and
'''Tcl_ListObjIndex()'''.  Other calls like '''Tcl_ListObjReplace()'''
may be optimized for the lazy-list case when possible, and the
'''lrange''' command may be optimized (particularly when the start
index is zero).

The ''List'' will be converted into a non-lazy version if the user
tries to modify it, for example using the
'''Tcl_ListObjAppendElement()''' function. The ''List'' will also be
converted into a non-lazy version on '''Tcl_ListObjGetElements()'''
calls.

It's possible to handle the '''range''' command as a particular case
of lazy-list in order to provide a very fast implementation of foreach
iterating over an integer range (probably much faster than the today
'''for''', being '''foreach''' already faster iterating over a literal
list of numbers).

~~ Consequences: Reference Management

The author of this TIP tried to implement the proposed changes in the
HEAD, discovering that the '''Tcl_ListObjIndex()''' interface creates
a serious problem due to the assumption that the ''List'' object holds
at least one reference to the returned element. The implementation of
'''Tcl_ListObjIndex()''' in the lazy case can't just create the
element object and return it with refcount of zero because it will
leak if the caller does not increment the reference count itself.

It's also not safe to store a reference to the last few elements
created in the lazy way inside the ''List'' object, and release this
references in order to create more elements, because in theory the
caller may require a large number of elements storing pointers into an
array, and finally incrementing the reference counts in a single pass.

In order to avoid this problem, the semantics of
'''Tcl_ListObjIndex()''' should be changed in order to always return
the element with an already incremented reference count. It will be up
to the caller to decrement the reference count if the object will be
discarded.  (This is why this change is proposed for Tcl 9.0 and not
8.5, as this has a significant impact on both the core and on
extensions.)

An alternative change to '''Tcl_ListObjIndex()''' (in order to make it
"compatible" with the semantics of lazy lists) is to disallow
successive calls against the same list if a previous call returned an
object that the caller plans to reference the object.

So:

|Tcl_ListObjIndex(interp, myListPtr, 0, &a);
|Tcl_ListObjIndex(interp, myListPtr, 0, &b);
|mystruct->a = a;
|mystruct->b = b;
|Tcl_IncrRefCount(a);
|Tcl_IncrRefCount(b);

will be invalid, while:

|Tcl_ListObjIndex(interp, myListPtr, 0, &a);
|Tcl_IncrRefCount(a);
|mystruct->a = a;
|Tcl_ListObjIndex(interp, myListPtr, 0, &b);
|Tcl_IncrRefCount(b);
|mystruct->b = b;

is valid. This fixes any problem because the ''List'' object can just
take a reference to the last generated object and avoid any leak.  A
study of existing code in the core and extensions is required to see
whether this will allow the majority of code to operate unchanged.

~~ Consequences: Non-constant Lists

The TIP also poses another problem in the case the unary function has
side effects. In this case the behaviour can be described without to
violate the Tcl semantic in terms of variable traces most of the time,
but actually it's possible to write code that shows that the list
value is non-stable even without using variables (because Tcl has no
"object trace" concept actually).

If this is considered a problem, the TIP may be reduced in order to
only allow lazy generated lists composed of integer ranges, (but that
is one of the most interesting advantages of this TIP anyway.)  With
integer ranges there are no side effects, so the semantical problem is
not an issue, but the '''Tcl_ListObjIndex()''' problem is exactly the
same.

Of course, this is arguably just an unavoidable consequence and shows
that not all possible unary element generator functions, but just
those with a functional denotation, are necessarily reasonable
choices.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|
|
|

|

|

|


|


|
|
|
|
<
>
|
<
|
|
>


|
|
|
|
<
>
|
|

|
|
|
|
|
|


|
|
<
>



|
|
<
|
>

|
|



|





|

|

|

|


|
|
|

|
|

|

|
|


|

|
|
|

|


|
|

|




|





|


|

|

|
|





|
|
|
|
|
|



|
|
|
|
|
|

|




|





|
|


|
|

|







|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182

# TIP 192: Lazy Lists

	Author:         Salvatore Sanfilippo <[email protected]>
	Author:         Theo Verelst <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        27-Mar-2004
	Post-History:   
	Keywords:       Tcl
	Tcl-Version:    9.0
-----

# Abstract

This TIP proposes to add a new command to generate lists of _N_
elements, where the _i_-th element is computed as the result of
an unary Tcl procedure with _i_ as itsargument. Implementing special
handling for this kind of lists inside the Tcl core will allow
generation of lists in a _lazy_ way.  This TIP's goal is not to
change the semantics of Tcl, but just to provide a different space
complexity for an \(often interesting\) subset of Tcl lists.

# Rationale

A subset of Tcl lists can be generated mapping an unary function to an
integer sequence in the range [0,n\), where _n_ is the length of the
list. The following procedure implements this concept:

	proc lgen {len func} {
	    set l {}
	    for {set i 0} {$i < $len} {incr i} {
	        lappend l [uplevel 1 [list $func $i]]

	    }
	    return $l

	}

and the following \(using the **lambda** from [[187]](187.md)\) is an example of
usage:

	proc lambda {argl body} {
	    set name [info level 0]
	    proc $name $argl $body
	    set name

	}
	
	set mylist [lgen 10 [lambda x {incr x; expr $x*$x}]]

The above code will evaluate to the same as [list 1 4 9 16 25 36 49
64 81 100].  **lgen** can be used in order to build a particularly
useful Tcl procedure named **range**, returning a sequence of
integers with given _start_ _end_ and \(optionally\) _step_
paramenters. The **range** function is convenient for rewriting many
**for** loops in terms of **foreach** iterating over an integer
range. So instead of writing:

	for {set i 0} {$i < 20} {incr i 2} {
	    puts $i

	}

It is possible to write:

	foreach i [range 0 20 2] {
	    puts $i

	}

That is more convenient to write and to read for the programmer.  Of
course it's possible to use **foreach** to iterate any sequence that
**lgen** is able to generate, but **range** is probably one of the
more common of the possible usages.

The TIP proposes to implement the ability to handle this kind of lists
in a special way directly inside the _List_ object implementation.
This allows these common usage patterns of the list object to not need
to hold the real sequence but just the length and the unary element
generator function.

The interface to the Tcl programmer is a single command similar in
semantics to **lgen**, but possibly with a more suitable name.

# Proposed Change

The _List_ object should be modified in order to have the lazy-list
as subtype or alternate internal implementation. All the core should
use the proper _List_ object API instead to access to the _List_
object via the internal representation.

The two calls that should be guaranteed to not alter the _lazyness_
of the list are **Tcl\_ListObjLength\(\)** and
**Tcl\_ListObjIndex\(\)**.  Other calls like **Tcl\_ListObjReplace\(\)**
may be optimized for the lazy-list case when possible, and the
**lrange** command may be optimized \(particularly when the start
index is zero\).

The _List_ will be converted into a non-lazy version if the user
tries to modify it, for example using the
**Tcl\_ListObjAppendElement\(\)** function. The _List_ will also be
converted into a non-lazy version on **Tcl\_ListObjGetElements\(\)**
calls.

It's possible to handle the **range** command as a particular case
of lazy-list in order to provide a very fast implementation of foreach
iterating over an integer range \(probably much faster than the today
**for**, being **foreach** already faster iterating over a literal
list of numbers\).

## Consequences: Reference Management

The author of this TIP tried to implement the proposed changes in the
HEAD, discovering that the **Tcl\_ListObjIndex\(\)** interface creates
a serious problem due to the assumption that the _List_ object holds
at least one reference to the returned element. The implementation of
**Tcl\_ListObjIndex\(\)** in the lazy case can't just create the
element object and return it with refcount of zero because it will
leak if the caller does not increment the reference count itself.

It's also not safe to store a reference to the last few elements
created in the lazy way inside the _List_ object, and release this
references in order to create more elements, because in theory the
caller may require a large number of elements storing pointers into an
array, and finally incrementing the reference counts in a single pass.

In order to avoid this problem, the semantics of
**Tcl\_ListObjIndex\(\)** should be changed in order to always return
the element with an already incremented reference count. It will be up
to the caller to decrement the reference count if the object will be
discarded.  \(This is why this change is proposed for Tcl 9.0 and not
8.5, as this has a significant impact on both the core and on
extensions.\)

An alternative change to **Tcl\_ListObjIndex\(\)** \(in order to make it
"compatible" with the semantics of lazy lists\) is to disallow
successive calls against the same list if a previous call returned an
object that the caller plans to reference the object.

So:

	Tcl_ListObjIndex(interp, myListPtr, 0, &a);
	Tcl_ListObjIndex(interp, myListPtr, 0, &b);
	mystruct->a = a;
	mystruct->b = b;
	Tcl_IncrRefCount(a);
	Tcl_IncrRefCount(b);

will be invalid, while:

	Tcl_ListObjIndex(interp, myListPtr, 0, &a);
	Tcl_IncrRefCount(a);
	mystruct->a = a;
	Tcl_ListObjIndex(interp, myListPtr, 0, &b);
	Tcl_IncrRefCount(b);
	mystruct->b = b;

is valid. This fixes any problem because the _List_ object can just
take a reference to the last generated object and avoid any leak.  A
study of existing code in the core and extensions is required to see
whether this will allow the majority of code to operate unchanged.

## Consequences: Non-constant Lists

The TIP also poses another problem in the case the unary function has
side effects. In this case the behaviour can be described without to
violate the Tcl semantic in terms of variable traces most of the time,
but actually it's possible to write code that shows that the list
value is non-stable even without using variables \(because Tcl has no
"object trace" concept actually\).

If this is considered a problem, the TIP may be reduced in order to
only allow lazy generated lists composed of integer ranges, \(but that
is one of the most interesting advantages of this TIP anyway.\)  With
integer ranges there are no side effects, so the semantical problem is
not an issue, but the **Tcl\_ListObjIndex\(\)** problem is exactly the
same.

Of course, this is arguably just an unavoidable consequence and shows
that not all possible unary element generator functions, but just
those with a functional denotation, are necessarily reasonable
choices.

# Copyright

This document has been placed in the public domain.

Name change from tip/193.tip to tip/193.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

TIP:		193
Title:		Simple Syntax Help System
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Post-History:	
Version:	$Revision: 1.3 $
Author:		Donal K. Fellows <[email protected]>
Created:	29-Apr-2004
Keywords:	Tcl


~ Abstract

This TIP proposes a simple scheme to allow commands to provide basic
syntax help for themselves.  This information would allow for more
advanced processing by programs doing interactive input of Tcl
commands (by providing a mechanism for them to discover what possible
completions of the current command fragment are available) and could
be processed automatically by the '''interp alias''' and '''namespace
ensemble''' mechanisms so that help could be automatically extended to
commands defined through those mechanisms.

~ Rationale

Currently, Tcl commands are only partially consistent in how they
provide information about their own syntax; the only way of getting
any syntax help is by providing invalid input to the command, but not
all commands have invalid input sequences (e.g. '''list''') and nor is
there any way of knowing what those invalid sequences are (where they
do exist) unless you know the command beforehand.

Such help would be useful in a number of situations, such as command
expansion in something like tkcon.  It would also provide a mechanism
for supplying the sort of detailed information which the likes of
[[incr Tcl]]'s ensembles can generate, but which the Tcl ensembles of
[112] do not do (for the reason that this would produce output
significantly different in kind from existing core commands.)

Note that I do not want to provide extended help such as might be
obtained from manual pages; this help system is designed to be
mechanically queryable first.

~ Proposed Change

There are two main components

~~ Data Model

Every command would supply help for itself by providing a callback to
generate the information on demand; there will be a compatability
callback installed by default that states that the command may take
any number of unknown arguments.

The result of the callback will be a list of command call
descriptions.  Each description will be itself a list of terms that
describe a particular way of calling the command, with one term per
argument.  Each term may in turn be one of:

 * ''Required literal'' - this might be something like a subcommand
   name.

 * ''Optional literal'' - a good example of this are the '''then'''
   and '''else''' words in a call to '''if'''.

 * ''Required varying'' (with name for display to the user) - a normal
   argument which may be whatever the caller wants it to be, subject
   to the higher level constraints implicit in the name.

 * ''Optional varying'' (with name for display to the user) - a normal
   optional argument.

 * ''All remaining arguments'' - this would be used in the default
   help outlined above, but would also be useful for modelling the
   ''args'' parameter to a procedure.

[[ToDo: say how these are expressed in C code]]

[[ToDo: talk about how aliases and ensembles can do help construction]]

[[ToDo: talk about how such information can be partially derived in
procedures]]

~~ Information Access

There will be a new subcommand of '''info''' to provide access to this
information at the Tcl level: '''help'''.  The first argument to
'''info help''' will be the name of a command; if no further arguments
are supplied, the result will be a multi-line string with one
invokation per line; the invokations will be just the string parts
with the literal/varying information omitted and the optional/required
information converted into surrounding question marks.

Otherwise, the second argument to '''info help''' will be one of:

 get: Two optional arguments; an index into the list of help "lines"
   (first) and an index within the line (second).  If one index is
   supplied, returns the list of values (without lit/var or opt/req
   info) for the indexed line.  If two indexes are supplied, returns
   the string form for the indexed word within the indexed line.  If
   no indexes are supplied, or returns a list of every such value list
   when no index is supplied.

 literal: Two required arguments; an index into the list of help
   "lines" and an index into the list of values for that line.
   Returns a boolean that is true when the indexed word within the
   indexed line is a literal.

 required: Two required arguments; an index into the list of help
   "lines" and an index into the list of values for that line.
   Returns a boolean that is true when the indexed word within the
   indexed line is required.

[[ToDo: could '''info help''' be used as a mechanism for procedures to
set their own help up?]]

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|




|
|
|
|


|




|
|
|




|
|
|





|



|











|


|
|

|



|


|

|

|

|

|
|

|

|
|
|





|


|
|
|














|
|

|


>

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

# TIP 193: Simple Syntax Help System
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	29-Apr-2004
	Keywords:	Tcl
-----

# Abstract

This TIP proposes a simple scheme to allow commands to provide basic
syntax help for themselves.  This information would allow for more
advanced processing by programs doing interactive input of Tcl
commands \(by providing a mechanism for them to discover what possible
completions of the current command fragment are available\) and could
be processed automatically by the **interp alias** and **namespace
ensemble** mechanisms so that help could be automatically extended to
commands defined through those mechanisms.

# Rationale

Currently, Tcl commands are only partially consistent in how they
provide information about their own syntax; the only way of getting
any syntax help is by providing invalid input to the command, but not
all commands have invalid input sequences \(e.g. **list**\) and nor is
there any way of knowing what those invalid sequences are \(where they
do exist\) unless you know the command beforehand.

Such help would be useful in a number of situations, such as command
expansion in something like tkcon.  It would also provide a mechanism
for supplying the sort of detailed information which the likes of
[incr Tcl]'s ensembles can generate, but which the Tcl ensembles of
[[112]](112.md) do not do \(for the reason that this would produce output
significantly different in kind from existing core commands.\)

Note that I do not want to provide extended help such as might be
obtained from manual pages; this help system is designed to be
mechanically queryable first.

# Proposed Change

There are two main components

## Data Model

Every command would supply help for itself by providing a callback to
generate the information on demand; there will be a compatability
callback installed by default that states that the command may take
any number of unknown arguments.

The result of the callback will be a list of command call
descriptions.  Each description will be itself a list of terms that
describe a particular way of calling the command, with one term per
argument.  Each term may in turn be one of:

 * _Required literal_ - this might be something like a subcommand
   name.

 * _Optional literal_ - a good example of this are the **then**
   and **else** words in a call to **if**.

 * _Required varying_ \(with name for display to the user\) - a normal
   argument which may be whatever the caller wants it to be, subject
   to the higher level constraints implicit in the name.

 * _Optional varying_ \(with name for display to the user\) - a normal
   optional argument.

 * _All remaining arguments_ - this would be used in the default
   help outlined above, but would also be useful for modelling the
   _args_ parameter to a procedure.

[ToDo: say how these are expressed in C code]

[ToDo: talk about how aliases and ensembles can do help construction]

[ToDo: talk about how such information can be partially derived in
procedures]

## Information Access

There will be a new subcommand of **info** to provide access to this
information at the Tcl level: **help**.  The first argument to
**info help** will be the name of a command; if no further arguments
are supplied, the result will be a multi-line string with one
invokation per line; the invokations will be just the string parts
with the literal/varying information omitted and the optional/required
information converted into surrounding question marks.

Otherwise, the second argument to **info help** will be one of:

 get: Two optional arguments; an index into the list of help "lines"
   \(first\) and an index within the line \(second\).  If one index is
   supplied, returns the list of values \(without lit/var or opt/req
   info\) for the indexed line.  If two indexes are supplied, returns
   the string form for the indexed word within the indexed line.  If
   no indexes are supplied, or returns a list of every such value list
   when no index is supplied.

 literal: Two required arguments; an index into the list of help
   "lines" and an index into the list of values for that line.
   Returns a boolean that is true when the indexed word within the
   indexed line is a literal.

 required: Two required arguments; an index into the list of help
   "lines" and an index into the list of values for that line.
   Returns a boolean that is true when the indexed word within the
   indexed line is required.

[ToDo: could **info help** be used as a mechanism for procedures to
set their own help up?]

# Copyright

This document has been placed in the public domain.

Name change from tip/194.tip to tip/194.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149

TIP:            194
Title:          Procedures as Values via '''apply'''
Version:        $Revision: 1.6 $
Author:         Miguel Sofer <[email protected]>
Author:         Joe Mistachkin <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        30-Apr-2004
Post-History:   
Keywords:       Tcl,lambda,anonymous,command,function,functional programming
Tcl-Version:    8.5


~ Abstract

This TIP proposes a new command, tentatively named '''apply''', to
allow procedures to be first class values.  It is an alternative to
the approach of [187], where attaining a similar goal requires a
syntactic and semantic change.

~ Rationale

Tcl is typeless, and every first class value is a string (or at least
representable as such).  Strings are managed by reference counting in
the Tcl core, the required memory is freed automatically when the
string is no longer referenced.

Tcl commands may interpret their arguments differently. Some commands
interpret some of their arguments as scripts - '''eval''',
'''uplevel''', and so on.  But no current Tcl command is able to
specify that a script is to be run in an isolated environment, free of
unwanted side effects or memory leaks caused by name collisions.

In order to achieve this isolation, one has to define a new command
via '''proc''' and assume the burden of name-collision avoidance and
lifetime management, or else produce complicated scripts with ugly
contorsions to avoid the name collisions.

Both [187] and this one propose ways to provide this lacking
functionality to Tcl.  The approach here is to do so by creating a new
'''apply''' command without any change to Tcl's syntax.

~ Specification

A reference manual page can be found at
[http://utdt.edu/~mig/apply2.html]. Summarizing, the syntax of the new
command is:

 * '''apply''' ''func'' ?''arg1 arg2 ...''?

 > The first argument ''func'' is an anonymous function - a list of
   two or three elements [['''list''' ''arglist body''
   ?''namespace''?]]. The first two are exactly like the arguments to
   '''proc''', the third determines the namespace for '''variable''',
   '''namespace''' and command resolution when the body is
   evaluated. The ''namespace'' is interpreted as fixed, and is the
   interpreter's global namespace in the two-argument case.

 > The remaining arguments ''arg1 arg2 ...'' are taken as values for
   the first formal arguments in ''arglist''.

The semantics of '''apply''' (with the exception of some of the fine
details of error messages) can be described by:

| proc apply {fun args} {
|     set len [llength $fun]
|     if {($len < 2) || ($len > 3)} {
|         error "can't interpret \"$fun\" as anonymous function"
|     }

|     lassign $fun argList body ns
|     set name ::$ns::[getGloballyUniqueName]
|     set body0 {
|         rename [lindex [info level 0] 0] {}
|     }

|     proc $name $argList ${body0}$body
|     set code [catch {uplevel 1 $name $args} res opt]
|     return -options $opt $res
| }


where the availability of a '''getGloballyUniqueName''' procedure was
assumed.

~ Reference Implementation

There is a patch
[http://sf.net/tracker/?func=detail&aid=944803&group_id=10894&atid=360894]
that implements this TIP.

The patch defines a new ''tclLambdaType'' for ''Tcl_Obj''s that caches
the internal structures necessary for efficient evaluation: a Proc
struct, a pointer to ''namespace'', and the bytecodes implementing
''body''.  It is a small patch that relies heavily on the
implementation of '''proc''', producing essentially a regular
'''proc''' with no command attached to it: an anonymous function.

All cached internal structures are freed when ''func'' ceases to be
referenced or when it loses its internal representation as a
''tcllambdaType'' through shimmering.

Note that a similar approach is likely for a definitive implementation
of [187].

~ Further Functional Programming Constructs

The availability of '''apply''' permits an easy and efficient access
to other FP functions. For example one might define a constructor
'''lambda''' and a '''curry''' command like this:

| proc lambda {arglist body {ns {}}} {
|     list ::apply [list $arglist $body $ns]
| }

|
| proc curry {lam args} {
|     lappend lam {expand}$args
| }


Function composition is also relatively easy to specify. Further
examples may be seen in the Wiki, see for instance Neil Madden's
'''map''', '''filter''', '''foldl''', '''foldr'''
[http://wiki.tcl.tk/11141] - note that the syntax is slightly
different from the one proposed here.

~ Comparison to TIP 187 and outlook

In terms of usage, the main difference is that where TIP 187 does:

| set p [list lambda x {string length $x}]
| $p $foo

we would do here:

| set p [list ::apply [list x {string length $x}]]
| # or: set p [lambda x {string length $x}]
| {expand}$p $foo ;# or 'eval $p [list $foo]', or ...

or else:

| set p [list x {string length $x}]
| apply $p $foo

This TIP requires no changes to the rules in Tcl(n), whereas [187]
requires a change in rule [[2]].

If in the future Tcl evolves a rule for automatic expansion of leading
words, '''apply''' will provide automatically the syntax of [187].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|

|


|

|
|




|
|




|



|

|

|


|


|

|
|
|
|
|
|


|
|

|
|

|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
<
|
>
|


|


|


|

|
|
|
|

|

|


|

|

|

|

|
|
<
>
|
|
|
<
>



|
|


|



|
|



|
|
|



|
|

|
|


|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149

# TIP 194: Procedures as Values via '''apply'''

	Author:         Miguel Sofer <[email protected]>
	Author:         Joe Mistachkin <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        30-Apr-2004
	Post-History:   
	Keywords:       Tcl,lambda,anonymous,command,function,functional programming
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes a new command, tentatively named **apply**, to
allow procedures to be first class values.  It is an alternative to
the approach of [[187]](187.md), where attaining a similar goal requires a
syntactic and semantic change.

# Rationale

Tcl is typeless, and every first class value is a string \(or at least
representable as such\).  Strings are managed by reference counting in
the Tcl core, the required memory is freed automatically when the
string is no longer referenced.

Tcl commands may interpret their arguments differently. Some commands
interpret some of their arguments as scripts - **eval**,
**uplevel**, and so on.  But no current Tcl command is able to
specify that a script is to be run in an isolated environment, free of
unwanted side effects or memory leaks caused by name collisions.

In order to achieve this isolation, one has to define a new command
via **proc** and assume the burden of name-collision avoidance and
lifetime management, or else produce complicated scripts with ugly
contorsions to avoid the name collisions.

Both [[187]](187.md) and this one propose ways to provide this lacking
functionality to Tcl.  The approach here is to do so by creating a new
**apply** command without any change to Tcl's syntax.

# Specification

A reference manual page can be found at
<http://utdt.edu/~mig/apply2.html> . Summarizing, the syntax of the new
command is:

 * **apply** _func_ ?_arg1 arg2 ..._?

	 > The first argument _func_ is an anonymous function - a list of
   two or three elements [**list** _arglist body_
   ?_namespace_?]. The first two are exactly like the arguments to
   **proc**, the third determines the namespace for **variable**,
   **namespace** and command resolution when the body is
   evaluated. The _namespace_ is interpreted as fixed, and is the
   interpreter's global namespace in the two-argument case.

	 > The remaining arguments _arg1 arg2 ..._ are taken as values for
   the first formal arguments in _arglist_.

The semantics of **apply** \(with the exception of some of the fine
details of error messages\) can be described by:

	 proc apply {fun args} {
	     set len [llength $fun]
	     if {($len < 2) || ($len > 3)} {
	         error "can't interpret \"$fun\" as anonymous function"

	     }
	     lassign $fun argList body ns
	     set name ::$ns::[getGloballyUniqueName]
	     set body0 {
	         rename [lindex [info level 0] 0] {}

	     }
	     proc $name $argList ${body0}$body
	     set code [catch {uplevel 1 $name $args} res opt]
	     return -options $opt $res

	 }

where the availability of a **getGloballyUniqueName** procedure was
assumed.

# Reference Implementation

There is a patch
<http://sf.net/tracker/?func=detail&aid=944803&group_id=10894&atid=360894> 
that implements this TIP.

The patch defines a new _tclLambdaType_ for _Tcl\_Obj_s that caches
the internal structures necessary for efficient evaluation: a Proc
struct, a pointer to _namespace_, and the bytecodes implementing
_body_.  It is a small patch that relies heavily on the
implementation of **proc**, producing essentially a regular
**proc** with no command attached to it: an anonymous function.

All cached internal structures are freed when _func_ ceases to be
referenced or when it loses its internal representation as a
_tcllambdaType_ through shimmering.

Note that a similar approach is likely for a definitive implementation
of [[187]](187.md).

# Further Functional Programming Constructs

The availability of **apply** permits an easy and efficient access
to other FP functions. For example one might define a constructor
**lambda** and a **curry** command like this:

	 proc lambda {arglist body {ns {}}} {
	     list ::apply [list $arglist $body $ns]

	 }
	
	 proc curry {lam args} {
	     lappend lam {expand}$args

	 }

Function composition is also relatively easy to specify. Further
examples may be seen in the Wiki, see for instance Neil Madden's
**map**, **filter**, **foldl**, **foldr**
<http://wiki.tcl.tk/11141>  - note that the syntax is slightly
different from the one proposed here.

# Comparison to TIP 187 and outlook

In terms of usage, the main difference is that where TIP 187 does:

	 set p [list lambda x {string length $x}]
	 $p $foo

we would do here:

	 set p [list ::apply [list x {string length $x}]]
	 # or: set p [lambda x {string length $x}]
	 {expand}$p $foo ;# or 'eval $p [list $foo]', or ...

or else:

	 set p [list x {string length $x}]
	 apply $p $foo

This TIP requires no changes to the rules in Tcl\(n\), whereas [[187]](187.md)
requires a change in rule [[2]](2.md).

If in the future Tcl evolves a rule for automatic expansion of leading
words, **apply** will provide automatically the syntax of [[187]](187.md).

# Copyright

This document has been placed in the public domain.

Name change from tip/195.tip to tip/195.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

TIP:            195
Title:          A Unique Prefix Handling Command
Version:        $Revision: 1.18 $
Author:         Peter Spjuth <[email protected]>
Author:         Peter Spjuth <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        02-May-2004
Post-History:   
Keywords:       Tcl
Obsoletes:      105
Tcl-Version:    8.6


~ Abstract

This TIP adds a new command to support matching of strings to unique
prefixes of patterns, similar to Tcl's existing subcommand-name
matching or Tk's option-name matching.

~ Rationale

When code (particularly in script libraries) wants to support shortest
unique prefix matching in the manner of the Tcl core (as provided by
''Tcl_GetIndexFromObj'') currently either the prefixes have to be
precomputed (by hand or by script) or the matching has to be done
backwards.  In the first case, this is either error-prone or requires
an extra piece of code that has to be developed by the programmer.  In
the second case, the code has to be converted into a pattern which is
matched against the list of supported options in some way, which is
either inefficient or has hazards if the string being matched contains
characters that are meaningful to the matching engine being used.
Instead, it would be far nicer if we could make the core support this
directly, so that script authors could just say what they mean.

See also [105], which the text above comes from.

Another benefit of this command is getting an error message that
looks like those nice and informative error messages that built in
commands have.  The proposed command includes a flag to control
the error behaviour.

Another use of prefix matching is for completion, such as a combobox
showing matching alternatives, or tab completion at a prompt.

The former needs a list of matching elements, and the latter needs
a longest common prefix.  

These functionalities are similiar enough to group them but different
enought to make it a bad idea for flags, so a prefix ensemble seems
approriate for them.

~ Proposed Change

To support this, I propose adding a '''::tcl::prefix''' ensemble with
the following subcommands

 * '''prefix''' '''match''' ?'''-exact'''? ?'''-message''' ''string''? ?'''-error''' ''options''? ''list'' ''string''

 * '''prefix''' '''longest''' ''list'' ''string''

 * '''prefix''' '''all''' ''list'' ''string''

All commands are given a list of possibilities and a string to match.

'''prefix''' '''match''' returns the matching element in the list or an
error.  Basically it does what ''Tcl_GetIndexFromObj'' does except it
returns a string instead of an index.  The options '''-exact''' and '''-message''' corresponds to the ''flags'' and ''msg'' arguments to
''Tcl_GetIndexFromObj''.  The default value for '''-message''' is
"option".

The '''-error''' options are used when no match is found.
If '''-error''' is empty, no error is generated and an empty string is returned.
Otherwise the options are used as '''return''' options when generating the
error message.  The default corresponds to setting "-level 0".
Example: If '''-error''' "-errorcode MyError -level 1" is used, an error would
be generated as [[return -errorcode MyError -level 1 -code error "ErrMsg"]].

'''prefix''' '''longest''' returns the longest common prefix within
the group that matches the given string.  If there is no match, 
an empty string is returned.

'''prefix''' '''all''' returns a list of all matching elements.

~ Examples

Basic use:

|% namespace import ::tcl::prefix
|% prefix match {apa bepa cepa} apa
|apa
|% prefix match {apa bepa cepa} a
|apa
|% prefix match -exact {apa bepa cepa} a
|bad option "a": must be apa, bepa, or cepa
|% prefix match -message "switch" {apa ada bepa cepa} a
|ambiguous switch "a": must be apa, ada, bepa, or cepa
|% prefix longest {fblocked fconfigure fcopy file fileevent flush} fc
|fco
|% prefix all {fblocked fconfigure fcopy file fileevent flush} fc
|fconfigure fcopy

Simplifying option matching:

|array set opts {-apa 1 -bepa "" -cepa 0}
|foreach {arg val} $args {
|    set opts([prefix match {-apa -bepa -cepa} $arg]) $val
|}


Switch similar to [105]:

|switch -- [prefix match {apa bepa cepa} $arg] {
|    apa  { }
|    bepa { }
|    cepa { }
|}


~ Alternative names

Alternative names for the command that have been suggested are
'''prefix''', '''string prefix''', '''string disambiguate''',
'''string prefixmatch''', '''string matchprefix''' and
'''lsearch -prefix'''.

Any name based on ''Tcl_GetIndexFromObj'' feels wrong since this
command does not get any index.

~ Discussion

Pascal Scheffers wrote:

I am not very fond of new toplevel commands, as they have a habit
of breaking existing code, or, more likely, being redefined by
existing code.  How about '''string prefix ...''' or
'''lsearch -prefix'''? It feels like something that
could logically reside inside string handling or list handling.

Donal Fellows wrote:

Hmm, a new matching style for '''lsearch''' could work (yet another
option for an overly scary command!) especially in conjunction with
some of the other options like -inline, but I suspect it'll have to be
'''string prefix''' or something like that since then we can easily
state that the behaviour is not to necessarily return the first
matching element. That was what scuppered #105 after all (much to my
annoyance.)

Peter Spjuth: TIP was at this point altered to suggest '''string disambiguate''' after a suggestion from Donal.

Donal Fellows wrote:

I'd suggest that the '''-exact''' option be dropped, as it is trivially
implementable using '''lsearch -exact''', '''dict exists''', '''info exists''',
'''switch''', etc. It's also corresponding to a very rarely used flag to
Tcl_GetIndexFromObj.

Peter Spjuth: Other ways to do '''-exact''' doesn't give the
standardized error message so it has some value for those that want
that functionality.  The Core uses TCL_EXACT in a few places where it makes sense so the flag can be useful.

Voices were raised against the proposed '''string disambiguate''' and Jeff
Hobbs pointed out other prefix related functions that are useful.  This
lead to the prefix ensemble suggestion.

~ Reference Implementation

Partial implementation at:
https://sourceforge.net/support/tracker.php?aid=1040206

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|





|

|
|
|
|









|
















|

|


|

|

|



|
|
|
|


|
|
|

|
|

|



|

|



|
|
|
|
|
|
|
|
|
|
|
|
|



|
|
|
<
|
>
|

|
|
|
|
<
|
>
|


|
|
|

|


|





|
|




|
|

|

|
|

|



|
|
|
|

|

|

|



|


|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

# TIP 195: A Unique Prefix Handling Command

	Author:         Peter Spjuth <[email protected]>
	Author:         Peter Spjuth <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        02-May-2004
	Post-History:   
	Keywords:       Tcl
	Obsoletes:      105
	Tcl-Version:    8.6
-----

# Abstract

This TIP adds a new command to support matching of strings to unique
prefixes of patterns, similar to Tcl's existing subcommand-name
matching or Tk's option-name matching.

# Rationale

When code \(particularly in script libraries\) wants to support shortest
unique prefix matching in the manner of the Tcl core \(as provided by
_Tcl\_GetIndexFromObj_\) currently either the prefixes have to be
precomputed \(by hand or by script\) or the matching has to be done
backwards.  In the first case, this is either error-prone or requires
an extra piece of code that has to be developed by the programmer.  In
the second case, the code has to be converted into a pattern which is
matched against the list of supported options in some way, which is
either inefficient or has hazards if the string being matched contains
characters that are meaningful to the matching engine being used.
Instead, it would be far nicer if we could make the core support this
directly, so that script authors could just say what they mean.

See also [[105]](105.md), which the text above comes from.

Another benefit of this command is getting an error message that
looks like those nice and informative error messages that built in
commands have.  The proposed command includes a flag to control
the error behaviour.

Another use of prefix matching is for completion, such as a combobox
showing matching alternatives, or tab completion at a prompt.

The former needs a list of matching elements, and the latter needs
a longest common prefix.  

These functionalities are similiar enough to group them but different
enought to make it a bad idea for flags, so a prefix ensemble seems
approriate for them.

# Proposed Change

To support this, I propose adding a **::tcl::prefix** ensemble with
the following subcommands

 * **prefix** **match** ?**-exact**? ?**-message** _string_? ?**-error** _options_? _list_ _string_

 * **prefix** **longest** _list_ _string_

 * **prefix** **all** _list_ _string_

All commands are given a list of possibilities and a string to match.

**prefix** **match** returns the matching element in the list or an
error.  Basically it does what _Tcl\_GetIndexFromObj_ does except it
returns a string instead of an index.  The options **-exact** and **-message** corresponds to the _flags_ and _msg_ arguments to
_Tcl\_GetIndexFromObj_.  The default value for **-message** is
"option".

The **-error** options are used when no match is found.
If **-error** is empty, no error is generated and an empty string is returned.
Otherwise the options are used as **return** options when generating the
error message.  The default corresponds to setting "-level 0".
Example: If **-error** "-errorcode MyError -level 1" is used, an error would
be generated as [return -errorcode MyError -level 1 -code error "ErrMsg"].

**prefix** **longest** returns the longest common prefix within
the group that matches the given string.  If there is no match, 
an empty string is returned.

**prefix** **all** returns a list of all matching elements.

# Examples

Basic use:

	% namespace import ::tcl::prefix
	% prefix match {apa bepa cepa} apa
	apa
	% prefix match {apa bepa cepa} a
	apa
	% prefix match -exact {apa bepa cepa} a
	bad option "a": must be apa, bepa, or cepa
	% prefix match -message "switch" {apa ada bepa cepa} a
	ambiguous switch "a": must be apa, ada, bepa, or cepa
	% prefix longest {fblocked fconfigure fcopy file fileevent flush} fc
	fco
	% prefix all {fblocked fconfigure fcopy file fileevent flush} fc
	fconfigure fcopy

Simplifying option matching:

	array set opts {-apa 1 -bepa "" -cepa 0}
	foreach {arg val} $args {
	    set opts([prefix match {-apa -bepa -cepa} $arg]) $val

	}

Switch similar to [[105]](105.md):

	switch -- [prefix match {apa bepa cepa} $arg] {
	    apa  { }
	    bepa { }
	    cepa { }

	}

# Alternative names

Alternative names for the command that have been suggested are
**prefix**, **string prefix**, **string disambiguate**,
**string prefixmatch**, **string matchprefix** and
**lsearch -prefix**.

Any name based on _Tcl\_GetIndexFromObj_ feels wrong since this
command does not get any index.

# Discussion

Pascal Scheffers wrote:

I am not very fond of new toplevel commands, as they have a habit
of breaking existing code, or, more likely, being redefined by
existing code.  How about **string prefix ...** or
**lsearch -prefix**? It feels like something that
could logically reside inside string handling or list handling.

Donal Fellows wrote:

Hmm, a new matching style for **lsearch** could work \(yet another
option for an overly scary command!\) especially in conjunction with
some of the other options like -inline, but I suspect it'll have to be
**string prefix** or something like that since then we can easily
state that the behaviour is not to necessarily return the first
matching element. That was what scuppered \#105 after all \(much to my
annoyance.\)

Peter Spjuth: TIP was at this point altered to suggest **string disambiguate** after a suggestion from Donal.

Donal Fellows wrote:

I'd suggest that the **-exact** option be dropped, as it is trivially
implementable using **lsearch -exact**, **dict exists**, **info exists**,
**switch**, etc. It's also corresponding to a very rarely used flag to
Tcl\_GetIndexFromObj.

Peter Spjuth: Other ways to do **-exact** doesn't give the
standardized error message so it has some value for those that want
that functionality.  The Core uses TCL\_EXACT in a few places where it makes sense so the flag can be useful.

Voices were raised against the proposed **string disambiguate** and Jeff
Hobbs pointed out other prefix related functions that are useful.  This
lead to the prefix ensemble suggestion.

# Reference Implementation

Partial implementation at:
<https://sourceforge.net/support/tracker.php?aid=1040206>

# Copyright

This document has been placed in the public domain.

Name change from tip/196.tip to tip/196.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

TIP:		196
Title:		Tcl Commands as Values
Version:	$Revision: 1.2 $
Author:		Robert Suetterlin <[email protected]>
State:		Withdrawn
Type:		Project
Tcl-Version:	8.5
Vote:		Pending
Created:	11-May-2004
Post-History:	


~ Abstract

This TIP proposes making command procedures first-class values in Tcl.
It also changes the command binding scheme to recognize these values
before performing old-style name lookup indirection.

~ Rationale

A Tcl script is a string containing one or more commands separated by
semicolons or newlines.  The evaluation of the script breaks these
commands into words.  Currently the string value of the first such
word is used to lookup a command procedure (effectively a function
pointer) and some clientData (per-command instance state).  These will
then be used by the virtual machine.

For example, in the case of pure Tcl procedures created with
'''proc''' command, this is ''TclProcInterpProc'' with an associated
''procPtr'' that basically references the procedure body (as a string)
and its formal argument list.

Because of the name lookup indirection, Tcl does not support anonymous
commands.  (There is quite some interest in using such with Tcl,
please compare [187] and [194].  Several other languages (even C)
support anonymous commands.  They seem to be quite useful, just
compare their use in Tcl's C code.)

This can be changed by allowing for a new kind of word (i.e. a new
'''Tcl_Obj''' ''commandObject'') that can be immediately interpreted
as a command.  ([187] proposes the use of special Tcl lists, but this
is too limiting for the scope of this document.)  The evaluation
checks if the first word is a ''commandObject'', if not it does the
old style name lookup (with '''unknown''' fallback).

A ''commandObject'' should store information equivalent to what is
provided with the '''Tcl_CreateCommand()''' API and stored in the
global name lookup table.  Thus it can reference any command procedure
and any clientData, allowing the creation of arbitrary anonymous
commands in C extensions for example.

Having such ''commandObject''s available will allow for '''proc''' to
return these instead of an empty string and to skip registration of a
command when its name is provided as the empty string.

~ Examples

This will allow to reproduce all of the features of [187].  Compare
this example with the one in [187]:

|proc filter {list proc} {
|    set res {}
|    foreach e $list {
|        if {![$proc $e]} {
|            lappend res $e
|        }
|    }
|}



|
|set a [list 1 10 100 4 5]
|set b [filter $a [proc x {expr $x<10}]]

This sets the variable b to the list {''10 100''}.

In addition this TIP still allows:

|proc {list lambda x {body}} {var} {puts $var} 

if we really want to.

And we can use ''commandObject''s that have not been created by
'''proc''' in the first place - think OOP for example.

These ''commandObject''s could also be used as data structure for the
command namespace, which would then become a dictionary, if I recall
correctly.  Allowing for registering an anonymous command with a name
(via '''rename''') by putting the name and the commandObject into the
dictionary.

~ Specification

This document proposes at least the following changes to the Tcl core:

 1. Include a new ''Tcl_Obj'' '''commandObj''' that contains
    information equivalent to the arguments ''proc'', ''clientData''
    and ''deleteProc'' to '''Tcl_CreateObjCommand()'''.  (Maybe interp
    is necessary, too.  But I don't understand the byte compiler and
    execute stuff good enough to judge.)

 2. Change '''Tcl_GetCommandFromObj()''' to check if ''objPtr''
    references a ''commandObj'' first, otherwise check if it finds a
    named command.

 3. Have the '''proc''' command return a ''commandObj'' that is
    equivalent to the '''Tcl_Create(Obj)Command()''' calls in
    '''Tcl_ProcObjCmd()'''.  i.e. the ''proc'' is equal to
    '''Tcl(Obj)InterpProc()''' and the ''clientData'' is the
    ''procPtr''.

~ Copyright

This document is in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|





|




|
|



|
|



|
|

|

|
|
|
|
|
|

|
|




|



|

|
|

|
|
|
|
|
<
<
<
>
>
>
|
|
|

|



|



|
|

|


|


|



|
|
|

|

|
|


|
|
|
|
|

|


>

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

# TIP 196: Tcl Commands as Values

	Author:		Robert Suetterlin <[email protected]>
	State:		Withdrawn
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Pending
	Created:	11-May-2004
	Post-History:	
-----

# Abstract

This TIP proposes making command procedures first-class values in Tcl.
It also changes the command binding scheme to recognize these values
before performing old-style name lookup indirection.

# Rationale

A Tcl script is a string containing one or more commands separated by
semicolons or newlines.  The evaluation of the script breaks these
commands into words.  Currently the string value of the first such
word is used to lookup a command procedure \(effectively a function
pointer\) and some clientData \(per-command instance state\).  These will
then be used by the virtual machine.

For example, in the case of pure Tcl procedures created with
**proc** command, this is _TclProcInterpProc_ with an associated
_procPtr_ that basically references the procedure body \(as a string\)
and its formal argument list.

Because of the name lookup indirection, Tcl does not support anonymous
commands.  \(There is quite some interest in using such with Tcl,
please compare [[187]](187.md) and [[194]](194.md).  Several other languages \(even C\)
support anonymous commands.  They seem to be quite useful, just
compare their use in Tcl's C code.\)

This can be changed by allowing for a new kind of word \(i.e. a new
**Tcl\_Obj** _commandObject_\) that can be immediately interpreted
as a command.  \([[187]](187.md) proposes the use of special Tcl lists, but this
is too limiting for the scope of this document.\)  The evaluation
checks if the first word is a _commandObject_, if not it does the
old style name lookup \(with **unknown** fallback\).

A _commandObject_ should store information equivalent to what is
provided with the **Tcl\_CreateCommand\(\)** API and stored in the
global name lookup table.  Thus it can reference any command procedure
and any clientData, allowing the creation of arbitrary anonymous
commands in C extensions for example.

Having such _commandObject_s available will allow for **proc** to
return these instead of an empty string and to skip registration of a
command when its name is provided as the empty string.

# Examples

This will allow to reproduce all of the features of [[187]](187.md).  Compare
this example with the one in [[187]](187.md):

	proc filter {list proc} {
	    set res {}
	    foreach e $list {
	        if {![$proc $e]} {
	            lappend res $e



	        }
	    }
	}
	
	set a [list 1 10 100 4 5]
	set b [filter $a [proc x {expr $x<10}]]

This sets the variable b to the list \{_10 100_\}.

In addition this TIP still allows:

	proc {list lambda x {body}} {var} {puts $var} 

if we really want to.

And we can use _commandObject_s that have not been created by
**proc** in the first place - think OOP for example.

These _commandObject_s could also be used as data structure for the
command namespace, which would then become a dictionary, if I recall
correctly.  Allowing for registering an anonymous command with a name
\(via **rename**\) by putting the name and the commandObject into the
dictionary.

# Specification

This document proposes at least the following changes to the Tcl core:

 1. Include a new _Tcl\_Obj_ **commandObj** that contains
    information equivalent to the arguments _proc_, _clientData_
    and _deleteProc_ to **Tcl\_CreateObjCommand\(\)**.  \(Maybe interp
    is necessary, too.  But I don't understand the byte compiler and
    execute stuff good enough to judge.\)

 2. Change **Tcl\_GetCommandFromObj\(\)** to check if _objPtr_
    references a _commandObj_ first, otherwise check if it finds a
    named command.

 3. Have the **proc** command return a _commandObj_ that is
    equivalent to the **Tcl\_Create\(Obj\)Command\(\)** calls in
    **Tcl\_ProcObjCmd\(\)**.  i.e. the _proc_ is equal to
    **Tcl\(Obj\)InterpProc\(\)** and the _clientData_ is the
    _procPtr_.

# Copyright

This document is in the public domain.

Name change from tip/197.tip to tip/197.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

TIP:		197
Title:		Unfocussed Text Widget Cursor Control
Version:	$Revision: 1.10 $
Author:		R. Timothy Edwards <[email protected]>
Author:		Donal K. Fellows <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Created:	12-May-2004
Post-History:	
Keywords:	Tk


~Abstract

This TIP proposes a simple extension to the Tk text widget to allow the
insertion cursor to persist when the window containing the text widget does
not have focus.

~Rationale

In some cases it is useful to redirect text from one top-level window into a
separate top-level window containing a text widget. In such a case, it is
helpful to be able to see the cursor in the text widget. However, as
implemented, the Tk text widget always erases the insert cursor when the
window loses focus. It is a trivial fix to add an option
'''-insertunfocussed''' to the text widget that keeps the text cursor in the
window.

~Specification

The extension would provide a global '''text''' widget option
'''-insertunfocussed''' with a ternary value. The current behaviour would be
the default.

 > ''pathName'' '''configure -insertunfocussed''' ''value''

Supported values will be:

 none: Do not display the insertion cursor when the text widget doesn't have
   the focus.

 hollow: Display the border of the insertion cursor when the text widget
   doesn't have the focus, but do not fill the cursor or make it flash. If the
   '''-insertborderwidth''' option is zero, draw (but do not fill) a rectangle
   in the '''-insertbackground''' color.

 solid: Display the insertion cursor unchanged whether or not the text widget
   has the focus. The insertion cursor will not flash when the widget does not
   have the focus.

In all cases, the insertion cursor will be displayed as at present when the
text widget does have the focus.

~Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|





|






|


|

|
|


|








|
|








|


>

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

# TIP 197: Unfocussed Text Widget Cursor Control

	Author:		R. Timothy Edwards <[email protected]>
	Author:		Donal K. Fellows <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Done
	Created:	12-May-2004
	Post-History:	
	Keywords:	Tk
-----

# Abstract

This TIP proposes a simple extension to the Tk text widget to allow the
insertion cursor to persist when the window containing the text widget does
not have focus.

# Rationale

In some cases it is useful to redirect text from one top-level window into a
separate top-level window containing a text widget. In such a case, it is
helpful to be able to see the cursor in the text widget. However, as
implemented, the Tk text widget always erases the insert cursor when the
window loses focus. It is a trivial fix to add an option
**-insertunfocussed** to the text widget that keeps the text cursor in the
window.

# Specification

The extension would provide a global **text** widget option
**-insertunfocussed** with a ternary value. The current behaviour would be
the default.

 > _pathName_ **configure -insertunfocussed** _value_

Supported values will be:

 none: Do not display the insertion cursor when the text widget doesn't have
   the focus.

 hollow: Display the border of the insertion cursor when the text widget
   doesn't have the focus, but do not fill the cursor or make it flash. If the
   **-insertborderwidth** option is zero, draw \(but do not fill\) a rectangle
   in the **-insertbackground** color.

 solid: Display the insertion cursor unchanged whether or not the text widget
   has the focus. The insertion cursor will not flash when the widget does not
   have the focus.

In all cases, the insertion cursor will be displayed as at present when the
text widget does have the focus.

# Copyright

This document has been placed in the public domain.

Name change from tip/198.tip to tip/198.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

TIP:            198
Title:          Image Command XPM Extension
Version:        $Revision: 1.6 $
Author:         R. Timothy Edwards <[email protected]>
Author:         Don Porter <[email protected]>
Author:         Kevin Kenny <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        12-May-2004
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes an extension to the Tk '''image''' command to
incorporate color pixmap images based on the XPM format.  The format
is analogous to the '''bitmap''' option (''tkImgBmap.c'' in the Tk
source).

~Rationale

The "XPM" format has become more-or-less a standard, and is a nice
text-readable color alternative to the standard X11 bitmap format.
The runtime library for XPM is available in standard Linux
distributions and elsewhere.  Tk has a number of color '''photo'''
image formats, but these make various assumptions about rendering.
There is no color alternative to the simple pixel-based bitmap format.

~Specification

This TIP specifies the extension of the '''image''' command in the
following manner:

 > '''image create xpm''' ''name'' '''-file''' ''xpm_file''

It would probably be a nice idea to include in-line pixmap
specifications similar to that allowed for bitmaps by the BLT package.
However, at this time, the reference implementation does not include
such an extension.

~Reference Implementation

There is an implementation in the source for
XCircuit[http://xcircuit.ece.jhu.edu/].  The source file is
"tkPixmap.c".

~Comments

I'd like to see more justification in this proposal
as to why a new image type is needed, rather than
implementing a suitable format for either the existing
bitmap or photo image types.  

In fact, the Img extension already has XPM as a photo
image format.  I'm quite baffled as to the need for a new
image type.  Is this TIP better served by a request to
promote XPM to the core set of supported formats?

~Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|

|
|

|




|



|

|


|






|


|


|











|


>

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

# TIP 198: Image Command XPM Extension

	Author:         R. Timothy Edwards <[email protected]>
	Author:         Don Porter <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        12-May-2004
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes an extension to the Tk **image** command to
incorporate color pixmap images based on the XPM format.  The format
is analogous to the **bitmap** option \(_tkImgBmap.c_ in the Tk
source\).

# Rationale

The "XPM" format has become more-or-less a standard, and is a nice
text-readable color alternative to the standard X11 bitmap format.
The runtime library for XPM is available in standard Linux
distributions and elsewhere.  Tk has a number of color **photo**
image formats, but these make various assumptions about rendering.
There is no color alternative to the simple pixel-based bitmap format.

# Specification

This TIP specifies the extension of the **image** command in the
following manner:

 > **image create xpm** _name_ **-file** _xpm\_file_

It would probably be a nice idea to include in-line pixmap
specifications similar to that allowed for bitmaps by the BLT package.
However, at this time, the reference implementation does not include
such an extension.

# Reference Implementation

There is an implementation in the source for
XCircuit<http://xcircuit.ece.jhu.edu/> .  The source file is
"tkPixmap.c".

# Comments

I'd like to see more justification in this proposal
as to why a new image type is needed, rather than
implementing a suitable format for either the existing
bitmap or photo image types.  

In fact, the Img extension already has XPM as a photo
image format.  I'm quite baffled as to the need for a new
image type.  Is this TIP better served by a request to
promote XPM to the core set of supported formats?

# Copyright

This document has been placed in the public domain.

Name change from tip/199.tip to tip/199.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

TIP:            199
Title:          Specification of Alternatives to .wishrc/.tclshrc
Version:        $Revision: 1.8 $
Author:         R. Timothy Edwards <[email protected]>
Author:         Don Porter <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        12-May-2004
Post-History:   
Keywords:       Tcl,Tk,shell,interactive
Tcl-Version:    8.6


~ Abstract

This TIP describes an extension of the command-line options to the
"wish" and "tclsh" programs to allow the startup script to be
redirected from the default ~/.wishrc (or ~/.tclshrc) to an
alternative file.

~Rationale

It is possible to run an application from a terminal that starts up a
GUI or other event-based process but that, after setting up the event
callback procedures, drops back into the terminal to allow a
dual-input interface.  As written, the only way to execute a script
and return to the interpreter prompt in the terminal is to put the
script in the ".wishrc" or ".tclshrc" startup script.  One has to bend
over backwards to write an application that will make this happen
without actually changing the user's startup scripts.  The shell
script must redefine environment variable ''$HOME'' to point to the
place where the script is that needs to be run, and the script itself
then must be named ".wishrc" or ".tclshrc", or must have a symbolic
link of that name pointing to it.  The ''$HOME'' environment variable
must be copied to another variable name if the application needs to
reference the original value.

All this can be avoided by simply having a shell command-line option
"'''-startup''' ''filename''" that allows the specification of a name
other than ".wishrc" or ".tclshrc" in a directory path that is not
necessarily the user's home directory, to be used as the startup
script.  This would not only be useful for the purpose outlined above,
but also to simply bypass whatever commands are executed by the
default startup script.

~Specification

The command-line option for "wish" and "tclsh" would be extended to
add the option '''-startup''', for example:

 > '''wish -startup''' ''filename'' [''other options'']

~Comments

You are seeking interactivity following the evaluation
of a start-up script.  Is that the whole point?  If so,
then an alternative solution is provided at Tcl Patch 955470.

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

~Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|



|


|









|


|




|






|


|

|

|





|

|


>

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

# TIP 199: Specification of Alternatives to .wishrc/.tclshrc

	Author:         R. Timothy Edwards <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        12-May-2004
	Post-History:   
	Keywords:       Tcl,Tk,shell,interactive
	Tcl-Version:    8.6
-----

# Abstract

This TIP describes an extension of the command-line options to the
"wish" and "tclsh" programs to allow the startup script to be
redirected from the default ~/.wishrc \(or ~/.tclshrc\) to an
alternative file.

# Rationale

It is possible to run an application from a terminal that starts up a
GUI or other event-based process but that, after setting up the event
callback procedures, drops back into the terminal to allow a
dual-input interface.  As written, the only way to execute a script
and return to the interpreter prompt in the terminal is to put the
script in the ".wishrc" or ".tclshrc" startup script.  One has to bend
over backwards to write an application that will make this happen
without actually changing the user's startup scripts.  The shell
script must redefine environment variable _$HOME_ to point to the
place where the script is that needs to be run, and the script itself
then must be named ".wishrc" or ".tclshrc", or must have a symbolic
link of that name pointing to it.  The _$HOME_ environment variable
must be copied to another variable name if the application needs to
reference the original value.

All this can be avoided by simply having a shell command-line option
"**-startup** _filename_" that allows the specification of a name
other than ".wishrc" or ".tclshrc" in a directory path that is not
necessarily the user's home directory, to be used as the startup
script.  This would not only be useful for the purpose outlined above,
but also to simply bypass whatever commands are executed by the
default startup script.

# Specification

The command-line option for "wish" and "tclsh" would be extended to
add the option **-startup**, for example:

 > **wish -startup** _filename_ [_other options_]

# Comments

You are seeking interactivity following the evaluation
of a start-up script.  Is that the whole point?  If so,
then an alternative solution is provided at Tcl Patch 955470.

<http://sf.net/tracker/index.php?func=detail&aid=955470&group\_id=10894&atid=310894>

# Copyright

This document has been placed in the public domain.

Name change from tip/2.tip to tip/2.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

TIP:            2
Title:          TIP Guidelines
Version:        $Revision: 1.38 $
Author:         Andreas Kupries <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         Don Porter <[email protected]>
Author:         Mo DeJong <[email protected]>
Author:         Larry W. Virden <[email protected]>
Author:         Kevin Kenny <[email protected]>
State:          Draft
Type:           Process
Vote:           Pending
Created:        12-Sep-2000
Post-History:   


~ Abstract

This document describes and defines the editorial process a TCT
document (TIP) has to go through before accepted as official.

~ What is a TIP?

TIP stands for Tcl Improvement Proposal.  A TIP is a design document
providing information to the Tcl community, or describing a new
feature for Tcl.  The TIP should provide a concise technical
specification of the feature and a rationale for the feature.

We intend TIPs to be the primary mechanisms for proposing new
features, for collecting community input on an issue, and for
documenting the design decisions that have gone into Tcl.  The TIP
author is responsible for building consensus within the community and
documenting dissenting opinions.

Because the TIPs are maintained as text files under revision control,
their history is the historical record of the feature proposal.  This
historical record is available by the normal (CVS?) commands for
retrieving older revisions.  For those without direct access to the
CVS tree, you can browse the current and past TIP revisions
[http://www.cs.man.ac.uk/fellowsd-bin/TIP/].

Further details on the arguments behind the evolution of the TIP
concept and formatting can be found in the archive of the ''tclcore''
mailing list
[http://aspn.activestate.com/ASPN/Mail/Browse/Threaded/tcl-core].

~ Kinds of TIPs

There are three kinds of TIPs.  A project TIP describes a new (or
significantly updated) feature or implementation for Tcl.  An
informative TIP describes a Tcl design issue, or provides general
guidelines or information to the Tcl community, but does not propose a
new feature.  A process TIP is like an informative TIP but the
provided guidelines are mandatory in a certain context (as specified
in the TIP itself).

Voting by the TCT as per the charter (see [0]) is required to make a
project or process TIP official.

~ TIP Workflow

The TIP editor, Donal K. Fellows <[email protected]> ''pro
tem'', is responsible for assigning numbers to each TIP and managing its
status on behalf of authors.

Everyone in the community can submit a TIP to the TIP editor. It should
contain at least a proposed title and a rough, but fleshed out, draft of the
TIP. It ''must'' include a copyright statement that permits the normal
business of the TIP process as described here.

If the TIP editor approves, he will assign the TIP a number, label it as
either project, process or informational, give it status ''Draft'', and create
and check-in the initial draft of the TIP. The TIP editor will not
unreasonably deny a TIP.  Reasons for denying TIP status include gross
malformatting, inappropriate copyright, duplication of effort, being
technically unsound, or not in keeping with the Tcl philosophy; the TCT and
after that John Ousterhout <[email protected]> is the final arbitrator of the
latter, as defined in the charter ([0]).

Discussion concerning a TIP should initially be kept out of the
tclcore and tct mailing lists.  Instead, comments should be sent to,
and collected by, the TIP author, who has the responsibility to
incorporate these comments into the document.

''Note:'' It has been proposed to create a new mailing list for each
TIP to handle its discussion.  Rejection and finalization of the TIP
closes the mailing list, but not the archive.  Together with the CVS
history a complete record of the development of a TIP will be
available.

The authors of the TIP are responsible for writing the TIP and
marshaling community support for it.  The structure of a TIP is
described in detail in [3].

A project TIP consists in principle of two parts, a design document and a
reference implementation. The TIP will not normally be reviewed and accepted
before a reference implementation is begun so that the amount of time between
acceptance and a final implementation can be minimized. The implementation can
be given in the form of code, patch, or URL to same, and ''must'' be applied
to the Tcl/Tk core before it can be considered ''Final''; while small
reference implementations may be placed inside the TIP itself, large reference
implementations should be held externally and linked to by reference
(typically a URL). Authors are encouraged to use the SourceForge Patch
trackers for this purpose.

Process and Informational TIPs do not need an implementation.

TIP authors are responsible for collecting community feedback on a TIP
before submitting it for review (the creation of a TIP is a part of
that review process.)  However, wherever possible, long open-ended
discussions on public mailing lists should be avoided.  A better
strategy is to encourage public feedback directly to the TIP author,
who collects and integrates the comments back into the TIP.

Once the authors have completed a TIP, they must inform the Tcl Core
Team that it is ready for review.  TIPs are reviewed by the Tcl Core
Team and (for Project TIPs) the maintainers for the relevant parts of
the core, who may accept or reject a TIP or send it back to the
author(s) for revision (as detailed in [0].)  The acceptance or
rejection of a TIP will cause its state to be changed accordingly to
''Accepted'' or ''Rejected''.

Once a TIP requiring a reference implementation has been accepted, the
reference implementation must be completed. When the reference implementation
is complete and accepted by the TCT (who can reject it if they feel the
implementation would damage the rest of the core) the status will be changed
to ''Final''. This is usually done by the TIP Editor, as advised by the
responsible Tcl/Tk maintainer.

A TIP can also be assigned status ''Deferred''.  The TIP author or the
editor can assign the TIP this status when no progress is being made
on the TIP.  Once a TIP is deferred, the TIP editor can re-assign it
to ''Draft'' status.

A TIP can also be ''Withdrawn'' by the author.  Perhaps after all is
said and done, the author believes it was not a good idea.  It is
still important to have a record of this fact.  It is expected that
''Accepted'' TIPs will only be withdrawn very rarely, and ''Final''
TIPs only under exceptional circumstances.

TIP workflow is as follows:

#image:2workflow TIP Workflow

Some informative TIPs may also have a status of ''Active'' if they are
never meant to be completed.  For example: [1].

~ What belongs in a successful TIP?

Each TIP should have the following parts:

 1. ''Title'' - a short, descriptive title.

 2. ''Author''(s) - names and contact info (email addresses) for each
    author.

 3. ''Abstract'' - a short (typically <200 word) description of the
    technical issue being addressed.

 4. ''Copyright''/public domain - Each TIP must either be explicitly
    labelled in the public domain (the preferred 'license') or the
    Open Publication License [http://www.opencontent.org/openpub/].
    It is recommended that this be done by making the last section of
    the document be a copyright heading, with the body describing what
    copyright (if any) the document is released under.

 5. ''Specification'' - Project TIPs should have a technical
    specification that should describe the syntax and semantics of any
    new language feature.  The specification should be detailed enough
    to allow (competing) interoperable implementations for any of the
    current Tcl platforms.

 6. ''Rationale'' - The rationale fleshes out the specification by
    describing what motivated the design and why particular design
    decisions were made.  It should describe alternate designs that
    were considered and related work, ''e.g.'' how the feature is
    supported in other languages.

 >  The rationale should provide evidence of consensus within the
    community and discuss important objections or concerns raised
    during discussion.

 7. ''Reference Implementation'' - The reference implementation must
    be completed before any TIP requiring such is given status
    ''Final'', but it need not be completed before the TIP is
    accepted.  It is better to finish the specification and rationale
    first and reach consensus on it before writing code.

 >  The final implementation must include test code and documentation
    appropriate for either the Tcl language reference or the standard
    library reference.

~ TIP Style

TIPs are written in plain ASCII text with an RFC822-like header and
embedded sequences suitable for Wiki-like processing as indicated in
[3].

There are Tcl scripts that convert the TIP into HTML for viewing on
the web.  Scripts for producing other formats are available too, for
example LaTeX and plain ASCII.

~ Sample Project TIP

(With thanks to William H. Duquette <[email protected]>
for suggesting this.)  Note that the TIP Editor is responsible for
allocating TIP numbers, so you can leave that unfilled.

|TIP:           ???
|Title:         The TIP Title as Plain Text
|Version:       $Revision: 1.38 $
|Author:        Author Name <[email protected]>
|State:         Draft
|Type:          Project
|Tcl-Version:   8.4
|Vote:          Pending
|Created:       31-Feb-1999
|Post-History:
|
|~ Abstract
|
|This is an example of how to write a simple project TIP.  This is the
|abstract which should consist of a single paragraph of under 200
|words.  If you need more than this, you should stop and think about
|writing a real abstract, not a whole section!  :^)
|
|~ Some Sections
|
|Yada yada yada.  Look at the sources to the various TIPs for tricks
|on how to do various things.  ''Note that for complete legal safety,
|you must specify what copyright is used.''  We prefer public domain,
|as it allows others (notably the TIP editor(s)) to maintain the TIP
|as necessary without having to seek permission.
|
|I also prefer to make sure TIP and section titles are capitalized
|according to the usual rules of English.
|
|~ Copyright
|
|This document has been placed in the public domain.

A more complex example is [7] by Kevin Kenny <[email protected]> (the
source is at http://www.cs.man.ac.uk/fellowsd-bin/TIP/7.tip) and which
includes demonstrations of how to use advanced features like figures
and verbatim text.  His is a very high quality TIP though, and it has
been though several revisions; don't feel too put off if your first
attempt isn't quite as good...

~ Patches

For preference, patches to Tcl should be stored separately on another
website or submitted as a separate file.  This is because (quite
rightly) the news:comp.lang.tcl.announce moderator does not allow
patches to be posted on that newsgroup.  If you want a patch to be
incorporated into the archive, please contact the TIP Editor.

----

~ Comments

 > From Don Porter  < [email protected] > :

 > 1. It is confusing that "project" TIPs defined here do not
      correspond to "projects" defined in [0].

 > 2. The TIP Workflow section should mention the web-based
      drafting service [13] as another way for members of the
      community to add their comments to a draft TIP.

 > 3. The TIP Workflow section calls for TCT acceptance of a
      project TIP implementation to move it from state Accepted
      to state Final.  This conflicts with [0] which delegates that
      acceptance task to maintainers.

 > 4. It is not clear how the TIP workflow state diagram applies
      to non-project TIPs.  Non-project TIPs do not have an
      implementation.  Do they move straight from state Draft to
      state Final when they receive TCT approval?  Or do they
      just stay in state Accepted forever with no need to move to
      state Final?

 > 5. It should be noted in the TIP Workflow section that according
      to [0] a project TIP cannot be approved (and therefore should
      not be sponsored) until the TIP names a committed implementor.

 > 6. The Patches section indicates that patches in the TIP are
      incompatible with posting to comp.lang.tcl.announce, so
      earlier sections of this TIP should not indicate that including
      patches in the TIP is an acceptable practice.

 > 7. Should process TIPs be reserved for those proposals that
      revise [0] and require 2/3 support of the entire TCT?

From Mo DeJong:

It seems like we have a documentation problem with
respect to how a TIP becomes "un-rejected".

The text says:

 > ... may accept or reject a TIP or send it back to the author(s)
   for revision"

But the state transition diagram shows no way to go from
''Rejected'' to ''Draft''. What becomes of a TIP after it
is put up for a vote? If it is rejected, should the
author create a new TIP number or can they rewrite
the original TIP?

----

''Larry W. Virden writes:''  I would really find it useful
if upon submission of a TIP, a web page, perhaps on
the Tcl'ers Wiki or elsewhere, would be referenced in
the TIP itself.  This web page would contain a summary
of the discussion to date, perhaps containing urls
to relevant postings within the tct archives, etc.
This page could be used by those looking at the
archive to quickly determine the state of the discussion,
as well as the reasons for the final disposition of the
TIP.

''Donal Fellows responds:'' Feel free to establish such things. But I've
definitely not got time to maintain them, and especially haven't got time to
go back through the archives to make the resource complete for those TIPs that
have already been voted upon.

----

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
>

|


|

|














|


|


|

|

|

|
|



|
|

|


|

|
|




|



|





|






|







|





|
|


|





|
|






|

|

|



|
|
|


|


|

|


|




|

|
|

|



|

|


|


|
|
|


|

|


|


|


|


|



|

|



|



|



|





|

|
|


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|





|


|
|





|




|


|




|










|
|







|








|



|






|










|






|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

# TIP 2: TIP Guidelines

	Author:         Andreas Kupries <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         Don Porter <[email protected]>
	Author:         Mo DeJong <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	State:          Draft
	Type:           Process
	Vote:           Pending
	Created:        12-Sep-2000
	Post-History:   
-----

# Abstract

This document describes and defines the editorial process a TCT
document \(TIP\) has to go through before accepted as official.

# What is a TIP?

TIP stands for Tcl Improvement Proposal.  A TIP is a design document
providing information to the Tcl community, or describing a new
feature for Tcl.  The TIP should provide a concise technical
specification of the feature and a rationale for the feature.

We intend TIPs to be the primary mechanisms for proposing new
features, for collecting community input on an issue, and for
documenting the design decisions that have gone into Tcl.  The TIP
author is responsible for building consensus within the community and
documenting dissenting opinions.

Because the TIPs are maintained as text files under revision control,
their history is the historical record of the feature proposal.  This
historical record is available by the normal \(CVS?\) commands for
retrieving older revisions.  For those without direct access to the
CVS tree, you can browse the current and past TIP revisions
<http://www.cs.man.ac.uk/fellowsd-bin/TIP/> .

Further details on the arguments behind the evolution of the TIP
concept and formatting can be found in the archive of the _tclcore_
mailing list
<http://aspn.activestate.com/ASPN/Mail/Browse/Threaded/tcl-core> .

# Kinds of TIPs

There are three kinds of TIPs.  A project TIP describes a new \(or
significantly updated\) feature or implementation for Tcl.  An
informative TIP describes a Tcl design issue, or provides general
guidelines or information to the Tcl community, but does not propose a
new feature.  A process TIP is like an informative TIP but the
provided guidelines are mandatory in a certain context \(as specified
in the TIP itself\).

Voting by the TCT as per the charter \(see [[0]](0.md)\) is required to make a
project or process TIP official.

# TIP Workflow

The TIP editor, Donal K. Fellows <[email protected]> _pro
tem_, is responsible for assigning numbers to each TIP and managing its
status on behalf of authors.

Everyone in the community can submit a TIP to the TIP editor. It should
contain at least a proposed title and a rough, but fleshed out, draft of the
TIP. It _must_ include a copyright statement that permits the normal
business of the TIP process as described here.

If the TIP editor approves, he will assign the TIP a number, label it as
either project, process or informational, give it status _Draft_, and create
and check-in the initial draft of the TIP. The TIP editor will not
unreasonably deny a TIP.  Reasons for denying TIP status include gross
malformatting, inappropriate copyright, duplication of effort, being
technically unsound, or not in keeping with the Tcl philosophy; the TCT and
after that John Ousterhout <[email protected]> is the final arbitrator of the
latter, as defined in the charter \([[0]](0.md)\).

Discussion concerning a TIP should initially be kept out of the
tclcore and tct mailing lists.  Instead, comments should be sent to,
and collected by, the TIP author, who has the responsibility to
incorporate these comments into the document.

_Note:_ It has been proposed to create a new mailing list for each
TIP to handle its discussion.  Rejection and finalization of the TIP
closes the mailing list, but not the archive.  Together with the CVS
history a complete record of the development of a TIP will be
available.

The authors of the TIP are responsible for writing the TIP and
marshaling community support for it.  The structure of a TIP is
described in detail in [[3]](3.md).

A project TIP consists in principle of two parts, a design document and a
reference implementation. The TIP will not normally be reviewed and accepted
before a reference implementation is begun so that the amount of time between
acceptance and a final implementation can be minimized. The implementation can
be given in the form of code, patch, or URL to same, and _must_ be applied
to the Tcl/Tk core before it can be considered _Final_; while small
reference implementations may be placed inside the TIP itself, large reference
implementations should be held externally and linked to by reference
\(typically a URL\). Authors are encouraged to use the SourceForge Patch
trackers for this purpose.

Process and Informational TIPs do not need an implementation.

TIP authors are responsible for collecting community feedback on a TIP
before submitting it for review \(the creation of a TIP is a part of
that review process.\)  However, wherever possible, long open-ended
discussions on public mailing lists should be avoided.  A better
strategy is to encourage public feedback directly to the TIP author,
who collects and integrates the comments back into the TIP.

Once the authors have completed a TIP, they must inform the Tcl Core
Team that it is ready for review.  TIPs are reviewed by the Tcl Core
Team and \(for Project TIPs\) the maintainers for the relevant parts of
the core, who may accept or reject a TIP or send it back to the
author\(s\) for revision \(as detailed in [[0]](0.md).\)  The acceptance or
rejection of a TIP will cause its state to be changed accordingly to
_Accepted_ or _Rejected_.

Once a TIP requiring a reference implementation has been accepted, the
reference implementation must be completed. When the reference implementation
is complete and accepted by the TCT \(who can reject it if they feel the
implementation would damage the rest of the core\) the status will be changed
to _Final_. This is usually done by the TIP Editor, as advised by the
responsible Tcl/Tk maintainer.

A TIP can also be assigned status _Deferred_.  The TIP author or the
editor can assign the TIP this status when no progress is being made
on the TIP.  Once a TIP is deferred, the TIP editor can re-assign it
to _Draft_ status.

A TIP can also be _Withdrawn_ by the author.  Perhaps after all is
said and done, the author believes it was not a good idea.  It is
still important to have a record of this fact.  It is expected that
_Accepted_ TIPs will only be withdrawn very rarely, and _Final_
TIPs only under exceptional circumstances.

TIP workflow is as follows:

![TIP Workflow](../assets/2workflow.gif)

Some informative TIPs may also have a status of _Active_ if they are
never meant to be completed.  For example: [[1]](1.md).

# What belongs in a successful TIP?

Each TIP should have the following parts:

 1. _Title_ - a short, descriptive title.

 2. _Author_\(s\) - names and contact info \(email addresses\) for each
    author.

 3. _Abstract_ - a short \(typically <200 word\) description of the
    technical issue being addressed.

 4. _Copyright_/public domain - Each TIP must either be explicitly
    labelled in the public domain \(the preferred 'license'\) or the
    Open Publication License <http://www.opencontent.org/openpub/> .
    It is recommended that this be done by making the last section of
    the document be a copyright heading, with the body describing what
    copyright \(if any\) the document is released under.

 5. _Specification_ - Project TIPs should have a technical
    specification that should describe the syntax and semantics of any
    new language feature.  The specification should be detailed enough
    to allow \(competing\) interoperable implementations for any of the
    current Tcl platforms.

 6. _Rationale_ - The rationale fleshes out the specification by
    describing what motivated the design and why particular design
    decisions were made.  It should describe alternate designs that
    were considered and related work, _e.g._ how the feature is
    supported in other languages.

	 >  The rationale should provide evidence of consensus within the
    community and discuss important objections or concerns raised
    during discussion.

 7. _Reference Implementation_ - The reference implementation must
    be completed before any TIP requiring such is given status
    _Final_, but it need not be completed before the TIP is
    accepted.  It is better to finish the specification and rationale
    first and reach consensus on it before writing code.

	 >  The final implementation must include test code and documentation
    appropriate for either the Tcl language reference or the standard
    library reference.

# TIP Style

TIPs are written in plain ASCII text with an RFC822-like header and
embedded sequences suitable for Wiki-like processing as indicated in
[[3]](3.md).

There are Tcl scripts that convert the TIP into HTML for viewing on
the web.  Scripts for producing other formats are available too, for
example LaTeX and plain ASCII.

# Sample Project TIP

\(With thanks to William H. Duquette <[email protected]>
for suggesting this.\)  Note that the TIP Editor is responsible for
allocating TIP numbers, so you can leave that unfilled.

	TIP:           ???
	Title:         The TIP Title as Plain Text
	Version:       $Revision: 1.38 $
	Author:        Author Name <[email protected]>
	State:         Draft
	Type:          Project
	Tcl-Version:   8.4
	Vote:          Pending
	Created:       31-Feb-1999
	Post-History:
	
	~ Abstract
	
	This is an example of how to write a simple project TIP.  This is the
	abstract which should consist of a single paragraph of under 200
	words.  If you need more than this, you should stop and think about
	writing a real abstract, not a whole section!  :^)
	
	~ Some Sections
	
	Yada yada yada.  Look at the sources to the various TIPs for tricks
	on how to do various things.  ''Note that for complete legal safety,
	you must specify what copyright is used.''  We prefer public domain,
	as it allows others (notably the TIP editor(s)) to maintain the TIP
	as necessary without having to seek permission.
	
	I also prefer to make sure TIP and section titles are capitalized
	according to the usual rules of English.
	
	~ Copyright
	
	This document has been placed in the public domain.

A more complex example is [[7]](7.md) by Kevin Kenny <[email protected]> \(the
source is at <http://www.cs.man.ac.uk/fellowsd-bin/TIP/7.tip\)> and which
includes demonstrations of how to use advanced features like figures
and verbatim text.  His is a very high quality TIP though, and it has
been though several revisions; don't feel too put off if your first
attempt isn't quite as good...

# Patches

For preference, patches to Tcl should be stored separately on another
website or submitted as a separate file.  This is because \(quite
rightly\) the news:comp.lang.tcl.announce moderator does not allow
patches to be posted on that newsgroup.  If you want a patch to be
incorporated into the archive, please contact the TIP Editor.

----

# Comments

 > From Don Porter  < [email protected] > :

 > 1. It is confusing that "project" TIPs defined here do not
      correspond to "projects" defined in [[0]](0.md).

 > 2. The TIP Workflow section should mention the web-based
      drafting service [[13]](13.md) as another way for members of the
      community to add their comments to a draft TIP.

 > 3. The TIP Workflow section calls for TCT acceptance of a
      project TIP implementation to move it from state Accepted
      to state Final.  This conflicts with [[0]](0.md) which delegates that
      acceptance task to maintainers.

 > 4. It is not clear how the TIP workflow state diagram applies
      to non-project TIPs.  Non-project TIPs do not have an
      implementation.  Do they move straight from state Draft to
      state Final when they receive TCT approval?  Or do they
      just stay in state Accepted forever with no need to move to
      state Final?

 > 5. It should be noted in the TIP Workflow section that according
      to [[0]](0.md) a project TIP cannot be approved \(and therefore should
      not be sponsored\) until the TIP names a committed implementor.

 > 6. The Patches section indicates that patches in the TIP are
      incompatible with posting to comp.lang.tcl.announce, so
      earlier sections of this TIP should not indicate that including
      patches in the TIP is an acceptable practice.

 > 7. Should process TIPs be reserved for those proposals that
      revise [[0]](0.md) and require 2/3 support of the entire TCT?

From Mo DeJong:

It seems like we have a documentation problem with
respect to how a TIP becomes "un-rejected".

The text says:

 > ... may accept or reject a TIP or send it back to the author\(s\)
   for revision"

But the state transition diagram shows no way to go from
_Rejected_ to _Draft_. What becomes of a TIP after it
is put up for a vote? If it is rejected, should the
author create a new TIP number or can they rewrite
the original TIP?

----

_Larry W. Virden writes:_  I would really find it useful
if upon submission of a TIP, a web page, perhaps on
the Tcl'ers Wiki or elsewhere, would be referenced in
the TIP itself.  This web page would contain a summary
of the discussion to date, perhaps containing urls
to relevant postings within the tct archives, etc.
This page could be used by those looking at the
archive to quickly determine the state of the discussion,
as well as the reasons for the final disposition of the
TIP.

_Donal Fellows responds:_ Feel free to establish such things. But I've
definitely not got time to maintain them, and especially haven't got time to
go back through the archives to make the resource complete for those TIPs that
have already been voted upon.

----

# Copyright

This document has been placed in the public domain.

Name change from tip/20.tip to tip/20.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

TIP:		20
Title:		Add C Locale-Exact CType Functions
Version:	$Revision: 1.4 $
Author:		Jeffrey Hobbs <[email protected]>
State:		Deferred
Type:		Project
Tcl-Version:	8.5
Vote:		Pending
Created:	08-Jan-2001
Post-History: 


~Abstract

This TIP adds functions to Tcl that are a subset of the standard ctype
functions (isspace, isalpha, ...) that are ensured to operate only in
the C locale (char < 0x80).

~Rationale

Tcl used to force the C locale everywhere in order to have parsing
work as expected throughout Tcl, but that prevented certain i18n
features from working correctly (like native character input).  In
enabling the i18n features, some bugs (like
[http://sf.net/bugs/?func=detailbug&bug_id=127512&group_id=10894])
were exposed that required the C locale to be enabled to function
properly.  Since we don't want to force that requirement, creating
ctype functions that work as if they were always in the C locale is
the best solution.

~Reference Implementation

Add a file ''generic/tclC.c'' (to parallel ''generic/tclUtf.c'') that
contains functions following the convention C_isspace, C_isalpha, ...
These functions would use character or bit maps to ensure greatest
speed and efficiency of the functions.

Not all use of the ctype functions need be replaced.  Those that walk
over a string, especially backwards, are the ones that need
replacement.

~ Copyright 

This document is in the public domain. 

<
|
<
|
|
|
|
|
|
|
>

|


|
|

|



|
|
|





|

|
|







|


>

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

# TIP 20: Add C Locale-Exact CType Functions

	Author:		Jeffrey Hobbs <[email protected]>
	State:		Deferred
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Pending
	Created:	08-Jan-2001
	Post-History: 
-----

# Abstract

This TIP adds functions to Tcl that are a subset of the standard ctype
functions \(isspace, isalpha, ...\) that are ensured to operate only in
the C locale \(char < 0x80\).

# Rationale

Tcl used to force the C locale everywhere in order to have parsing
work as expected throughout Tcl, but that prevented certain i18n
features from working correctly \(like native character input\).  In
enabling the i18n features, some bugs \(like
<http://sf.net/bugs/?func=detailbug&bug_id=127512&group_id=10894> \)
were exposed that required the C locale to be enabled to function
properly.  Since we don't want to force that requirement, creating
ctype functions that work as if they were always in the C locale is
the best solution.

# Reference Implementation

Add a file _generic/tclC.c_ \(to parallel _generic/tclUtf.c_\) that
contains functions following the convention C\_isspace, C\_isalpha, ...
These functions would use character or bit maps to ensure greatest
speed and efficiency of the functions.

Not all use of the ctype functions need be replaced.  Those that walk
over a string, especially backwards, are the ones that need
replacement.

# Copyright 

This document is in the public domain. 

Name change from tip/200.tip to tip/200.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

TIP:            200
Title:          Listing the Values in an Array
Version:        $Revision: 1.4 $
Author:         Donal K. Fellows <[email protected]>
Author:         Dossy Shiobara <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        20-May-2004
Post-History:   
Keywords:       Tcl
Tcl-Version:    8.5


~ Abstract

This TIP proposes adding another subcommand to the '''array''' command
to list the values in an array.

~ Rationale

Currently, the easiest ways of building a list of all values within an
array involve either iterating over the names of the array elements
and then reading the value at each step, or iterating over the result
of '''array get''' and dropping the ''name'' part of each pair, as can
be seen from these code examples:

|set list {}
|foreach name [array names SomeArray] {
|   lappend list $SomeArray($name)
|}

|
|set list {}
|foreach {name value} [array get SomeArray] {
|   lappend list $value
|}


Neither of these is especially efficient, since the first does a very
large number of array reads, and the second builds a very large
intermediate list (particularly if you subsequently want to filter the
values to select a subset of them.)

It would be better if the functionality was added directly to the Tcl
core, especially as the conceptual overhead would be very low as there
are already subcommands of '''array''' for returning both the names of
the array and the name/value pairs.

~ Proposed Change

I propose to add a new subcommand to '''array''' called '''values'''
with the following syntax:

 > '''array values''' ''arrayName'' ?''globPattern''?

This returns a list of values that are contained in the array in the
"natural order" of the values within the array.  The optional
''globPattern'' argument allows for returning only some of the values
in the array (those values for keys that match the pattern according
to the rules of '''string match''').  The pattern will not change the
ordering of the list; it only filters the result.

The order of the values returned shall be such that the following two
'''foreach''' iterations shall behave identically (modulo traces on
the array variable):

|foreach {name value} [array get AnyArray $pattern] {
|   AnyScript
|}


|foreach name  [array names  AnyArray $pattern] \
|        value [array values AnyArray $pattern] {
|   AnyScript
|}


Note that this implies that the resulting list from '''array values'''
may well contain duplicates, and that none of the values actually
returned will necessarily match the supplied pattern.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|




|


|
|
|
<
>
|
|
|
|
<
>



|
|



|


|

|


|



|
|
|



|
|

|
|
<
|
>
|
|
|
<
|
>
|



|


>

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

# TIP 200: Listing the Values in an Array

	Author:         Donal K. Fellows <[email protected]>
	Author:         Dossy Shiobara <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        20-May-2004
	Post-History:   
	Keywords:       Tcl
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes adding another subcommand to the **array** command
to list the values in an array.

# Rationale

Currently, the easiest ways of building a list of all values within an
array involve either iterating over the names of the array elements
and then reading the value at each step, or iterating over the result
of **array get** and dropping the _name_ part of each pair, as can
be seen from these code examples:

	set list {}
	foreach name [array names SomeArray] {
	   lappend list $SomeArray($name)

	}
	
	set list {}
	foreach {name value} [array get SomeArray] {
	   lappend list $value

	}

Neither of these is especially efficient, since the first does a very
large number of array reads, and the second builds a very large
intermediate list \(particularly if you subsequently want to filter the
values to select a subset of them.\)

It would be better if the functionality was added directly to the Tcl
core, especially as the conceptual overhead would be very low as there
are already subcommands of **array** for returning both the names of
the array and the name/value pairs.

# Proposed Change

I propose to add a new subcommand to **array** called **values**
with the following syntax:

 > **array values** _arrayName_ ?_globPattern_?

This returns a list of values that are contained in the array in the
"natural order" of the values within the array.  The optional
_globPattern_ argument allows for returning only some of the values
in the array \(those values for keys that match the pattern according
to the rules of **string match**\).  The pattern will not change the
ordering of the list; it only filters the result.

The order of the values returned shall be such that the following two
**foreach** iterations shall behave identically \(modulo traces on
the array variable\):

	foreach {name value} [array get AnyArray $pattern] {
	   AnyScript

	}

	foreach name  [array names  AnyArray $pattern] \
	        value [array values AnyArray $pattern] {
	   AnyScript

	}

Note that this implies that the resulting list from **array values**
may well contain duplicates, and that none of the values actually
returned will necessarily match the supplied pattern.

# Copyright

This document has been placed in the public domain.

Name change from tip/201.tip to tip/201.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

TIP:            201
Title:          Add 'in' Operator to [expr]
Version:        $Revision: 1.5 $
Author:         Jeff Hobbs <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        21-May-2004
Post-History:   
Keywords:       Tk,list membership,sets
Tcl-Version:    8.5


~ Abstract

This TIP proposes new '''expr''' operators "'''in'''" and "'''ni'''" that simplifies the standard "does this item exist in list" '''lsearch''' case in expressions, with "'''ni'''" being "not in".

~ Rationale

The addition of '''in''' and '''ni''' operators is syntactic sugar for the
verbose '''lsearch''' operation that checks for a single items
existence (or non-existence) in a list.  It serves to simplify the reading and writing of
code that requires this comparatively-common operation.  The
operators will do '''lsearch -exact''' searching as well, which would
correct an inadvertant bug that many users introduce into their code
when they write:

| if {[lsearch $list $item] != -1} { ... }

as '''lsearch''' does '''-glob''' matching by default.  I have found
this error repeated often in user code.

Note that [133] uses an '''in''' operator as a motivating case, but is
actually proposing a much more general alteration.

~ Specification

A new infix '''expr''' operators '''in''' and '''ni''' will be added, making the
following pairs of commands equivalent (assuming nobody has redefined
'''lsearch''' of course):

 * Searching for an arbitrary item in an arbitrary list.

| if {[lsearch -exact $list $item] != -1} { ... }
| if {$item in $list} { ... }

 * Checking for the absence of an arbitrary item from an arbitrary
   list.

| if {[lsearch -exact $list $item] == -1} { ... }
| if {$item ni $list} { ... }

~ Comments

There was a proposal to add a separate operator "'''!in'''" to do
negated membership testing, but that significantly complicates the
expression parser and is likely to be harder to teach to newcomers to
Tcl, since it looks like the application of an operator to another
operator.

'''notin''' and '''ni''' were also suggested, and '''ni''' was accepted as a reasonable pair for "not in", similar to '''ne''' being "not equal".  There was some concern about '''ni''' in that TeX has a different interpretation, but that is unlikely to confuse the majority of Tcl users.

~ Reference Implementation

''[[To Follow]]''

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|

|

|
|
|

|



|

|


|


|

|
|
|



|
|




|
|

|

|





|

|

|

|


>

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

# TIP 201: Add 'in' Operator to [expr]

	Author:         Jeff Hobbs <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        21-May-2004
	Post-History:   
	Keywords:       Tk,list membership,sets
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes new **expr** operators "**in**" and "**ni**" that simplifies the standard "does this item exist in list" **lsearch** case in expressions, with "**ni**" being "not in".

# Rationale

The addition of **in** and **ni** operators is syntactic sugar for the
verbose **lsearch** operation that checks for a single items
existence \(or non-existence\) in a list.  It serves to simplify the reading and writing of
code that requires this comparatively-common operation.  The
operators will do **lsearch -exact** searching as well, which would
correct an inadvertant bug that many users introduce into their code
when they write:

	 if {[lsearch $list $item] != -1} { ... }

as **lsearch** does **-glob** matching by default.  I have found
this error repeated often in user code.

Note that [[133]](133.md) uses an **in** operator as a motivating case, but is
actually proposing a much more general alteration.

# Specification

A new infix **expr** operators **in** and **ni** will be added, making the
following pairs of commands equivalent \(assuming nobody has redefined
**lsearch** of course\):

 * Searching for an arbitrary item in an arbitrary list.

		 if {[lsearch -exact $list $item] != -1} { ... }
		 if {$item in $list} { ... }

 * Checking for the absence of an arbitrary item from an arbitrary
   list.

		 if {[lsearch -exact $list $item] == -1} { ... }
		 if {$item ni $list} { ... }

# Comments

There was a proposal to add a separate operator "**!in**" to do
negated membership testing, but that significantly complicates the
expression parser and is likely to be harder to teach to newcomers to
Tcl, since it looks like the application of an operator to another
operator.

**notin** and **ni** were also suggested, and **ni** was accepted as a reasonable pair for "not in", similar to **ne** being "not equal".  There was some concern about **ni** in that TeX has a different interpretation, but that is unlikely to confuse the majority of Tcl users.

# Reference Implementation

_[To Follow]_

# Copyright

This document has been placed in the public domain.

Name change from tip/202.tip to tip/202.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

TIP:		202
Title:		Add 2>@1 Special Case to [open] and [exec]
Version:	$Revision: 1.4 $
Author:		Jeff Hobbs <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Created:	19-May-2004
Post-History:	
Keywords:	Tcl, redirection


~ Abstract

This TIP proposes adding a new redirection case '2>@1' that redirects
the error channel to the output channel in '''open''' and '''exec'''.
This would only be valid at the end of a pipeline.

~ Rationale

Tcl is currently limited on how ''stderr'' can be managed from a
command opened with '''open |''' or '''exec'''.  This TIP adds the
ability to simply combine the ''stderr'' stream with the ''stdout''
stream by adding a new output redirection case, '''2>@1''' (i.e. as in
Bourne shell syntax), that is only ever valid as the last redirection
item in a pipeline.  This will enable simple capturing of ''stderr''
as well as ''stdout'' across platforms.

The behavior is similar to '''2>@stdout''', but that does not work
across platforms.  The difference is that directs to a real ''stdout''
file channel (which is not available in Windows wish for example),
whereas '''2>@1''' would redirect to the output result for
'''exec'''/'''open'''.

The intention is to handle the common case of wanting to capture
''stderr'' as well as ''stdout'' output from a single command.  This
operator is only valid as the last redirection operator.  To redirect
''stderr'' of previous commands along with their ''stdout'', use the
preexisting '''|&''' pipe operator.

This is backwards compatible as '''2>@1''' currently raises an error
that "1" is not a valid file id (Tcl does not create such file ids).

~~ Examples

| set fid [open "|$cmd 2>@1"]
| set result [exec $cmd 2>@1]

~ Reference Implementation 

See SF Tcl Patch 957132
[http://sf.net/tracker/?func=detail&aid=957132&group_id=10894&atid=310894]
for details.

~ Copyright 

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|


|

|
|
|
|
|
|
|

|
|
|
|
|


|

|
|

|
|

|

|
|

|


|


|


>

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

# TIP 202: Add 2>@1 Special Case to [open] and [exec]

	Author:		Jeff Hobbs <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Created:	19-May-2004
	Post-History:	
	Keywords:	Tcl, redirection
-----

# Abstract

This TIP proposes adding a new redirection case '2>@1' that redirects
the error channel to the output channel in **open** and **exec**.
This would only be valid at the end of a pipeline.

# Rationale

Tcl is currently limited on how _stderr_ can be managed from a
command opened with **open \|** or **exec**.  This TIP adds the
ability to simply combine the _stderr_ stream with the _stdout_
stream by adding a new output redirection case, **2>@1** \(i.e. as in
Bourne shell syntax\), that is only ever valid as the last redirection
item in a pipeline.  This will enable simple capturing of _stderr_
as well as _stdout_ across platforms.

The behavior is similar to **2>@stdout**, but that does not work
across platforms.  The difference is that directs to a real _stdout_
file channel \(which is not available in Windows wish for example\),
whereas **2>@1** would redirect to the output result for
**exec**/**open**.

The intention is to handle the common case of wanting to capture
_stderr_ as well as _stdout_ output from a single command.  This
operator is only valid as the last redirection operator.  To redirect
_stderr_ of previous commands along with their _stdout_, use the
preexisting **\|&** pipe operator.

This is backwards compatible as **2>@1** currently raises an error
that "1" is not a valid file id \(Tcl does not create such file ids\).

## Examples

	 set fid [open "|$cmd 2>@1"]
	 set result [exec $cmd 2>@1]

# Reference Implementation 

See SF Tcl Patch 957132
<http://sf.net/tracker/?func=detail&aid=957132&group_id=10894&atid=310894> 
for details.

# Copyright 

This document has been placed in the public domain.

Name change from tip/203.tip to tip/203.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

TIP:            203
Title:          Create tclConfig.sh-Equivalent in Tcl
Version:        $Revision: 1.11 $
Author:         Colin McCormack <[email protected]>
Author:         Don Porter <[email protected]>
Author:         Colin McCormack <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        17-Jun-2004
Post-History:   
Discussions-To: http://mini.net/tcl/tclConfig.sh
Keywords:       configuration,installation
Tcl-Version:    8.5


~ Abstract

This proposal requires the registration of information about the built process, currently stored in tclConfig.sh, by means of the Tcl_RegisterConfig mechanism set out in [Tip 59].

~ Rationale

Packages such as Critcl[http://www.equi4.com/critcl.html], and indeed
anything written in pure tcl which tries to build extensions under Tcl need more introspection to discover the ground rules of construction in the installation in which they find themselves.

In order to facilitate such future build tools, the build information
should be made available to Tcl scripts.

~ Specification

Every variable defined in the unix tclConfig.sh should be registered using '''Tcl_RegisterConfig''', with the following exceptions:

 * TCL_VERSION and similar redundant version, patch level information.

 * TCL_THREADS - redundant.

 * TCL_BUILD_* - nothing specifying the build directory.

Because Windows and other platforms don't have a tclConfig.sh, the following fields are desirable for hand construction:
----
'''Compilation:'''
 * TCL_CC # C compiler to use for compilation.

 * TCL_DEFS # -D flags for use with the C compiler.

 * TCL_INCLUDE_SPEC # String to pass to the compiler so that an extension can find installed Tcl headers.

 * TCL_LIB_FILE # The name of the Tcl library

 * TCL_LIBS # Additional libraries to use when linking Tcl.

 * TCL_SHLIB_CFLAGS # Flags to pass to cc when compiling the components of a shared library:

 * TCL_CFLAGS_WARNING # Flags to pass to cc to get warning messages

 * TCL_EXTRA_CFLAGS # Extra flags to pass to cc:
----
'''Linking:'''

 * TCL_SHLIB_LD # Base command to use for combining object files into a shared library:

 * TCL_SHLIB_LD_LIBS # dependent libraries should be included when linking shared libraries

 * TCL_SH
LIB_SUFFIX # Suffix to use for the name of a shared library.

 * TCL_LD_FLAGS # Flags to pass to the compiler when linking object files into an executable tclsh or tcltest binary.

 * TCL_COMPAT_OBJS # Additional object files linked with Tcl to provide compatibility with standard facilities from ANSI C or POSIX.

 * TCL_LIB_FLAG # -l flag to pass to the linker to pick up the Tcl library

 * TCL_LIB_SPEC # String to pass to linker to pick up the Tcl library from its installed directory.

----
'''Stub Support:'''

 * TCL_SUPPORTS_STUBS # Tcl supports stub.

 * TCL_STUB_LIB_FILE # The name of the Tcl stub library (.a):

 * TCL_STUB_LIB_FLAG # -l flag to pass to the linker to pick up the Tcl stub library
 * TCL_STUB_LIB_SPEC # String to pass to linker to pick up the Tcl stub library from its installed directory.
 * TCL_STUB_LIB_PATH # Path to the Tcl stub library in the install directory.
----

~ Comments

How about converting this proposal into
a proposal listing the values found in
''tclConfig.sh'' and proposing that Tcl
should pass those values into
'''Tcl_RegisterConfig''' during initialization?
That would make all the values available
to scripts via the '''::tcl::pkgconfig''' command. -- Good idea.  Done.

Several of the assigned values in tclConfig.sh contain references to other variables - should these be reproduced verbatim, or evaluated prior to registration?  I'm leaning toward verbatim storage: let the people who need the data construct an evaluation which serves their purposes because (a) the form is easy enough to evaluate, as in the parser I threw together [http://mini.net/tcl/tclConfig.sh], (b) there might be information in the verbatim form which needs to be preserved.  Comments welcome.

~ Withdrawal

Joe English points out that those parts potentially useful to a pure-tcl builder are not necessarily applicable, since the build and installation machines may/will differ substantially, and that those parts universally applicable are available via some combination of info and ::tcl::pkgconfig.  Given this insight, I withdraw this TIP.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
>

|

|

|

|





|

|

|

|

|



|
|

|

|

|

|

|

|

|

|

|

|

|
|

|

|

|

|


|

|

|

|
|
|


|



|

|

|

|

|



|


>

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

# TIP 203: Create tclConfig.sh-Equivalent in Tcl

	Author:         Colin McCormack <[email protected]>
	Author:         Don Porter <[email protected]>
	Author:         Colin McCormack <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        17-Jun-2004
	Post-History:   
	Discussions-To: http://mini.net/tcl/tclConfig.sh
	Keywords:       configuration,installation
	Tcl-Version:    8.5
-----

# Abstract

This proposal requires the registration of information about the built process, currently stored in tclConfig.sh, by means of the Tcl\_RegisterConfig mechanism set out in [Tip 59].

# Rationale

Packages such as Critcl<http://www.equi4.com/critcl.html> , and indeed
anything written in pure tcl which tries to build extensions under Tcl need more introspection to discover the ground rules of construction in the installation in which they find themselves.

In order to facilitate such future build tools, the build information
should be made available to Tcl scripts.

# Specification

Every variable defined in the unix tclConfig.sh should be registered using **Tcl\_RegisterConfig**, with the following exceptions:

 * TCL\_VERSION and similar redundant version, patch level information.

 * TCL\_THREADS - redundant.

 * TCL\_BUILD\_\* - nothing specifying the build directory.

Because Windows and other platforms don't have a tclConfig.sh, the following fields are desirable for hand construction:
----
**Compilation:**
 * TCL\_CC \# C compiler to use for compilation.

 * TCL\_DEFS \# -D flags for use with the C compiler.

 * TCL\_INCLUDE\_SPEC \# String to pass to the compiler so that an extension can find installed Tcl headers.

 * TCL\_LIB\_FILE \# The name of the Tcl library

 * TCL\_LIBS \# Additional libraries to use when linking Tcl.

 * TCL\_SHLIB\_CFLAGS \# Flags to pass to cc when compiling the components of a shared library:

 * TCL\_CFLAGS\_WARNING \# Flags to pass to cc to get warning messages

 * TCL\_EXTRA\_CFLAGS \# Extra flags to pass to cc:
----
**Linking:**

 * TCL\_SHLIB\_LD \# Base command to use for combining object files into a shared library:

 * TCL\_SHLIB\_LD\_LIBS \# dependent libraries should be included when linking shared libraries

 * TCL\_SH
LIB\_SUFFIX \# Suffix to use for the name of a shared library.

 * TCL\_LD\_FLAGS \# Flags to pass to the compiler when linking object files into an executable tclsh or tcltest binary.

 * TCL\_COMPAT\_OBJS \# Additional object files linked with Tcl to provide compatibility with standard facilities from ANSI C or POSIX.

 * TCL\_LIB\_FLAG \# -l flag to pass to the linker to pick up the Tcl library

 * TCL\_LIB\_SPEC \# String to pass to linker to pick up the Tcl library from its installed directory.

----
**Stub Support:**

 * TCL\_SUPPORTS\_STUBS \# Tcl supports stub.

 * TCL\_STUB\_LIB\_FILE \# The name of the Tcl stub library \(.a\):

 * TCL\_STUB\_LIB\_FLAG \# -l flag to pass to the linker to pick up the Tcl stub library
 * TCL\_STUB\_LIB\_SPEC \# String to pass to linker to pick up the Tcl stub library from its installed directory.
 * TCL\_STUB\_LIB\_PATH \# Path to the Tcl stub library in the install directory.
----

# Comments

How about converting this proposal into
a proposal listing the values found in
_tclConfig.sh_ and proposing that Tcl
should pass those values into
**Tcl\_RegisterConfig** during initialization?
That would make all the values available
to scripts via the **::tcl::pkgconfig** command. -- Good idea.  Done.

Several of the assigned values in tclConfig.sh contain references to other variables - should these be reproduced verbatim, or evaluated prior to registration?  I'm leaning toward verbatim storage: let the people who need the data construct an evaluation which serves their purposes because \(a\) the form is easy enough to evaluate, as in the parser I threw together <http://mini.net/tcl/tclConfig.sh> , \(b\) there might be information in the verbatim form which needs to be preserved.  Comments welcome.

# Withdrawal

Joe English points out that those parts potentially useful to a pure-tcl builder are not necessarily applicable, since the build and installation machines may/will differ substantially, and that those parts universally applicable are available via some combination of info and ::tcl::pkgconfig.  Given this insight, I withdraw this TIP.

# Copyright

This document has been placed in the public domain.

Name change from tip/204.tip to tip/204.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

TIP:		204
Title:		Virtual Events for Keyboard Traversal
Version:	$Revision: 1.5 $
Author:		Joe English <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Created:	21-Jun-2004
Post-History:	


~ Abstract

Proposes using two new virtual events, '''<<TraverseIn>>''' and
'''<<TraverseOut>>''', to notify widgets of keyboard navigation
events.

~ Rationale

Certain widgets need to perform some action when they receive and/or
lose keyboard focus because of keyboard traversal.  For example,
tabbing into an Entry or Spinbox widget selects the widget contents.

This cannot be done with a <FocusIn> binding, since widgets may
receive <FocusIn> events for reasons other than keyboard traversal.

Tk currently implements this feature with special-case logic that
checks the target window's widget class in the ''tk::TabToWindow''
procedure.  The drawback to this approach is that it only works for
the built-in widgets; third party widget sets like
BWidget[http://tcllib.sf.net/],
IWidgets[http://sf.net/projects/incrtcl/], and
Tile[http://tktable.sf.net/tile/] must implement their own
workarounds.

~ Proposal

Change the standard Tk bindings for <Key-Tab> and <Shift-Key-Tab> to
do the following:

 * Send a '''<<TraverseOut>>''' virtual event to the current focus
   window, if any;

 * Set the focus to the new window;

 * Send a '''<<TraverseIn>>''' virtual event to the new window.

Additionally, move the current code to handle traversal to Entry and
Spinbox widgets from ''tk::TabToWindow'' to class bindings.

~ Implementation

See Tk Patch #976928[http://sourceforge.net/support/tracker.php?aid=976928].

The BWidget package has used an identical scheme since version 1.7;
see Tcllib bug
#720032[http://sourceforge.net/support/tracker.php?aid=720032] for
details.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|


|









|


|
|
|


|




|




|


|

|

|



|


|


>

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

# TIP 204: Virtual Events for Keyboard Traversal

	Author:		Joe English <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Created:	21-Jun-2004
	Post-History:	
-----

# Abstract

Proposes using two new virtual events, **<<TraverseIn>>** and
**<<TraverseOut>>**, to notify widgets of keyboard navigation
events.

# Rationale

Certain widgets need to perform some action when they receive and/or
lose keyboard focus because of keyboard traversal.  For example,
tabbing into an Entry or Spinbox widget selects the widget contents.

This cannot be done with a <FocusIn> binding, since widgets may
receive <FocusIn> events for reasons other than keyboard traversal.

Tk currently implements this feature with special-case logic that
checks the target window's widget class in the _tk::TabToWindow_
procedure.  The drawback to this approach is that it only works for
the built-in widgets; third party widget sets like
BWidget<http://tcllib.sf.net/> ,
IWidgets<http://sf.net/projects/incrtcl/> , and
Tile<http://tktable.sf.net/tile/>  must implement their own
workarounds.

# Proposal

Change the standard Tk bindings for <Key-Tab> and <Shift-Key-Tab> to
do the following:

 * Send a **<<TraverseOut>>** virtual event to the current focus
   window, if any;

 * Set the focus to the new window;

 * Send a **<<TraverseIn>>** virtual event to the new window.

Additionally, move the current code to handle traversal to Entry and
Spinbox widgets from _tk::TabToWindow_ to class bindings.

# Implementation

See Tk Patch \#976928<http://sourceforge.net/support/tracker.php?aid=976928> .

The BWidget package has used an identical scheme since version 1.7;
see Tcllib bug
\#720032<http://sourceforge.net/support/tracker.php?aid=720032>  for
details.

# Copyright

This document has been placed in the public domain.

Name change from tip/205.tip to tip/205.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

TIP:            205
Title:          Use pkgconfig Database to Register Xft Support
Version:        $Revision: 1.5 $
Author:         Joe English <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        23-Jun-2004
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes to use Tcl's package configuration database (see
[59]) to register whether Tk was compiled with support for Xft.

~ Rationale

As of version 8.5, Tk has optional support for Xft (the modern
replacement for server-side fonts in X11).  However, at present
application code has no way to determine whether or not Xft support
was enabled when Tk was built.  The package configuration database
facility introduced in [59] seems like an ideal place to record this
information.

~ Proposal

If Tk was configured with ''--enable-xft'', the command

| tk::pkgconfig get fontsystem

shall return the value '''xft'''.

~ Notes

The change as currently proposed is the minimum necessary to satisfy
the requirement listed in the Rationale.  In particular: nothing else
in Tk currently calls ''Tcl_RegisterConfig()'', so if Xft support is
not enabled the '''tk::pkgconfig''' command will remain undefined.

This TIP (or something like it) is a prerequisite for a script-level implementation of [145], which will need to distinguish whether or not Xft is in use.

~ Implementation

See Tk Patch #976520[http://sourceforge.net/support/tracker.php?aid=976520]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|

|

|
|


|


|

|

|

|

|



|
|

|

|

|

|


>

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

# TIP 205: Use pkgconfig Database to Register Xft Support

	Author:         Joe English <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        23-Jun-2004
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to use Tcl's package configuration database \(see
[[59]](59.md)\) to register whether Tk was compiled with support for Xft.

# Rationale

As of version 8.5, Tk has optional support for Xft \(the modern
replacement for server-side fonts in X11\).  However, at present
application code has no way to determine whether or not Xft support
was enabled when Tk was built.  The package configuration database
facility introduced in [[59]](59.md) seems like an ideal place to record this
information.

# Proposal

If Tk was configured with _--enable-xft_, the command

	 tk::pkgconfig get fontsystem

shall return the value **xft**.

# Notes

The change as currently proposed is the minimum necessary to satisfy
the requirement listed in the Rationale.  In particular: nothing else
in Tk currently calls _Tcl\_RegisterConfig\(\)_, so if Xft support is
not enabled the **tk::pkgconfig** command will remain undefined.

This TIP \(or something like it\) is a prerequisite for a script-level implementation of [[145]](145.md), which will need to distinguish whether or not Xft is in use.

# Implementation

See Tk Patch \#976520<http://sourceforge.net/support/tracker.php?aid=976520> 

# Copyright

This document has been placed in the public domain.

Name change from tip/206.tip to tip/206.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

TIP:            206
Title:          Add an [ftruncate] Command
Version:        $Revision: 1.5 $
Author:         Joe Mistachkin <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        25-Jun-2004
Post-History:   
Tcl-Version:    8.5
Obsoleted-By:	208


~ Abstract

This TIP proposes a new command '''ftruncate''' for truncating open
files.

~ Note

This TIP has been effectively rolled into [208].

~ Rationale

In Tcl, there is currently no way to truncate a file while it is open
even though all modern operating systems support such an operation.
The current workaround is to close the file and reopen it.  However,
in cases where the file must be held open (e.g. on Unix where the file
has already been deleted and is just being used as scratch space) this
workaround cannot be used.

~ Specification

 > '''ftruncate''' ''channelId'' ?''length''?

The channel specified by ''channelId'' must refer to a file that was
opened for writing.  The ''length'' argument must be greater than or
equal to zero and can be bigger than the current size of the file.  If
the ''length'' argument is omitted, the file will be truncated at the current access position.  This command will return any errors received from the operating system.

~~Example Usage

|# Open the file for reading and writing...
|set file [open "test.txt" {RDWR}]
|# Write some data to the file...
|puts $file "test data"
|
|# Some time later...
|# ... ... ...
|ftruncate $file
|# ... ... ...
|
|# We are done, close the file...
|close $file

~ Proposed C API Changes

A new function named '''Tcl_TruncateChannel''' would be added to the
Tcl C API (taking two arguments, the channel to truncate and the
length (as a wide integer to facilitate use with large files) to
truncate it to in bytes).  The channel API would be modified to add
the new functionality for standard disk file channels and to allow
extension authors to implement it for their custom channel types
through specifying in their ''Tcl_ChannelType'' structure a value for
the new field ''truncateProc'' (of type pointer to
''Tcl_DriverTruncateProc'', which will be a function with the obvious
type signature).  Finally, the maximum TCL_CHANNEL_VERSION would be
increased to TCL_CHANNEL_VERSION_4 to accommodate this new field.

~ Reference Implementation

A reference implementation does ''not'' yet exist.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|

|




|
|


|

|

|
|

|

|

|
|
|
|
|
|
|
|
|
|
|
|

|

|
|
|
|


|
|
|
|
|

|

|

|


>

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

# TIP 206: Add an [ftruncate] Command

	Author:         Joe Mistachkin <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        25-Jun-2004
	Post-History:   
	Tcl-Version:    8.5
	Obsoleted-By:	208
-----

# Abstract

This TIP proposes a new command **ftruncate** for truncating open
files.

# Note

This TIP has been effectively rolled into [[208]](208.md).

# Rationale

In Tcl, there is currently no way to truncate a file while it is open
even though all modern operating systems support such an operation.
The current workaround is to close the file and reopen it.  However,
in cases where the file must be held open \(e.g. on Unix where the file
has already been deleted and is just being used as scratch space\) this
workaround cannot be used.

# Specification

 > **ftruncate** _channelId_ ?_length_?

The channel specified by _channelId_ must refer to a file that was
opened for writing.  The _length_ argument must be greater than or
equal to zero and can be bigger than the current size of the file.  If
the _length_ argument is omitted, the file will be truncated at the current access position.  This command will return any errors received from the operating system.

## Example Usage

	# Open the file for reading and writing...
	set file [open "test.txt" {RDWR}]
	# Write some data to the file...
	puts $file "test data"
	
	# Some time later...
	# ... ... ...
	ftruncate $file
	# ... ... ...
	
	# We are done, close the file...
	close $file

# Proposed C API Changes

A new function named **Tcl\_TruncateChannel** would be added to the
Tcl C API \(taking two arguments, the channel to truncate and the
length \(as a wide integer to facilitate use with large files\) to
truncate it to in bytes\).  The channel API would be modified to add
the new functionality for standard disk file channels and to allow
extension authors to implement it for their custom channel types
through specifying in their _Tcl\_ChannelType_ structure a value for
the new field _truncateProc_ \(of type pointer to
_Tcl\_DriverTruncateProc_, which will be a function with the obvious
type signature\).  Finally, the maximum TCL\_CHANNEL\_VERSION would be
increased to TCL\_CHANNEL\_VERSION\_4 to accommodate this new field.

# Reference Implementation

A reference implementation does _not_ yet exist.

# Copyright

This document has been placed in the public domain.

Name change from tip/207.tip to tip/207.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

TIP:            207
Title:          Add a -namespace Option to [interp invokehidden]
Version:        $Revision: 1.8 $
Author:         Joe Mistachkin <[email protected]>
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        29-Jun-2004
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes a ''-namespace'' option for the '''interp
invokehidden''' subcommand to allow hidden commands to be invoked in
the specified namespace context in the slave interpreter.

~ Rationale

Safe interpreters and namespaces have been useful and important
features of Tcl since version 8.0.  However, it can sometimes be
difficult to use them together effectively.  For example, while you
can invoke a hidden command in a safe interpreter with '''interp
invokehidden''', such as '''source''', you cannot specify the target
namespace context where the command should be invoked.  Using the
'''interp eval''' subcommand is not an option because that, by design,
does not allow hidden commands to be invoked.  In addition, since the
'''interp invokehidden''' subcommand expects a command name,
'''namespace eval''' and similar constructs that would typically be
used to change the target namespace context cannot be used.

~ Specification

 > '''interp invokehidden''' ''path''
   ?'''-namespace''' ''namespace''? ?'''-global'''?
   ?'''--'''? ''hiddenCmdName'' ?''arg ...''?

The '''interp invokehidden''' subcommand would continue to function as
the current documentation dictates with the following notable
exceptions:

   * The '''-namespace''' specifies the target namespace context in
     the slave interpreter where the command should be invoked starting
     from the global namespace in the slave interpreter.

   * The target namespace context specified by the '''-namespace'''
     option is created in the slave interpreter if it does not already
     exist.

   * If both the '''-global''' and '''-namespace''' options are
     present, the '''-namespace''' option is ignored.

A '''--''' option (with the standard meaning) will be added as well.

The slave-interpreter command version of '''invokehidden''' will be
updated in an equivalent way.

~~Example Usage

The following example scripts illustrates how this feature might be used.

|################################################
|# file inside.tcl
|################################################
|
|set x "this is a test from inside [namespace current]."
|
|################################################
|# file invoke.tcl
|################################################
|
|set i [interp create -safe]
|set file [file join [file dirname [info script]] inside.tcl]
|
|interp invokehidden $i -namespace ::test::foo::bar source $file
|
|set result [interp eval $i [list set ::test::foo::bar::x]]
|
|# should be: "this is a test from inside ::test::foo::bar."
|puts stdout $result

~ Proposed Internal C API Changes

To be determined.

~ Reference Implementation

A reference implementation of this TIP is availble
[http://sf.net/tracker/?func=detail&aid=981841&group_id=10894&atid=310894].

~ Comments

''DGP'': Note that the '''interp''' command (including the
'''interp invokehidden''' subcommand) was added for
Tcl 7.5.  The '''namespace''' command arrived later
in Tcl 8.0.  This proposal observes and proposes to
correct that the '''interp invokehidden''' command
was not updated to account for the arrival of 
namespaces.  Clearly the ''-global'' option indicates
that control over evaluation context is something
the caller needs.  This command simply failed to
evolve in a timely manner.  This proposal is an
overdue correction.

Looking ahead, I'd be happy if the ''-global'' option
was dropped from the documentation, so that only the
new ''-namespace'' option is favored, and so that the
recommended way one
forces evaluation in the global namespace is with
''-namespace ::''.  The ''-global'' option would still
work through the remaining Tcl 8 releases, but no
longer be recommended for new code.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|


|




|
|

|

|
|


|

|
|
|

|



|



|



|
|

|

|


|



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|



|


|

|

|
|
|

|

|





|

|


|



|


>

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

# TIP 207: Add a -namespace Option to [interp invokehidden]

	Author:         Joe Mistachkin <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        29-Jun-2004
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes a _-namespace_ option for the **interp
invokehidden** subcommand to allow hidden commands to be invoked in
the specified namespace context in the slave interpreter.

# Rationale

Safe interpreters and namespaces have been useful and important
features of Tcl since version 8.0.  However, it can sometimes be
difficult to use them together effectively.  For example, while you
can invoke a hidden command in a safe interpreter with **interp
invokehidden**, such as **source**, you cannot specify the target
namespace context where the command should be invoked.  Using the
**interp eval** subcommand is not an option because that, by design,
does not allow hidden commands to be invoked.  In addition, since the
**interp invokehidden** subcommand expects a command name,
**namespace eval** and similar constructs that would typically be
used to change the target namespace context cannot be used.

# Specification

 > **interp invokehidden** _path_
   ?**-namespace** _namespace_? ?**-global**?
   ?**--**? _hiddenCmdName_ ?_arg ..._?

The **interp invokehidden** subcommand would continue to function as
the current documentation dictates with the following notable
exceptions:

   * The **-namespace** specifies the target namespace context in
     the slave interpreter where the command should be invoked starting
     from the global namespace in the slave interpreter.

   * The target namespace context specified by the **-namespace**
     option is created in the slave interpreter if it does not already
     exist.

   * If both the **-global** and **-namespace** options are
     present, the **-namespace** option is ignored.

A **--** option \(with the standard meaning\) will be added as well.

The slave-interpreter command version of **invokehidden** will be
updated in an equivalent way.

## Example Usage

The following example scripts illustrates how this feature might be used.

	################################################
	# file inside.tcl
	################################################
	
	set x "this is a test from inside [namespace current]."
	
	################################################
	# file invoke.tcl
	################################################
	
	set i [interp create -safe]
	set file [file join [file dirname [info script]] inside.tcl]
	
	interp invokehidden $i -namespace ::test::foo::bar source $file
	
	set result [interp eval $i [list set ::test::foo::bar::x]]
	
	# should be: "this is a test from inside ::test::foo::bar."
	puts stdout $result

# Proposed Internal C API Changes

To be determined.

# Reference Implementation

A reference implementation of this TIP is availble
<http://sf.net/tracker/?func=detail&aid=981841&group_id=10894&atid=310894> .

# Comments

_DGP_: Note that the **interp** command \(including the
**interp invokehidden** subcommand\) was added for
Tcl 7.5.  The **namespace** command arrived later
in Tcl 8.0.  This proposal observes and proposes to
correct that the **interp invokehidden** command
was not updated to account for the arrival of 
namespaces.  Clearly the _-global_ option indicates
that control over evaluation context is something
the caller needs.  This command simply failed to
evolve in a timely manner.  This proposal is an
overdue correction.

Looking ahead, I'd be happy if the _-global_ option
was dropped from the documentation, so that only the
new _-namespace_ option is favored, and so that the
recommended way one
forces evaluation in the global namespace is with
_-namespace ::_.  The _-global_ option would still
work through the remaining Tcl 8 releases, but no
longer be recommended for new code.

# Copyright

This document has been placed in the public domain.

Name change from tip/208.tip to tip/208.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

TIP:            208
Title:          Add a 'chan' Command
Version:        $Revision: 1.8 $
Author:         Jeff Hobbs <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        02-Jul-2004
Post-History:   
Keywords:       Tcl
Tcl-Version:    8.5
Obsoletes:	206


~ Abstract

This TIP proposes adding a '''chan''' command that would serve as a
top-level command container for all the related channel commands that
have proliferated over time, as well as future new channel-based
commands.

~ Rationale

Tcl's channel system has evolved over time from a thin layer on top of
the OS into a very complex, multi-platform system.  There are numerous
top-level commands for channels already, with more being proposed for
Tcl 8.5.  This command would centralize them, making it easier for new
users to see all the related channel commands, much as '''string''' or
'''file''' operate today.

The name '''chan''' was chosen over "channel" because it is a
clearly recognizable abbreviation, much like '''eval''' vs. "evaluate"
and '''interp''' vs "interpreter".

~ Specification

A new command '''chan''' will be added with the following syntax:

|      chan blocked    ; # fblocked
|      chan close      ; # close
|      chan configure  ; # fconfigure
|      chan copy       ; # fcopy
|      chan eof        ; # eof
|      chan event      ; # fileevent
|      chan flush      ; # flush
|      chan gets       ; # gets
|      chan names      ; # file channels
|      chan puts       ; # puts
|      chan read       ; # read
|      chan seek       ; # seek
|      chan tell       ; # tell
|      chan truncate   ; # ftruncate (if TIP#206 had been accepted)

Each represents the existing command that is commented.  The arguments
to each would remain what the current command takes.

Note that '''open''' is not included above, as it is a channel
creation function, just like '''socket'''.

~~ Specification of the 'truncate' Subcommand

[[See [206] for Rationale]]

 > '''chan truncate''' ''channelId'' ?''length''?

The channel specified by ''channelId'' must refer to a file that was
opened for writing.  The ''length'' argument must be greater than or
equal to zero and can be bigger than the current size of the file.  If
the ''length'' argument is omitted, the file will be truncated at the
current access position.  The result of this command will normally be
the empty string; any errors from the filesystem when truncating will
generate error results in the normal fashion.

~~ Deprecation of Existing Commands

In addition, I would recommend only the following commands be marked
deprecated so as to help systematize their names better:

|      fblocked
|      fconfigure
|      fcopy
|      fileevent
|      file channels

~ Related C API Changes

A new function named '''Tcl_TruncateChannel''' would be added to the
Tcl C API (taking two arguments, the channel to truncate and the
length (as a wide integer to facilitate use with large files) to
truncate it to in bytes).

 > int '''Tcl_TruncateChannel'''(Tcl_Channel ''chan'', Tcl_WideInt ''length'')

The channel API would be modified to add the new functionality for
standard disk file channels and to allow extension authors to
implement it for their custom channel types through specifying in
their ''Tcl_ChannelType'' structure a value for the new field
''truncateProc'' (of type pointer to ''Tcl_DriverTruncateProc'', which
will be a function with the obvious type signature).  Finally, the
maximum TCL_CHANNEL_VERSION would be increased to
TCL_CHANNEL_VERSION_4 to accommodate this new field.

~ Reference Implementation

The implementation of the Tcl-level TIP is really a simple command
that makes use of the existing command implementations.  It could be a
namespace ensemble or a C-based command. The '''chan truncate''' part
will require C code.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|




|





|
|

|
|
|

|

|

|
|
|
|
|
|
|
|
|
|
|
|
|
|




|
|

|

|

|

|
|

|




|




|
|
|
|
|

|

|
|
|
|

|




|
|
|
|
|

|



|


|


>

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

# TIP 208: Add a 'chan' Command

	Author:         Jeff Hobbs <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        02-Jul-2004
	Post-History:   
	Keywords:       Tcl
	Tcl-Version:    8.5
	Obsoletes:	206
-----

# Abstract

This TIP proposes adding a **chan** command that would serve as a
top-level command container for all the related channel commands that
have proliferated over time, as well as future new channel-based
commands.

# Rationale

Tcl's channel system has evolved over time from a thin layer on top of
the OS into a very complex, multi-platform system.  There are numerous
top-level commands for channels already, with more being proposed for
Tcl 8.5.  This command would centralize them, making it easier for new
users to see all the related channel commands, much as **string** or
**file** operate today.

The name **chan** was chosen over "channel" because it is a
clearly recognizable abbreviation, much like **eval** vs. "evaluate"
and **interp** vs "interpreter".

# Specification

A new command **chan** will be added with the following syntax:

	      chan blocked    ; # fblocked
	      chan close      ; # close
	      chan configure  ; # fconfigure
	      chan copy       ; # fcopy
	      chan eof        ; # eof
	      chan event      ; # fileevent
	      chan flush      ; # flush
	      chan gets       ; # gets
	      chan names      ; # file channels
	      chan puts       ; # puts
	      chan read       ; # read
	      chan seek       ; # seek
	      chan tell       ; # tell
	      chan truncate   ; # ftruncate (if TIP#206 had been accepted)

Each represents the existing command that is commented.  The arguments
to each would remain what the current command takes.

Note that **open** is not included above, as it is a channel
creation function, just like **socket**.

## Specification of the 'truncate' Subcommand

[See [[206]](206.md) for Rationale]

 > **chan truncate** _channelId_ ?_length_?

The channel specified by _channelId_ must refer to a file that was
opened for writing.  The _length_ argument must be greater than or
equal to zero and can be bigger than the current size of the file.  If
the _length_ argument is omitted, the file will be truncated at the
current access position.  The result of this command will normally be
the empty string; any errors from the filesystem when truncating will
generate error results in the normal fashion.

## Deprecation of Existing Commands

In addition, I would recommend only the following commands be marked
deprecated so as to help systematize their names better:

	      fblocked
	      fconfigure
	      fcopy
	      fileevent
	      file channels

# Related C API Changes

A new function named **Tcl\_TruncateChannel** would be added to the
Tcl C API \(taking two arguments, the channel to truncate and the
length \(as a wide integer to facilitate use with large files\) to
truncate it to in bytes\).

 > int **Tcl\_TruncateChannel**\(Tcl\_Channel _chan_, Tcl\_WideInt _length_\)

The channel API would be modified to add the new functionality for
standard disk file channels and to allow extension authors to
implement it for their custom channel types through specifying in
their _Tcl\_ChannelType_ structure a value for the new field
_truncateProc_ \(of type pointer to _Tcl\_DriverTruncateProc_, which
will be a function with the obvious type signature\).  Finally, the
maximum TCL\_CHANNEL\_VERSION would be increased to
TCL\_CHANNEL\_VERSION\_4 to accommodate this new field.

# Reference Implementation

The implementation of the Tcl-level TIP is really a simple command
that makes use of the existing command implementations.  It could be a
namespace ensemble or a C-based command. The **chan truncate** part
will require C code.

# Copyright

This document has been placed in the public domain.

Name change from tip/209.tip to tip/209.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

TIP:            209
Title:          Add [clock milliseconds], and [clock microseconds]
Version:        $Revision: 1.5 $
Author:         Reinhard Max <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        12-Jul-2004
Post-History:   
Keywords:       clock, milliseconds, microseconds
Tcl-Version:    8.5


~ Abstract

This TIP proposes to replace '''clock clicks -milliseconds''' by
'''clock milliseconds''' and '''clock clicks -microseconds''' by
'''clock microseconds'''.

~ Proposed change

 1. Rename the '''clock clicks -microseconds''' command as defined by [124] to
    '''clock microseconds'''.

 2. Deprecate '''clock clicks -milliseconds''', and make it's functionality as
    defined by [124] available as '''clock milliseconds'''.

~ Rationale

In the author's understanding, the whole purpose of the '''clock clicks''' name
was to indicate that the returned value is neither absolute nor guaranteed
to have the same unit on different platforms. With the changes of [124] in
place both cases are not true anymore. Therefore the commands to return
absolute timestamps with millisecond and microsecond resolution should be on
the same level as '''clock seconds''' rather than being switches to '''clock
clicks'''.

The '''-microseconds''' option can be removed from '''clock clicks''' immediately,
because it never has been part of an official Tcl release while
'''-milliseconds''' has to be kept at least until the next major release for
backwards compatibility.

~ Reference Implementation

A reference implementation has been added to the Tcl patch tracker
at SourceForge, item #991742 .

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|
|

|

|
|

|
|

|

|

|


|
|

|

|


|


|

|


>

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

# TIP 209: Add [clock milliseconds], and [clock microseconds]

	Author:         Reinhard Max <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        12-Jul-2004
	Post-History:   
	Keywords:       clock, milliseconds, microseconds
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to replace **clock clicks -milliseconds** by
**clock milliseconds** and **clock clicks -microseconds** by
**clock microseconds**.

# Proposed change

 1. Rename the **clock clicks -microseconds** command as defined by [[124]](124.md) to
    **clock microseconds**.

 2. Deprecate **clock clicks -milliseconds**, and make it's functionality as
    defined by [[124]](124.md) available as **clock milliseconds**.

# Rationale

In the author's understanding, the whole purpose of the **clock clicks** name
was to indicate that the returned value is neither absolute nor guaranteed
to have the same unit on different platforms. With the changes of [[124]](124.md) in
place both cases are not true anymore. Therefore the commands to return
absolute timestamps with millisecond and microsecond resolution should be on
the same level as **clock seconds** rather than being switches to **clock
clicks**.

The **-microseconds** option can be removed from **clock clicks** immediately,
because it never has been part of an official Tcl release while
**-milliseconds** has to be kept at least until the next major release for
backwards compatibility.

# Reference Implementation

A reference implementation has been added to the Tcl patch tracker
at SourceForge, item \#991742 .

# Copyright

This document has been placed in the public domain.

Name change from tip/21.tip to tip/21.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

TIP:            21
Title:          Asymmetric Padding in the Pack and Grid Geometry Managers
Version:        $Revision: 1.6 $
Author:         D. Richard Hipp <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        14-Jan-2001
Post-History:   
Tcl-Version:    8.4


~ Abstract

Proposes modifying the ''pack'' and ''grid'' geometry 
managers to support asymmetric padding.

~ Rationale

The ''pack'' and ''grid'' geometry managers allow for 
adding extra space to the
left and right of a widget using the -padx option, and above and below
the widget using -pady.  But there is currently no way to add
different amounts of space on opposite sides of the widget.  When a
layout requires differing amounts of space on opposite sides of the
same widget, the usual solution is to introduce extra ''frame''
widgets to act as spacers.  But that both complicates the code
unnecessarily and obscures the intent of the programmer.

~ Proposed Enhancement

This TIP proposes to modify the -padx and -pady of both
the ''pack'' and ''grid'' geometry
managers as follows: If the argument to -padx or -pady is a screen
distance, that distance is added to both sides of the widget.  (This
is the current behavior.)  If the argument is a list of two screen
distances, then the first screen distance is the extra space to add to
the left or top and the second screen distance is the extra space to
add to the right or bottom.

The changes to -padx and -pady occur in ''pack'' 
only if the pack geometry manager
is used according to the new syntax.  The older deprecated syntax
(that dates from Tk3.3) will not support asymmetric padding.

~ Copyright

This document has been placed in the public domain.

~ Patch

Patches to implement asymmetric padding in the 
pack and grid geometry managers,
as described above, are available at
http://www.hwaci.com/sw/asym_pad_patch_2.txt

<
|
<
|
|
|
|
|
|
|
>

|

|


|

|





|



|


|

|
|




|


|

|



|




|
>

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

# TIP 21: Asymmetric Padding in the Pack and Grid Geometry Managers

	Author:         D. Richard Hipp <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        14-Jan-2001
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

Proposes modifying the _pack_ and _grid_ geometry 
managers to support asymmetric padding.

# Rationale

The _pack_ and _grid_ geometry managers allow for 
adding extra space to the
left and right of a widget using the -padx option, and above and below
the widget using -pady.  But there is currently no way to add
different amounts of space on opposite sides of the widget.  When a
layout requires differing amounts of space on opposite sides of the
same widget, the usual solution is to introduce extra _frame_
widgets to act as spacers.  But that both complicates the code
unnecessarily and obscures the intent of the programmer.

# Proposed Enhancement

This TIP proposes to modify the -padx and -pady of both
the _pack_ and _grid_ geometry
managers as follows: If the argument to -padx or -pady is a screen
distance, that distance is added to both sides of the widget.  \(This
is the current behavior.\)  If the argument is a list of two screen
distances, then the first screen distance is the extra space to add to
the left or top and the second screen distance is the extra space to
add to the right or bottom.

The changes to -padx and -pady occur in _pack_ 
only if the pack geometry manager
is used according to the new syntax.  The older deprecated syntax
\(that dates from Tk3.3\) will not support asymmetric padding.

# Copyright

This document has been placed in the public domain.

# Patch

Patches to implement asymmetric padding in the 
pack and grid geometry managers,
as described above, are available at
<http://www.hwaci.com/sw/asym\_pad\_patch\_2.txt>

Name change from tip/210.tip to tip/210.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

TIP:            210
Title:          Add 'tempfile' Subcommand to 'file'
Version:        $Revision: 1.11 $
Author:         Bob Techentin <[email protected]>
Author:		Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        19-Jul-2004
Post-History:   
Keywords:       Tcl,filename
Tcl-Version:    8.6


~ Abstract

Programmers often need to create temporary files. This TIP proposes adding the
new subcommand '''tempfile''' to the '''file''' command, simplifying
programmer effort in creating a unique temporary file name.

~ Rationale

Creating temporary files is a primitive and common enough operation that the
ANSI C standard defines several subroutines to assist programmers. The
''tmpnam()'' function generates a string that is a valid file name that is not
the name of an existing file. The ''tmpfile()'' function returns a valid file
pointer to a temporary file that is removed automatically when it is closed or
at program termination. Both functions are commonly used by programmers,
without worrying about the optimal location for temporary files or schemes
required to create unique file names.

Tcl has not supported temporary files, so programmers have had to write code
to generate unique file names and choose locations like ''/tmp'' or
''C:\temp''. The ''fileutil'' module of tcllib provides a relatively
sophisticated implementation of ''tempfile'', but extension writers have not
been able to rely on this code. Modules in Iwidgets, the Tcl plugin, tcllib,
and TclX all appear to have this sort of code, and not all are correct.

This TIP proposes to extend the '''file''' command with one subcommand to
generate temporary files and file names. By extending the core command,
application programmers and extension writers will be able to depend on this
functionality for their code, without resorting to copying or depending on
tcllib.

~ Specification

This TIP proposes an extension to the '''file''' command, implementing the
functionality of the POSIX standard mkstemp() function. The new subcommand
will be called '''tempfile'''. It will return an open file channel, and
(optionally) the name of the temporary file.

~ Synopsis

 > '''file tempfile''' ?''namevar''? ?''template''?

Opens a unique temporary file and returns an open file channel. If ''namevar''
is specified, then the command will set the variable to the name of the
temporary file. If the ''template'' string is specified, it will be decomposed
into (up to) three parts: the path, the root, and the extension. Any part may
be absent. If the path or root are absent, system-dependent defaults will be
used. If the extension is absent, no extension will be used. The temporary
name will then be formed from the path, the root, some unique string, and the
extension (if defined).

The returned channel will have been opened in read-write mode (but not append
mode) using the defaults for EOL translation, encoding, etc.

~ Reference Implementation

Available as Tcl Patch #999162 on SourceForge
[https://sourceforge.net/support/tracker.php?aid=999162]. ''(That
patch is for an old version of the TIP.)''

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|


|


|



|
|






|
|
|



|





|

|
|
|
|

|

|

|

|
|



|

|
|

|

|
|
|

|


>

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

# TIP 210: Add 'tempfile' Subcommand to 'file'

	Author:         Bob Techentin <[email protected]>
	Author:		Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        19-Jul-2004
	Post-History:   
	Keywords:       Tcl,filename
	Tcl-Version:    8.6
-----

# Abstract

Programmers often need to create temporary files. This TIP proposes adding the
new subcommand **tempfile** to the **file** command, simplifying
programmer effort in creating a unique temporary file name.

# Rationale

Creating temporary files is a primitive and common enough operation that the
ANSI C standard defines several subroutines to assist programmers. The
_tmpnam\(\)_ function generates a string that is a valid file name that is not
the name of an existing file. The _tmpfile\(\)_ function returns a valid file
pointer to a temporary file that is removed automatically when it is closed or
at program termination. Both functions are commonly used by programmers,
without worrying about the optimal location for temporary files or schemes
required to create unique file names.

Tcl has not supported temporary files, so programmers have had to write code
to generate unique file names and choose locations like _/tmp_ or
_C:\\temp_. The _fileutil_ module of tcllib provides a relatively
sophisticated implementation of _tempfile_, but extension writers have not
been able to rely on this code. Modules in Iwidgets, the Tcl plugin, tcllib,
and TclX all appear to have this sort of code, and not all are correct.

This TIP proposes to extend the **file** command with one subcommand to
generate temporary files and file names. By extending the core command,
application programmers and extension writers will be able to depend on this
functionality for their code, without resorting to copying or depending on
tcllib.

# Specification

This TIP proposes an extension to the **file** command, implementing the
functionality of the POSIX standard mkstemp\(\) function. The new subcommand
will be called **tempfile**. It will return an open file channel, and
\(optionally\) the name of the temporary file.

# Synopsis

 > **file tempfile** ?_namevar_? ?_template_?

Opens a unique temporary file and returns an open file channel. If _namevar_
is specified, then the command will set the variable to the name of the
temporary file. If the _template_ string is specified, it will be decomposed
into \(up to\) three parts: the path, the root, and the extension. Any part may
be absent. If the path or root are absent, system-dependent defaults will be
used. If the extension is absent, no extension will be used. The temporary
name will then be formed from the path, the root, some unique string, and the
extension \(if defined\).

The returned channel will have been opened in read-write mode \(but not append
mode\) using the defaults for EOL translation, encoding, etc.

# Reference Implementation

Available as Tcl Patch \#999162 on SourceForge
<https://sourceforge.net/support/tracker.php?aid=999162> . _\(That
patch is for an old version of the TIP.\)_

# Copyright

This document has been placed in the public domain.

Name change from tip/211.tip to tip/211.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149

TIP:            211
Title:          Add Full Stack Trace Capability
Version:        $Revision: 1.6 $
Author:         Robert Seeger <[email protected]>
Author:         Robert Seeger <[email protected]>
Author:         Don Porter <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        10-Aug-2004
Post-History:   
Keywords:       Tcl
Tcl-Version:    8.5
Obsoleted-By:	280


~ Abstract

This TIP proposes adding a new subcommand to the '''info''' command
to get a list of all the frames on the current
stack, rather than the limited list returned
by '''info level'''.

~ Rationale

Currently, there is no way to get a list of all the frames in
the current stack managed by '''Tcl_PushCallFrame()''' and
'''Tcl_PopCallFrame()'''. The '''info level''' command does not
contain frames that are callers of  '''uplevel''', reporting only the
frames that are accessible via another '''uplevel'''
command. There are times when the lack of information can have a
negative impact on code design. The difference in information can be
seen with the following code snippets:

|% proc bob {args} { 
|    joe {expand}$args
|  }

|% proc joe {args} {
|    uplevel 1 dave {expand}$args
|  }

|% proc dave {args} {
|    puts "Level: [info level]"
|    for {set i [info level]} { $i > 0 } {incr i -1 } {
|      puts "${i}: [info level $i]"
|    }
|  }


|% bob x y z
|Level: 2
|2: dave x y z
|1: bob x y z
|% proc dave {args} {
|    puts "Level: [info frame]" 
|    for {set i [info frame]} { $i > 0 } {incr i -1 } {
|      puts "${i}: [info frame $i]"
|    }
|  }


|% bob
|Level: 3
|3: dave x y z
|2: joe x y z
|1: bob x y z

There are 3 reasons I see for bringing forth this TIP: 

   1. It's an introspection ability that is currently lacking, with no
      good reason for that lack.

   2. The more information that is available to the programmer, the
      easier it is to accomplish a goal in a straightforward, easily
      maintainable way.

   3. I have code in which the impact of not having this information
      available is visible.

~~Use Cases

There are two cases I have run into where the ability to query all
frames on the stack would have been particularly useful.

 1. '''TclTest'''

  > The first case is with Tcltest, where the complete lack of ability
    to gain access to that information means it is impossible to gain
    information about a test without modifying the Tcltest code
    itself. Being able to find out the name of the current test would
    be very handy, especially in naming test procs and logging
    information. Currently, there is no way to find out the name of
    the currently executing test, due to the fact that the code for
    the test is '''uplevel'''ed and, hence, not visible via '''info
    level'''.

 2. '''TestStubs Package'''

  > The TestStubs package provides the ability to temporarily redefine
    commands, in particular for stubbing out or replacing
    functionality in a test case. There is a command in the package
    called '''chain''', which is used within the code replacing a
    command (or part of a command) to call the original definition of
    the command. For example, one could do:

|stubs::stub ensemble array names {
|    return [lsort [uplevel 1 chain names $args]]
|}

  > However, since the '''chain''' command is (and should be) limited

    to only running from within a stub definition, it needs to call
    '''info level''' to find out if its caller is one of the stubbed
    commands, and what the name of that command is. With '''info
    level''', it would not have access to the level that is running
    inside the stubbed procedure. Hence, either it cannot check this
    constraint, or stubs cannot be allowed to use '''uplevel''' when
    calling it (which means things like the above either cannot work,
    or need to be rewritten in a considerably less clear manner).

~ Proposed Change

I propose to add a new subcommand to the info command with the
following syntax:

 > '''info frame''' ?''level''?

The new functionality will provide access to all frames on the stack
rather than the current limited subset. The information to do so already
exists within the Interp object that all commands are passed, and the
code needed to expose it differs in only a few aspects from that of
'''info level'''.

This TIP does ''not'' propose to alter '''uplevel''' or '''upvar''' so
that they can see these hidden levels.

~~ Child Interps

The current implementation of ''info level'' only returns levels up to the top of the stack for the current interpreter. Such an approach puts limitations on what information can be retrieved, but allows for a certain level of ''"security"'' when running code in child interps, especially safe interps.

Given the security considerations of safe interps, and consistancy with regards to what information is returned across multiple circumstances, the stack trace returned will only return information up to the top level of the current interp, the same limit ''info level'' is bound by. 

~ Implementation

An implementation patch is available on SourceForge
[http://sourceforge.net/tracker/?func=detail&aid=1503647&group_id=10894&atid=310894].

~ Copyright

This document has been placed in the public domain.

Please note that any correspondence to the author concerning this TIP
is considered in the public domain unless otherwise specifically
requested by the individual(s) authoring said correspondence. This is
to allow information about the TIP to be placed in a public forum for
discussion.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
>

|

|


|

|


|
|
|
|




|
|
<
>
|
|
<
>
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|













|




|

|






|
|

|

|


|
|


|
|
<
|
|
>

|
|
|

|
|
|

|




|





|

|


|

|

|

|


|

|





|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149

# TIP 211: Add Full Stack Trace Capability

	Author:         Robert Seeger <[email protected]>
	Author:         Robert Seeger <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        10-Aug-2004
	Post-History:   
	Keywords:       Tcl
	Tcl-Version:    8.5
	Obsoleted-By:	280
-----

# Abstract

This TIP proposes adding a new subcommand to the **info** command
to get a list of all the frames on the current
stack, rather than the limited list returned
by **info level**.

# Rationale

Currently, there is no way to get a list of all the frames in
the current stack managed by **Tcl\_PushCallFrame\(\)** and
**Tcl\_PopCallFrame\(\)**. The **info level** command does not
contain frames that are callers of  **uplevel**, reporting only the
frames that are accessible via another **uplevel**
command. There are times when the lack of information can have a
negative impact on code design. The difference in information can be
seen with the following code snippets:

	% proc bob {args} { 
	    joe {expand}$args

	  }
	% proc joe {args} {
	    uplevel 1 dave {expand}$args

	  }
	% proc dave {args} {
	    puts "Level: [info level]"
	    for {set i [info level]} { $i > 0 } {incr i -1 } {
	      puts "${i}: [info level $i]"


	    }
	  }
	% bob x y z
	Level: 2
	2: dave x y z
	1: bob x y z
	% proc dave {args} {
	    puts "Level: [info frame]" 
	    for {set i [info frame]} { $i > 0 } {incr i -1 } {
	      puts "${i}: [info frame $i]"


	    }
	  }
	% bob
	Level: 3
	3: dave x y z
	2: joe x y z
	1: bob x y z

There are 3 reasons I see for bringing forth this TIP: 

   1. It's an introspection ability that is currently lacking, with no
      good reason for that lack.

   2. The more information that is available to the programmer, the
      easier it is to accomplish a goal in a straightforward, easily
      maintainable way.

   3. I have code in which the impact of not having this information
      available is visible.

## Use Cases

There are two cases I have run into where the ability to query all
frames on the stack would have been particularly useful.

 1. **TclTest**

	  > The first case is with Tcltest, where the complete lack of ability
    to gain access to that information means it is impossible to gain
    information about a test without modifying the Tcltest code
    itself. Being able to find out the name of the current test would
    be very handy, especially in naming test procs and logging
    information. Currently, there is no way to find out the name of
    the currently executing test, due to the fact that the code for
    the test is **uplevel**ed and, hence, not visible via **info
    level**.

 2. **TestStubs Package**

	  > The TestStubs package provides the ability to temporarily redefine
    commands, in particular for stubbing out or replacing
    functionality in a test case. There is a command in the package
    called **chain**, which is used within the code replacing a
    command \(or part of a command\) to call the original definition of
    the command. For example, one could do:

		stubs::stub ensemble array names {
		    return [lsort [uplevel 1 chain names $args]]

		}

	  > However, since the **chain** command is \(and should be\) limited
    to only running from within a stub definition, it needs to call
    **info level** to find out if its caller is one of the stubbed
    commands, and what the name of that command is. With **info
    level**, it would not have access to the level that is running
    inside the stubbed procedure. Hence, either it cannot check this
    constraint, or stubs cannot be allowed to use **uplevel** when
    calling it \(which means things like the above either cannot work,
    or need to be rewritten in a considerably less clear manner\).

# Proposed Change

I propose to add a new subcommand to the info command with the
following syntax:

 > **info frame** ?_level_?

The new functionality will provide access to all frames on the stack
rather than the current limited subset. The information to do so already
exists within the Interp object that all commands are passed, and the
code needed to expose it differs in only a few aspects from that of
**info level**.

This TIP does _not_ propose to alter **uplevel** or **upvar** so
that they can see these hidden levels.

## Child Interps

The current implementation of _info level_ only returns levels up to the top of the stack for the current interpreter. Such an approach puts limitations on what information can be retrieved, but allows for a certain level of _"security"_ when running code in child interps, especially safe interps.

Given the security considerations of safe interps, and consistancy with regards to what information is returned across multiple circumstances, the stack trace returned will only return information up to the top level of the current interp, the same limit _info level_ is bound by. 

# Implementation

An implementation patch is available on SourceForge
<http://sourceforge.net/tracker/?func=detail&aid=1503647&group_id=10894&atid=310894> .

# Copyright

This document has been placed in the public domain.

Please note that any correspondence to the author concerning this TIP
is considered in the public domain unless otherwise specifically
requested by the individual\(s\) authoring said correspondence. This is
to allow information about the TIP to be placed in a public forum for
discussion.

Name change from tip/212.tip to tip/212.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
136
137

138
139
140
141
142
143
144


145
146
147
148
149

150
151
152
153
154
155
156

TIP:		212
Title:		Temporarily Opening out a Dictionary
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Post-History:	
Version:	$Revision: 1.9 $
Author:		Donal K. Fellows <[email protected]>
Created:	11-Aug-2004
Keywords:	tcl, dict, update, script


~ Abstract

This TIP proposes a new subcommand of '''dict''' that associates
variables with dictionary entries while a Tcl script (the "body" of
the command) runs.

~ Rationale

The standard set of operations provided by the '''dict''' command (see
[111] and [163]) give a fairly rich set of operations, but there are
always further things that script authors want to do.  Instead of
ever-expanding numbers of subcommands offering tiny variants on
existing operations, this TIP provides a generalized mechanism for
associating variables and dictionary entries for the duration of a
script.  This makes writing arbitrary complex manipulations of
dictionaries much simpler.

~ Proposed Change

This TIP proposes two new subcommands to '''dict''', '''update''' and
'''with''', with the following syntaxes and semantics.

~~ The 'dict update' Subcommand

 > '''dict update''' ''dictVarName dictKey varName'' ?''dictKey
   varName'' ...? ''bodyScript''

In prose, the first argument is the name of a variable containing a
dictionary that will be updated, the last argument is a script to be
executed with the variables set up and whose effects are expected to
be to update the associated variables, and the other arguments between
those two (of which there must be an even number, with a minimum of
two) are a list of dictionary keys and the names of variables with
which to associate those keys.

The semantics of the command are this:

 1. For each dictionary key (''dictKey''), the value from the
    dictionary contained in the variable named by ''dictVarName''
    which that key maps to will be written to the variable associated
    with that key (''varName'').  If the key is not present in the
    dictionary, the variable will be unset.

 2. The script (''bodyScript'') is executed.

 3. The dictionary is read out of ''dictVarName'' again and, for each
    ''dictKey'', the ''varName'' variable is consulted and the
    contained value placed in the dictionary (if ''varName'' is unset,
    any existing mapping for ''dictKey'' will be removed.)  Finally,
    the resulting dictionary value is written back to ''dictVarName''.

 >  If the ''dictVarName'' variable was unset (without being set to a
    new value) or otherwise rendered unreadable during the execution
    of ''bodyScript'', the updating of the keys and writing back of
    the resulting dictionary to ''dictVarName'' is skipped. Note that
    it is only an unreadable ''dictVarName'' that is treated this way;
    it is an error for the variable to contain a value that is not a
    valid dictionary.

Note that ''dictVarName'' is read twice (each time, the value read
must be a valid dictionary or the variable must be unset, which is
interpreted as an empty dictionary) and (assuming the second read
succeeds and returns a valid dictionary value) written once, and that
''no'' traces are set up; ''dictVarName'' is completely independent of
the ''varName''s during the execution of ''bodyScript''.

Also note that step 3 is carried out even if ''bodyScript'' completes
with a result code other than TCL_OK, and that the result code of the
overall command will be
the result code of the script unless TCL_ERROR was the result of the
write-back stage, which might happen if the variable ''dictVarName''
is updated (during the execution of ''bodyScript'') to contain a
non-dictionary value, or if the variable ''dictVarName'' is either
unset or cannot be written to (which can happen if a write trace
throws an error); note that this mandates that any errors from the
''bodyScript'' are lost if the write-back phase also throws an error.
If the result code is TCL_OK, the result string/object will be
whatever the result string/object of ''bodyScript'' was.

~~ The 'dict with' Subcommand

 > '''dict with''' ''dictVarName'' ?''key ...''? ''bodyScript''

This is a shorthand version of '''dict update''' (named after the
Pascal ''with'' keyword) which maps ''all'' of the keys in the
dictionary in the variable ''dictVarName'' to variables during the
evaluation of ''bodyScript''. Note that it builds a list of all the
keys in the dictionary before ''bodyScript'' runs and only those
variables which are created are mapped back at the end; if extra keys
are defined in the dictionary in the variable during the execution of
''bodyScript'', they will be left alone when ''bodyScript'' finishes.

The variables will be written to and read from in the natural order of
the keys of the dictionary in the variable ''dictVarName'' when the
'''dict with''' command starts.

When a ''key'' (or several ''key''s) is provided, it describes a path
into a nested set of dictionaries (much like with '''dict set''')
where the selected leaf indicates a dictionary that is to be opened
out.  When writing back, non-existence of any key on the path is
treated the same as if ''dictVarName'' itself didn't exist.

~ Examples

A somewhat-less-efficient version of '''dict set''':

| dict update someVar $key local {
|     set local $value
| }


Sorting a list inside a nested dictionary:

| dict update someVar OuterKey temp {
|     dict update temp InnerKey temp2 {
|         set temp2 [lsort $temp2]
|     }
| }



"Renaming" a key:

| dict update someVar oldKey foo newKey bar {
|     set bar $foo
|     unset foo
| }


Opening out a nested dictionary:

| dict update someVar OuterKey temp {
|     dict with temp {
|         # Some script goes in here...
|     }
| }


| # Alternative version using a key with 'dict with'...
| dict with someVar OuterKey {
|     # Some script goes in here...  
| }


~ Reference Implementation

See SF patch 1008768[http://sf.net/tracker/?func=detail&aid=1008768&group_id=10894&atid=310894].

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|

|
|
|

|

|
|







|

|
|

|

|
|





|
|




|
|

|


|

|
|
|
|
|

|
|
|
|
|



|

|
|
|
|

|
|

|
|
|
|
|
|
|
|
|

|

|

|
|
|
|
|


|


|
|

|
|


|

|

|

|
|
<
|
>


|
|
|
<
<
>
>



|
|
|
<
|
>


|
|
|
<
<
>
>
|
|
|
<
|
>
|

|

|


>

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
136
137
138
139
140
141


142
143
144
145
146

147
148
149
150
151
152
153
154
155
156

# TIP 212: Temporarily Opening out a Dictionary
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	11-Aug-2004
	Keywords:	tcl, dict, update, script
-----

# Abstract

This TIP proposes a new subcommand of **dict** that associates
variables with dictionary entries while a Tcl script \(the "body" of
the command\) runs.

# Rationale

The standard set of operations provided by the **dict** command \(see
[[111]](111.md) and [[163]](163.md)\) give a fairly rich set of operations, but there are
always further things that script authors want to do.  Instead of
ever-expanding numbers of subcommands offering tiny variants on
existing operations, this TIP provides a generalized mechanism for
associating variables and dictionary entries for the duration of a
script.  This makes writing arbitrary complex manipulations of
dictionaries much simpler.

# Proposed Change

This TIP proposes two new subcommands to **dict**, **update** and
**with**, with the following syntaxes and semantics.

## The 'dict update' Subcommand

 > **dict update** _dictVarName dictKey varName_ ?_dictKey
   varName_ ...? _bodyScript_

In prose, the first argument is the name of a variable containing a
dictionary that will be updated, the last argument is a script to be
executed with the variables set up and whose effects are expected to
be to update the associated variables, and the other arguments between
those two \(of which there must be an even number, with a minimum of
two\) are a list of dictionary keys and the names of variables with
which to associate those keys.

The semantics of the command are this:

 1. For each dictionary key \(_dictKey_\), the value from the
    dictionary contained in the variable named by _dictVarName_
    which that key maps to will be written to the variable associated
    with that key \(_varName_\).  If the key is not present in the
    dictionary, the variable will be unset.

 2. The script \(_bodyScript_\) is executed.

 3. The dictionary is read out of _dictVarName_ again and, for each
    _dictKey_, the _varName_ variable is consulted and the
    contained value placed in the dictionary \(if _varName_ is unset,
    any existing mapping for _dictKey_ will be removed.\)  Finally,
    the resulting dictionary value is written back to _dictVarName_.

	 >  If the _dictVarName_ variable was unset \(without being set to a
    new value\) or otherwise rendered unreadable during the execution
    of _bodyScript_, the updating of the keys and writing back of
    the resulting dictionary to _dictVarName_ is skipped. Note that
    it is only an unreadable _dictVarName_ that is treated this way;
    it is an error for the variable to contain a value that is not a
    valid dictionary.

Note that _dictVarName_ is read twice \(each time, the value read
must be a valid dictionary or the variable must be unset, which is
interpreted as an empty dictionary\) and \(assuming the second read
succeeds and returns a valid dictionary value\) written once, and that
_no_ traces are set up; _dictVarName_ is completely independent of
the _varName_s during the execution of _bodyScript_.

Also note that step 3 is carried out even if _bodyScript_ completes
with a result code other than TCL\_OK, and that the result code of the
overall command will be
the result code of the script unless TCL\_ERROR was the result of the
write-back stage, which might happen if the variable _dictVarName_
is updated \(during the execution of _bodyScript_\) to contain a
non-dictionary value, or if the variable _dictVarName_ is either
unset or cannot be written to \(which can happen if a write trace
throws an error\); note that this mandates that any errors from the
_bodyScript_ are lost if the write-back phase also throws an error.
If the result code is TCL\_OK, the result string/object will be
whatever the result string/object of _bodyScript_ was.

## The 'dict with' Subcommand

 > **dict with** _dictVarName_ ?_key ..._? _bodyScript_

This is a shorthand version of **dict update** \(named after the
Pascal _with_ keyword\) which maps _all_ of the keys in the
dictionary in the variable _dictVarName_ to variables during the
evaluation of _bodyScript_. Note that it builds a list of all the
keys in the dictionary before _bodyScript_ runs and only those
variables which are created are mapped back at the end; if extra keys
are defined in the dictionary in the variable during the execution of
_bodyScript_, they will be left alone when _bodyScript_ finishes.

The variables will be written to and read from in the natural order of
the keys of the dictionary in the variable _dictVarName_ when the
**dict with** command starts.

When a _key_ \(or several _key_s\) is provided, it describes a path
into a nested set of dictionaries \(much like with **dict set**\)
where the selected leaf indicates a dictionary that is to be opened
out.  When writing back, non-existence of any key on the path is
treated the same as if _dictVarName_ itself didn't exist.

# Examples

A somewhat-less-efficient version of **dict set**:

	 dict update someVar $key local {
	     set local $value

	 }

Sorting a list inside a nested dictionary:

	 dict update someVar OuterKey temp {
	     dict update temp InnerKey temp2 {
	         set temp2 [lsort $temp2]


	     }
	 }

"Renaming" a key:

	 dict update someVar oldKey foo newKey bar {
	     set bar $foo
	     unset foo

	 }

Opening out a nested dictionary:

	 dict update someVar OuterKey temp {
	     dict with temp {
	         # Some script goes in here...


	     }
	 }
	 # Alternative version using a key with 'dict with'...
	 dict with someVar OuterKey {
	     # Some script goes in here...  

	 }

# Reference Implementation

See SF patch 1008768<http://sf.net/tracker/?func=detail&aid=1008768&group_id=10894&atid=310894> .

# Copyright

This document has been placed in the public domain.

Name change from tip/213.tip to tip/213.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

TIP:            213
Title:          A Standard Dialog for Font Selection
Version:        $Revision: 1.7 $
Author:         Donal K. Fellows <[email protected]>
Author:         Pat Thoyts <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        21-Aug-2004
Post-History:   
Keywords:       Tk
Obsoleted-By:	324
Tcl-Version:    8.6


~ Abstract

This TIP proposes a new command that pops up a dialog box that allows
the selection of a font.  Where possible, this dialog will be
implemented using the host platform's standard dialogs.

~ Rationale

A number of platforms (Windows and MacOSX) have standard dialogs for
common user-oriented tasks, and Tk provides an interface to these
 dialogs through commands such as ''tk_getOpenFile'' and
''tk_chooseColor''. However, another dialog that they provide and
which some programs would find useful is a font selector.  This TIP
proposes adding a command to do just that; where a platform does not
provide such a standard dialog, one implemented using a Tcl script
will be used instead.

~ Proposed Change

Tk shall have a new command, '''tk_chooseFont''', with the syntax
described below (which should be recognizably similar to
'''tk_chooseColor''').  The dialog will not return a result as on some platforms (MacOSX) this is required to be modeless while on others (Windows) it must be modal. Therefore all actions will be done via an ''-apply'' command. In the modal case clicking either the ''Apply'' button (if present) or the ''OK'' button will cause the ''-apply'' command to be called with the font specification appended as an additional argument. If ''Cancel'' is chosen then this is not called. For the modeless (MacOSX) case calling the ''tk_chooseFont'' command will cause the dialog to be displayed and closing the dialog will just withdraw it.

 > '''tk_chooseFont''' ?''-option value -option value ...''?

Permitted options are:

 -parent: This specifies the parent window of the dialog (similarly to
  the '''-parent''' option to other dialogs).

 -title: This specifies the title of the dialog. If the platform
  specific dialog cannot support this then the option is ignored.

 -initialfont: This specifies the initial font in any form given on
  the font(n) manual page (section "FONT DESCRIPTION"). Provided it
  is supported by the platform implementation this font will be
  selected when the dialog is displayed.

 -apply: This specifies a command prefix to be called when a
  font selection has been made by the user. The command will
  have the font specification appended as the final parameter
  and is then evaluated in the global namespace. The font
  specification will be a list of the form described on the
  font(n) manual page under "FONT DESCRIPTION" section 3.
  That is a list of {family size style ?style ...?}

Whenever a platform provides a suitable font dialog in its own API, Tk
should not use a script-based alternative, even if this means missing
out on features like the title or dynamic updating of the font during
the selection process.

User code should not expect to receive a result from ''tk_chooseFont'' and may not assume that the dialog has been withdrawn or closed when the command returns.

~ Reference Implementation

http://sourceforge.net/support/tracker.php?aid=1477426

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|





|

|

|
|





|

|
|
|

|



|
|





|








|
|






|

|

|

|


>

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

# TIP 213: A Standard Dialog for Font Selection

	Author:         Donal K. Fellows <[email protected]>
	Author:         Pat Thoyts <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        21-Aug-2004
	Post-History:   
	Keywords:       Tk
	Obsoleted-By:	324
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes a new command that pops up a dialog box that allows
the selection of a font.  Where possible, this dialog will be
implemented using the host platform's standard dialogs.

# Rationale

A number of platforms \(Windows and MacOSX\) have standard dialogs for
common user-oriented tasks, and Tk provides an interface to these
 dialogs through commands such as _tk\_getOpenFile_ and
_tk\_chooseColor_. However, another dialog that they provide and
which some programs would find useful is a font selector.  This TIP
proposes adding a command to do just that; where a platform does not
provide such a standard dialog, one implemented using a Tcl script
will be used instead.

# Proposed Change

Tk shall have a new command, **tk\_chooseFont**, with the syntax
described below \(which should be recognizably similar to
**tk\_chooseColor**\).  The dialog will not return a result as on some platforms \(MacOSX\) this is required to be modeless while on others \(Windows\) it must be modal. Therefore all actions will be done via an _-apply_ command. In the modal case clicking either the _Apply_ button \(if present\) or the _OK_ button will cause the _-apply_ command to be called with the font specification appended as an additional argument. If _Cancel_ is chosen then this is not called. For the modeless \(MacOSX\) case calling the _tk\_chooseFont_ command will cause the dialog to be displayed and closing the dialog will just withdraw it.

 > **tk\_chooseFont** ?_-option value -option value ..._?

Permitted options are:

 -parent: This specifies the parent window of the dialog \(similarly to
  the **-parent** option to other dialogs\).

 -title: This specifies the title of the dialog. If the platform
  specific dialog cannot support this then the option is ignored.

 -initialfont: This specifies the initial font in any form given on
  the font\(n\) manual page \(section "FONT DESCRIPTION"\). Provided it
  is supported by the platform implementation this font will be
  selected when the dialog is displayed.

 -apply: This specifies a command prefix to be called when a
  font selection has been made by the user. The command will
  have the font specification appended as the final parameter
  and is then evaluated in the global namespace. The font
  specification will be a list of the form described on the
  font\(n\) manual page under "FONT DESCRIPTION" section 3.
  That is a list of \{family size style ?style ...?\}

Whenever a platform provides a suitable font dialog in its own API, Tk
should not use a script-based alternative, even if this means missing
out on features like the title or dynamic updating of the font during
the selection process.

User code should not expect to receive a result from _tk\_chooseFont_ and may not assume that the dialog has been withdrawn or closed when the command returns.

# Reference Implementation

<http://sourceforge.net/support/tracker.php?aid=1477426>

# Copyright

This document has been placed in the public domain.

Name change from tip/214.tip to tip/214.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

TIP:            214
Title:          Add New Object Introspection Command
Version:        $Revision: 1.7 $
Author:         Ulrich Sch�bel <[email protected]>
Author:         Larry W. Virden <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        24-Aug-2004
Post-History:   
Keywords:       Tcl,info,representation
Tcl-Version:    8.7
Obsoletes:	117


~ Abstract

This TIP proposes the new '''representation''' subcommand to '''info'''
which returns the internal representation of a variable's contents.

~Rationale

Inspired by a posting on news:comp.lang.tcl by Victor Wagner, I
considered a facility to obtain the internal representation of 
the value of a variable to be useful.

   * It further extends the Tcl introspection commands.

   * It offers a method to check the type of a variable without
     conversion.

   * During the development process it is useful to detect/avoid
     shimmering and its negative performance effects.

~Proposed Change

Add the new subcommand '''info representation''' with the following
syntax:

 > '''info representation''' ''varName''

It returns the type of the variable ''varName'' or an error, if

   * ''varName'' doesn't exist,

   * ''varName'' is an array and no index is provided,

   * ''varName'' is a scalar variable but an index is provided.

~Implementation

A patch against Tcl8.4.6 is available
[http://sf.net/support/tracker.php?aid=1015338].

~Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|


|













|

|


|

|

|

|

|

|


|

|


>

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

# TIP 214: Add New Object Introspection Command

	Author:         Ulrich Schöbel <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        24-Aug-2004
	Post-History:   
	Keywords:       Tcl,info,representation
	Tcl-Version:    8.7
	Obsoletes:	117
-----

# Abstract

This TIP proposes the new **representation** subcommand to **info**
which returns the internal representation of a variable's contents.

# Rationale

Inspired by a posting on news:comp.lang.tcl by Victor Wagner, I
considered a facility to obtain the internal representation of 
the value of a variable to be useful.

   * It further extends the Tcl introspection commands.

   * It offers a method to check the type of a variable without
     conversion.

   * During the development process it is useful to detect/avoid
     shimmering and its negative performance effects.

# Proposed Change

Add the new subcommand **info representation** with the following
syntax:

 > **info representation** _varName_

It returns the type of the variable _varName_ or an error, if

   * _varName_ doesn't exist,

   * _varName_ is an array and no index is provided,

   * _varName_ is a scalar variable but an index is provided.

# Implementation

A patch against Tcl8.4.6 is available
<http://sf.net/support/tracker.php?aid=1015338> .

# Copyright

This document has been placed in the public domain.

Name change from tip/215.tip to tip/215.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

TIP:            215
Title:          Make [incr] Auto-Initialize Undefined Variables
Version:        $Revision: 1.11 $
Author:         Andreas Leitgeb <[email protected]>
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        25-Aug-2004
Post-History:   
Keywords:       Tcl
Tcl-Version:    8.5


~ Abstract

Unlike '''append''' and '''lappend''', '''incr''' currently does not
auto-create yet-undefined variables.  This TIP proposes to make
'''incr''''s behaviour in this regard more like the aforementioned
commands.

~ Rationale

A quite common task is counting the number of occurrences of items in
a given list.  The usual solution is to iterate the list, and for each
item, increment the associated value in a tcl-array.  As of now this
requires a separate step of determining the not-yet-existence and
eventual initialization to 0 or alternatively '''catch''''ing errors
from '''incr''' and setting the variable, if an error was raised.

If we instead alter '''incr''' to treat non-existant variables as if
they contained the value 0, this would be more like the
auto-initializing behaviour of '''append''' and '''lappend''', and
would make writing code that does this sort of summing up much
easier.  It is also very similar to the way that the '''dict incr'''
subcommand operates.

~ No Change for Variables that Contain Non-Integers

Just as '''lappend''' does complain if passed a variable whose value
is an invalid list (e.g. a single open-brace), so it appears
reasonable for '''incr''' to still throw an error if the variable
contains something that is not a number.

The empty string is invalid as an operand for '''expr''''s integer
operators, so it should remain illegal to '''incr''' an existing
variable that contains an empty string.

~ Further Special Cases

If a variable passed to incr is not yet existing, but linked to some
other not-yet existing var, or if it is traced, then of course it
would add flesh to that existing husk. Care should be taken that any
write traces only trigger once (like for '''lappend'''), not twice (as
in: for initializing and then for incrementing).

~ Proposal

The current '''incr''' command behaves like the following
proc:

| proc incr {varName {increment 1}} {
|     upvar 1 $varName v
|     return [set v [expr {$v + $increment}]] ;# read/write trace
| }  


It is proposed to make '''incr''' behave like the following
modified proc:

| proc incr {varName {increment 1}} {
|     upvar 1 $varName v
|     set code [catch {set v} value] ;# read trace
|     if {$code} {
|         return [set v $increment]  ;# write trace
|     }

|     return [set v [expr {$value + $increment}]] ;# write trace
| }  


Please note these example procs are meant to illustrate
the proposed change only.  They do not fully reflect
the exact function of '''incr''' (limiting to only
integer values, for example).

For a more concrete illustration of the proposal,
see the reference implementation, SF patch #1413115 [http://sourceforge.net/tracker/index.php?func=detail&aid=1413115&group_id=10894&atid=310894].

~ Discussion

There have been comments that '''incr''' modified as proposed
would lose one means of typo-detection: If the varname is mistyped,
then instead of throwing an error, it would turn into a noop.

My (TIP-originator) answer to this:  relying on thrown exceptions 
for mistyped varnames is a very weak strategy in dynamic 
(non-compiled) languages like tcl, anyway, because
it would require a 100%-test-coverage of execution-paths.

Nevertheless, this shouldn't exclude discussion about less
typo-forgiving alternatives:

Proposed (by others) alternative #1: make  '''incr''' accept a second
optional argument ''init'' which, if specified, will cause '''incr''' to 
accept non-existent variables and initialize them
with the value ''init''.
One disadvantage of this behaviour is, that it is at odds with append
and lappend behaviour, which would rather imply that if more than
one argument is given after the varname, then each of them would
be added in row. Another con would be, that it would not be intuitive,
whether the resulting value would be ''init'' or
(''init'' + ''increment'').
Similar alternatives mentioning new option '''-initValue'''
are over-verbose imho.

Another way to partially reduce this proposal's forgiveness would be
to allow autoinitialization only for array-elements. This looks
grossly unorthogonal at first sight, but addresses the fact, that
the primary reason for TIP 215 was counting occurrences of strings,
which are then made keys in an array. The danger of mistyped 
array-keys is surely much lower than that of mistyped variable
names.  See [224]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|

|


|





|
|

|

|

|


|

|
|
|


|
|


|




|
|

|

|


|
|
|
<
|
>
|


|
|
|
|
|
<
>
|
<
>



|
|


|

|

|



|

|





|
|

|




|
|
|








|

|


>

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

# TIP 215: Make [incr] Auto-Initialize Undefined Variables

	Author:         Andreas Leitgeb <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        25-Aug-2004
	Post-History:   
	Keywords:       Tcl
	Tcl-Version:    8.5
-----

# Abstract

Unlike **append** and **lappend**, **incr** currently does not
auto-create yet-undefined variables.  This TIP proposes to make
**incr**'s behaviour in this regard more like the aforementioned
commands.

# Rationale

A quite common task is counting the number of occurrences of items in
a given list.  The usual solution is to iterate the list, and for each
item, increment the associated value in a tcl-array.  As of now this
requires a separate step of determining the not-yet-existence and
eventual initialization to 0 or alternatively **catch**'ing errors
from **incr** and setting the variable, if an error was raised.

If we instead alter **incr** to treat non-existant variables as if
they contained the value 0, this would be more like the
auto-initializing behaviour of **append** and **lappend**, and
would make writing code that does this sort of summing up much
easier.  It is also very similar to the way that the **dict incr**
subcommand operates.

# No Change for Variables that Contain Non-Integers

Just as **lappend** does complain if passed a variable whose value
is an invalid list \(e.g. a single open-brace\), so it appears
reasonable for **incr** to still throw an error if the variable
contains something that is not a number.

The empty string is invalid as an operand for **expr**'s integer
operators, so it should remain illegal to **incr** an existing
variable that contains an empty string.

# Further Special Cases

If a variable passed to incr is not yet existing, but linked to some
other not-yet existing var, or if it is traced, then of course it
would add flesh to that existing husk. Care should be taken that any
write traces only trigger once \(like for **lappend**\), not twice \(as
in: for initializing and then for incrementing\).

# Proposal

The current **incr** command behaves like the following
proc:

	 proc incr {varName {increment 1}} {
	     upvar 1 $varName v
	     return [set v [expr {$v + $increment}]] ;# read/write trace

	 }  

It is proposed to make **incr** behave like the following
modified proc:

	 proc incr {varName {increment 1}} {
	     upvar 1 $varName v
	     set code [catch {set v} value] ;# read trace
	     if {$code} {
	         return [set v $increment]  ;# write trace

	     }
	     return [set v [expr {$value + $increment}]] ;# write trace

	 }  

Please note these example procs are meant to illustrate
the proposed change only.  They do not fully reflect
the exact function of **incr** \(limiting to only
integer values, for example\).

For a more concrete illustration of the proposal,
see the reference implementation, SF patch \#1413115 <http://sourceforge.net/tracker/index.php?func=detail&aid=1413115&group_id=10894&atid=310894> .

# Discussion

There have been comments that **incr** modified as proposed
would lose one means of typo-detection: If the varname is mistyped,
then instead of throwing an error, it would turn into a noop.

My \(TIP-originator\) answer to this:  relying on thrown exceptions 
for mistyped varnames is a very weak strategy in dynamic 
\(non-compiled\) languages like tcl, anyway, because
it would require a 100%-test-coverage of execution-paths.

Nevertheless, this shouldn't exclude discussion about less
typo-forgiving alternatives:

Proposed \(by others\) alternative \#1: make  **incr** accept a second
optional argument _init_ which, if specified, will cause **incr** to 
accept non-existent variables and initialize them
with the value _init_.
One disadvantage of this behaviour is, that it is at odds with append
and lappend behaviour, which would rather imply that if more than
one argument is given after the varname, then each of them would
be added in row. Another con would be, that it would not be intuitive,
whether the resulting value would be _init_ or
\(_init_ \+ _increment_\).
Similar alternatives mentioning new option **-initValue**
are over-verbose imho.

Another way to partially reduce this proposal's forgiveness would be
to allow autoinitialization only for array-elements. This looks
grossly unorthogonal at first sight, but addresses the fact, that
the primary reason for TIP 215 was counting occurrences of strings,
which are then made keys in an array. The danger of mistyped 
array-keys is surely much lower than that of mistyped variable
names.  See [[224]](224.md)

# Copyright

This document has been placed in the public domain.

Name change from tip/216.tip to tip/216.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

TIP:		216
Title:		Handling Command-Line Options in Tclsh and Wish
Version:	$Revision: 1.5 $
Author:		Arjen Markus <[email protected]>
State:		Draft
Type:		Project
Vote:		Pending
Created:	23-Aug-2004
Post-History:	
Tcl-Version:	8.7
Keywords:	Tcl, debugging, argument, shell


~ Abstract

Currently there is no means to add new command-line options to the
standard Tcl shells, tclsh and wish, that can be handled at the script
level. This hampers the development of, for instance, a scripted
debugger or tracing tool, because the shell must be called with an
awkward command line (stating the location of the script file
implementing the facility).  This TIP proposes a simple mechanism so
that a command line like "tclsh -debug myprog.tcl" is possible.  The
new mechanism relies on the existing package mechanism and a few
conventions. It can be implemented for the most part in Tcl.

~ Rationale

With Tcl 8.4 it is quite easy to create a scripted debugger - see for
instance [http://wiki.tcl.tk/6007] and [http://wiki.tcl.tk.12251] -
since this version introduced execution traces. However, it is less
simple to turn that into an "out-of-the-box" resource: suppose its
implementation file is "debug.tcl", residing in a directory
"~/my-tcl-utils" (or "d:\my-tcl-utils" under Windows), then the
following command-line is necessary:

| tclsh ~/my-tcl-utils/debug.tcl myapp.tcl

or under Windows:

| tclsh d:\my-tcl-utils\debug.tcl myapp.tcl

instead of the more elegant:

| tclsh -debug myapp.tcl

where some mechanism links the option "-debug" to the implementation
file "debug.tcl".

An alternative method could be to make the file "debug.tcl" a loadable
package but this requires the user to change the application: it
should then load the debug package whenever the user wants to
interactively debug it.

~ Proposed Changes

The only thing that needs to be changed in tclsh and wish
(''TclMain.c'' and ''TkMain.c'' respectively) or any other shell to
benefit from this new feature is that just before sourcing the file
given on the command-line or going into an interactive loop, is that a
new procedure is called, "HandleCmdLine" (and some proper processing
of its results).

This procedure, which will reside in ''init.tcl'', does the following
(at least in the proposed, default, implementation):

 * it loops over the command-line arguments (in the global variable
   ''argv''): if the argument starts with "-", it is considered an
   option (and it is removed from ''argv'').

 * the option is translated into the name of a package that gets
   loaded.

 * if the initialisation code of the package recognises other
   arguments, it must remove them from the list contained in ''argv''.

 * this continues until an argument is found that does not qualify as
   an option.

A simple implementation of this procedure is:

| proc HandleCmdLine {} {
|    while { [string index [lindex $::argv 0]] == "-" } {
|       set pkg [string range [lindex $::argv 0] 1 end]
|       package require $pkg
|
|       set ::argv [lrange $::argv 1 end]
|    }

|
|    if { [llength $::argv] > 0 } {
|       set ::argv0 [lindex $::argv 0]
|       set ::argv [lrange $::argv 1 end]
|    }
| }



(Details like proper error handling are left out for simplicity.)

After the call to this procedure in the C code, variable ''argv0''
must be examined to determine if the shell is to be run interactively
or not.

With the proposed mechanism, tclsh or wish can be invoked with:

| tclsh -debug myapp.tcl

or:

| tclsh -trace -out "report.out" myapp.tcl

(assuming that the package trace recognises the option -out)

or:

| wish -tkcon myapp.tcl

(assuming Tkcon has been turned into a package)

~ Reference Implementation

None yet.

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|
|




|


|



|


|



|



|









|


|


|
|

|
|

|
|
|





|






|
|
|
|
|
|
<
>
|
|
|
|
<
<
|
>
>
|

|





|



|

|



|

|

|



|


>

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

# TIP 216: Handling Command-Line Options in Tclsh and Wish

	Author:		Arjen Markus <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		Pending
	Created:	23-Aug-2004
	Post-History:	
	Tcl-Version:	8.7
	Keywords:	Tcl, debugging, argument, shell
-----

# Abstract

Currently there is no means to add new command-line options to the
standard Tcl shells, tclsh and wish, that can be handled at the script
level. This hampers the development of, for instance, a scripted
debugger or tracing tool, because the shell must be called with an
awkward command line \(stating the location of the script file
implementing the facility\).  This TIP proposes a simple mechanism so
that a command line like "tclsh -debug myprog.tcl" is possible.  The
new mechanism relies on the existing package mechanism and a few
conventions. It can be implemented for the most part in Tcl.

# Rationale

With Tcl 8.4 it is quite easy to create a scripted debugger - see for
instance <http://wiki.tcl.tk/6007>  and <http://wiki.tcl.tk.12251>  -
since this version introduced execution traces. However, it is less
simple to turn that into an "out-of-the-box" resource: suppose its
implementation file is "debug.tcl", residing in a directory
"~/my-tcl-utils" \(or "d:\\my-tcl-utils" under Windows\), then the
following command-line is necessary:

	 tclsh ~/my-tcl-utils/debug.tcl myapp.tcl

or under Windows:

	 tclsh d:\my-tcl-utils\debug.tcl myapp.tcl

instead of the more elegant:

	 tclsh -debug myapp.tcl

where some mechanism links the option "-debug" to the implementation
file "debug.tcl".

An alternative method could be to make the file "debug.tcl" a loadable
package but this requires the user to change the application: it
should then load the debug package whenever the user wants to
interactively debug it.

# Proposed Changes

The only thing that needs to be changed in tclsh and wish
\(_TclMain.c_ and _TkMain.c_ respectively\) or any other shell to
benefit from this new feature is that just before sourcing the file
given on the command-line or going into an interactive loop, is that a
new procedure is called, "HandleCmdLine" \(and some proper processing
of its results\).

This procedure, which will reside in _init.tcl_, does the following
\(at least in the proposed, default, implementation\):

 * it loops over the command-line arguments \(in the global variable
   _argv_\): if the argument starts with "-", it is considered an
   option \(and it is removed from _argv_\).

 * the option is translated into the name of a package that gets
   loaded.

 * if the initialisation code of the package recognises other
   arguments, it must remove them from the list contained in _argv_.

 * this continues until an argument is found that does not qualify as
   an option.

A simple implementation of this procedure is:

	 proc HandleCmdLine {} {
	    while { [string index [lindex $::argv 0]] == "-" } {
	       set pkg [string range [lindex $::argv 0] 1 end]
	       package require $pkg
	
	       set ::argv [lrange $::argv 1 end]

	    }
	
	    if { [llength $::argv] > 0 } {
	       set ::argv0 [lindex $::argv 0]
	       set ::argv [lrange $::argv 1 end]


	    }
	 }

\(Details like proper error handling are left out for simplicity.\)

After the call to this procedure in the C code, variable _argv0_
must be examined to determine if the shell is to be run interactively
or not.

With the proposed mechanism, tclsh or wish can be invoked with:

	 tclsh -debug myapp.tcl

or:

	 tclsh -trace -out "report.out" myapp.tcl

\(assuming that the package trace recognises the option -out\)

or:

	 wish -tkcon myapp.tcl

\(assuming Tkcon has been turned into a package\)

# Reference Implementation

None yet.

# Copyright

This document is placed in the public domain.

Name change from tip/217.tip to tip/217.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

TIP:            217
Title:          Getting Sorted Indices out of Lsort
Version:        $Revision: 1.20 $
Author:         James P. Salsman <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        26-Aug-2004
Post-History:   
Keywords:       Tcl,lsort,parallel lists
Tcl-Version:    8.5


~ Abstract

An '''-indices''' option is proposed for the '''lsort''' command, returning the indices of the given list's elements in the order that they would have otherwise been sorted.

~ Rationale

When corresponding parallel lists must be simultaneously sorted or 
accessed in the order given by sorting them all according to one used 
as a list of keys, it is necessary to obtain the indices of the key list's elements in the order that they would be sorted, without 
actually sorting the list.  For example, a list of first names and a 
corresponding list of last names can be displayed in side-by-side Tk 
listboxes, in which case we may want to sort both lists by either one 
used as the sorting key, or we may want to simultaneously iterate over 
both in either order.  To do so, merely sorting a list is unhelpful; 
we need to obtain the indices of the key list in the order that its 
corresponding elements would be sorted.

Tk listboxes, database I/O, and statistics applications often 
involve heavy use of parallel lists.  For this and other reasons, many
programming languages starting at least as early as APL, up to 
present-day, numerics-oriented languages such as MATLAB, have included 
the ability to directly obtain the indices required to access a list 
(or "vector") in sorted order.  As shown below, the fastest known 
pure Tcl solution to this problem takes about five times as long as 
the given reference implementation, which adds virtually no overhead 
when it is not invoked.

~ Specification

The '''lsort''' command may accept a new option, '''-indices'''.
When '''lsort''' is invoked with this option, it will return a list 
of integer indices of the elements of the list given as the final
argument to '''lsort''', in the order that the elements would have
been sorted had the '''-indices''' option not been specified.

This means an alternative (though less efficient for single lists) mechanism for producing a sorted list could be:

|  set resultList [list]
|  foreach idx [lsort -indices $sourceList] {
|    lappend resultList [lindex $sourceList $idx]
|  }


~ Reference Implementation

The reference implementation is available from SourceForge [http://sourceforge.net/tracker/index.php?func=detail&aid=1017532&group_id=10894&atid=310894] 
It may need to be applied with '''patch -l''' or '''patch --ignore-whitespace''' or it may not apply entirely.

That reference implementation is a 109-line context diff, involving 
adding 20 lines of code to ''tclCmdIL.c'', a single auto int of
new variable memory overhead, and no more than three additional integer 
comparisons and one integer assignment per use of '''lsort''' if the 
new option is not invoked.

Compared to the following pure Tcl implementation, the reference 
implementation is 2.4 to 6.7 times faster.  This very efficient Tcl 
implementation was provided by Lars Hellstr�m:

|  proc lsort-indices {itemL} {
|    set pairL [list]
|    foreach item $itemL {
|      lappend pairL [list $item [llength $pairL]]
|    }

|    set indexL [list]
|    foreach pair [lsort -index 0 -real $pairL] {
|      lappend indexL [lindex $pair 1]
|    }

|    set indexL
|  } 


The following timing data are the mean '''time''' returned from 20 different lists of random reals, with 10 iterations each:

|  List size  Ref. Imp.  Pure Tcl  Speedup
|  ---------  ---------  --------  -------   
|      100       13.1      47.9      3.7
|      200       33.9     224.1      6.6
|      300       45.0     303.1      6.7
|      400       62.0     360.6      5.8
|      800      142.3     655.0      4.6
|     1600      486.2    1150.0      2.4
|     5000     1582.5    4847.6      3.1 

At present, the Reference Implementation does not file the 
'''-indices''' switch alphabetically in the C list of '''lsort''' 
switches, or the C switch statement that interprets them.  This 
simple needs to be corrected before final check-in.

~ Suggested Documentation

In the '''lsort''' man page, under '''DESCRIPTION''', change the 
first sentence:

 > "This command sorts the elements of list, returning a new list in
   sorted order."

... to read:

 > "This command sorts the elements of list, and returns a new list in
   sorted order, unless the -indices option is specified, in which
   case a list of integers is returned, corresponding to the indices
   of the given list's elements in the order that they otherwise would
   have been sorted."

Under '''EXAMPLES''', at the end of the section, include the following
lines:

| Obtaining ordered indices:
|
|  % lsort -indices [list a c b]
|  0 2 1
|  % lsort -indices -unique -decreasing -real -index 0 \
|          {{1.2 a} {34.5 b} {34.5 c} {5.6 d}}
|  2 3 0

~ Tcl-core Discussion

Here are some highlights from the discussion of this TIP on the 
Tcl-core mailing list.  No assurance is given that the discussion
is either completely or impartially represented here.

Lars Hellstr�m 
[http://sourceforge.net/mailarchive/message.php?msg_id=9346824] 
described a pure Tcl solution virtually identical to the one shown 
above, "which could be complicated enough to warrent a special [lsort] 
option."  He also suggested a '''-keycommand''' option for sorting on 
keys generated on-the-fly.  Finally, he pointed out a flaw concerning
the example in the Rationale from the original version of this TIP, 
which has since been corrected.

In reply to Lars, James Salsman
[http://sourceforge.net/mailarchive/message.php?msg_id=9348381]
provided timing data and an efficient alternative to 
the '''-keycommand''' idea using this TIP's '''-indices''' proposal.

~ Acknowledgements

Thanks also to George Peter Staplin and Richard Suchenwirth for their 
kind help and good ideas at the genesis of this TIP.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|

|

















|




|

|
|

|
|

|

|
|
|
<
|
>
|

|
|


|

|




|

|
|
|
|
<
>
|
|
|
<
>
|
<
|
>
|

|
|
|
|
|
|
|
|
|


|



|

|













|


|
|
|
|
|
|
|

|





|
|


|





|

|

|




|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

# TIP 217: Getting Sorted Indices out of Lsort

	Author:         James P. Salsman <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        26-Aug-2004
	Post-History:   
	Keywords:       Tcl,lsort,parallel lists
	Tcl-Version:    8.5
-----

# Abstract

An **-indices** option is proposed for the **lsort** command, returning the indices of the given list's elements in the order that they would have otherwise been sorted.

# Rationale

When corresponding parallel lists must be simultaneously sorted or 
accessed in the order given by sorting them all according to one used 
as a list of keys, it is necessary to obtain the indices of the key list's elements in the order that they would be sorted, without 
actually sorting the list.  For example, a list of first names and a 
corresponding list of last names can be displayed in side-by-side Tk 
listboxes, in which case we may want to sort both lists by either one 
used as the sorting key, or we may want to simultaneously iterate over 
both in either order.  To do so, merely sorting a list is unhelpful; 
we need to obtain the indices of the key list in the order that its 
corresponding elements would be sorted.

Tk listboxes, database I/O, and statistics applications often 
involve heavy use of parallel lists.  For this and other reasons, many
programming languages starting at least as early as APL, up to 
present-day, numerics-oriented languages such as MATLAB, have included 
the ability to directly obtain the indices required to access a list 
\(or "vector"\) in sorted order.  As shown below, the fastest known 
pure Tcl solution to this problem takes about five times as long as 
the given reference implementation, which adds virtually no overhead 
when it is not invoked.

# Specification

The **lsort** command may accept a new option, **-indices**.
When **lsort** is invoked with this option, it will return a list 
of integer indices of the elements of the list given as the final
argument to **lsort**, in the order that the elements would have
been sorted had the **-indices** option not been specified.

This means an alternative \(though less efficient for single lists\) mechanism for producing a sorted list could be:

	  set resultList [list]
	  foreach idx [lsort -indices $sourceList] {
	    lappend resultList [lindex $sourceList $idx]

	  }

# Reference Implementation

The reference implementation is available from SourceForge <http://sourceforge.net/tracker/index.php?func=detail&aid=1017532&group_id=10894&atid=310894>  
It may need to be applied with **patch -l** or **patch --ignore-whitespace** or it may not apply entirely.

That reference implementation is a 109-line context diff, involving 
adding 20 lines of code to _tclCmdIL.c_, a single auto int of
new variable memory overhead, and no more than three additional integer 
comparisons and one integer assignment per use of **lsort** if the 
new option is not invoked.

Compared to the following pure Tcl implementation, the reference 
implementation is 2.4 to 6.7 times faster.  This very efficient Tcl 
implementation was provided by Lars Hellström:

	  proc lsort-indices {itemL} {
	    set pairL [list]
	    foreach item $itemL {
	      lappend pairL [list $item [llength $pairL]]

	    }
	    set indexL [list]
	    foreach pair [lsort -index 0 -real $pairL] {
	      lappend indexL [lindex $pair 1]

	    }
	    set indexL

	  } 

The following timing data are the mean **time** returned from 20 different lists of random reals, with 10 iterations each:

	  List size  Ref. Imp.  Pure Tcl  Speedup
	  ---------  ---------  --------  -------   
	      100       13.1      47.9      3.7
	      200       33.9     224.1      6.6
	      300       45.0     303.1      6.7
	      400       62.0     360.6      5.8
	      800      142.3     655.0      4.6
	     1600      486.2    1150.0      2.4
	     5000     1582.5    4847.6      3.1 

At present, the Reference Implementation does not file the 
**-indices** switch alphabetically in the C list of **lsort** 
switches, or the C switch statement that interprets them.  This 
simple needs to be corrected before final check-in.

# Suggested Documentation

In the **lsort** man page, under **DESCRIPTION**, change the 
first sentence:

 > "This command sorts the elements of list, returning a new list in
   sorted order."

... to read:

 > "This command sorts the elements of list, and returns a new list in
   sorted order, unless the -indices option is specified, in which
   case a list of integers is returned, corresponding to the indices
   of the given list's elements in the order that they otherwise would
   have been sorted."

Under **EXAMPLES**, at the end of the section, include the following
lines:

	 Obtaining ordered indices:
	
	  % lsort -indices [list a c b]
	  0 2 1
	  % lsort -indices -unique -decreasing -real -index 0 \
	          {{1.2 a} {34.5 b} {34.5 c} {5.6 d}}
	  2 3 0

# Tcl-core Discussion

Here are some highlights from the discussion of this TIP on the 
Tcl-core mailing list.  No assurance is given that the discussion
is either completely or impartially represented here.

Lars Hellström 
<http://sourceforge.net/mailarchive/message.php?msg_id=9346824>  
described a pure Tcl solution virtually identical to the one shown 
above, "which could be complicated enough to warrent a special [lsort] 
option."  He also suggested a **-keycommand** option for sorting on 
keys generated on-the-fly.  Finally, he pointed out a flaw concerning
the example in the Rationale from the original version of this TIP, 
which has since been corrected.

In reply to Lars, James Salsman
<http://sourceforge.net/mailarchive/message.php?msg_id=9348381> 
provided timing data and an efficient alternative to 
the **-keycommand** idea using this TIP's **-indices** proposal.

# Acknowledgements

Thanks also to George Peter Staplin and Richard Suchenwirth for their 
kind help and good ideas at the genesis of this TIP.

# Copyright

This document has been placed in the public domain.

Name change from tip/218.tip to tip/218.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

TIP:            218
Title:          Tcl Channel Driver Thread State Actions
Version:        $Revision: 1.10 $
Author:         Andreas Kupries <[email protected]>
Author:         Andreas Kupries <[email protected]>
Author:         Larry W. Virden <[email protected]>
Author:         David Gravereaux <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        09-Sep-2004
Post-History:   
Tcl-Version:    8.5


~ Abstract

This document specifies a modification of the public definition of
channel drivers for the Tcl I/O system to fix a bug in the transfer
of channels between threads affecting all drivers requiring
thread-specific initialization.
The targets for the change are Tcl 8.4.''x'' (note that this is an API
change to a release) and Tcl 8.5.

~ Background and Motivation

The purpose of this TIP is to address and solve a general problem
exposed through the actual usage of the ability to transfer any
channel between threads. Note that this ability was introduced into
the Tcl core before TIPs were used to manage major changes, therefore
it is not possible for us here to refer to a TIP. The relevant entry
in the Tcl core ChangeLog is of 02-May-2000.

The specific instance of the general problem is logged as SourceForge
tracker item 952332[http://sf.net/support/tracker.php?aid=952332] (a
Feature Request in the IOCPSock project). The Socket Channel Driver in
the core maintains state not only per channel, but on Windows also per
thread. This thread specific state is initialized during the first
usage of the '''socket''' command at the script-level,
i.e. ''Tcl_SocketObjCmd()'' at the C-level. The relevant internal
function for this is ''TclpHasSockets()''.

This causes problems when transferring a socket channel into a thread
which has not performed any socket operation before, as the per-thread
state of the driver is '''not''' initialized at all in that case,
causing a crash when trying to use the transfered channel.

This is a general problem all channel drivers maintaining per-thread
state will run into. And on Windows most channel drivers will '''have to''' maintain per-thread state.
This is imposed by the design of the Tcl Notifier.
It manages Event Sources on a per-thread basis, and this implies that the Event Source for channel drivers has to maintain, per-thread, a list of the channels belonging to a thread to make setup and checking for events efficient.
A process global list would be possible, but would also not be very fast, as it would require locking for each search through it, and such searches happens per iteration per active eventloop per Tcl thread.

What is needed is some way to initialize the thread-specific state of
a channel driver for a specific thread, whenever a channel is created
within that thread, independent of the method of creation. This can be
solved without API changes, if we would restrict ourselves to the
channel drivers in the core. This however would make non-core channel
drivers second class. To avoid this an official public API is
required.

Note that the currently used fix in both 8.4 and 8.5 is an ad-hoc
solution without API changes, making external drivers second class. In
8.4 the ad-hoc solution is even incomplete, not covering the sockets,
only files.

This TIP has been written to remedy this deficiency for both 8.4 and 8.5.

~ Specification

It is possible to solve the specific problem described in the last
chapter, by calling the relevant internal function, either in each
low-level socket operation, or during the transfer itself. The first
will slow down all socket operations (one additional check for
per-thread initialization per operation (read, write, seek, ...)), the
second introduces code specific to channel types into the transfer
code. Neither solution is considered acceptable; they are mere
band-aids.

Instead of using one of the band-aids described above, this TIP
proposes to solve the general problem of per-thread channel driver
initialization by extending the public structure of channel drivers
with one new function pointer.

The purpose of this function is not directly the initialization of
per-thread information, but to provide the driver with notifications
when a channel of its type is removed from or added to a thread, by
whatever means (creation, deletion, transfer, ...).  This can be used
not only to initialize the per-thread data of the channel driver,
but for other thread-specific actions of the driver as well.

As we are modifying a public structure, we have to distinguish between
older drivers not supporting the new function and new drivers which
do. The 'Tcl_ChannelType' structure contains a version field just for
this purpose. Currently known versions of drivers are version 0 to 3,
where version 0 is for drivers whose structure does not contain a
version field. The modification proposed in this document now
introduces channel driver version 4.

~~ Details

The definition of the new version tag is

| #define TCL_CHANNEL_VERSION_4 ((Tcl_ChannelTypeVersion) 0x4)

The signature of the new function is

| void Tcl_DriverThreadActionProc (ClientData instanceData, int action);
|
| /* Codes for 'action' */
|
| #define TCL_CHANNEL_THREAD_INSERT (0)
| #define TCL_CHANNEL_THREAD_REMOVE (1)

The ''Tcl_DriverThreadActionProc'' defined for a channel type ''FOO''
will be called by the core with thread ''BAR'' as current thread
whenever:

   1. a channel of type ''FOO'' is created in thread ''BAR''.

   1. a channel of type ''FOO'' is transfered into the thread ''BAR''.

   1. a channel of type ''FOO'' is closed in thread ''BAR''.

   1. a channel of type ''FOO'' is transfered out of the thread
      ''BAR''.

For the first two calls we can assert ''action ==
TCL_CHAN_THREAD_INSERT'', and the last two calls can assert ''action
== TCL_CHAN_THREAD_REMOVE''.

Note that multiple calls of ''Tcl_DriverThreadActionProc'' per thread
are possible and have to be dealt with correctly.

The new definition of structure ''Tcl_ChannelType'' is

| typedef struct Tcl_ChannelType {
| [... Existing Definition ...]
|     /*
|      * Only valid in TCL_CHANNEL_VERSION_4 channels or later
|      */
|     Tcl_DriverThreadActionProc *threadActionProc;
|                                       /* Procedure to call to notify
|                                        * the driver of thread specific
|                                        * activity for a channel.
|                                        * May be NULL. */
| } Tcl_ChannelType;

A new public accessor API is provided as well, returning a pointer to
the new function (or NULL if it does not exist).

| Tcl_DriverThreadActionProc *
| Tcl_ChannelThreadActionProc(Tcl_ChannelType* typePtr);

~ Discarded Solutions

It was initially proposed to extend the driver structure with a
function having only a very narrow purpose- the initialization of the
thread specific data of the driver.

This was dropped because the solution actually proposed is more
general and thus should be more stable in the long term. In other
words, we believe that the adoption of the general solution reduces
the risk of having to extend the Channel driver API again in the
future, compared to the risk of this should we adopt the narrow
solution.

Another approach uses the same model as specified here, i.e. general
cut and splice functionality, but uses two driver functions to
implement this. The problem with this approach is that an implementor
of a driver might get confused and realize only one of the two
functions, i.e. only part of the required functionality.

~ Reference Implementation

A reference implementation is provided at SourceForge
[http://sourceforge.net/support/tracker.php?aid=875701].

~ Comments

David Gravereaux has recently tested this with his IOCPSOCK extension (11/26) and found no problems.  If it hastens the acceptance of the TIP, 
David does not need the one export in the patch (''Tcl_DriverThreadActionProc'') to be exported for his extension to work.  Others that do channel chaining (windows expect, for example), will most likely need it.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|





|
|

|









|
|


|
|
|



|



|



















|




|
|












|





|





|



|



|
|
|
|
|
|

|
|


|

|

|

|
|

|
|
|

|


|

|
|
|
|
|
|
|
|
|
|
|


|

|
|

|


















|


|

|

|
|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

# TIP 218: Tcl Channel Driver Thread State Actions

	Author:         Andreas Kupries <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	Author:         David Gravereaux <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        09-Sep-2004
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This document specifies a modification of the public definition of
channel drivers for the Tcl I/O system to fix a bug in the transfer
of channels between threads affecting all drivers requiring
thread-specific initialization.
The targets for the change are Tcl 8.4._x_ \(note that this is an API
change to a release\) and Tcl 8.5.

# Background and Motivation

The purpose of this TIP is to address and solve a general problem
exposed through the actual usage of the ability to transfer any
channel between threads. Note that this ability was introduced into
the Tcl core before TIPs were used to manage major changes, therefore
it is not possible for us here to refer to a TIP. The relevant entry
in the Tcl core ChangeLog is of 02-May-2000.

The specific instance of the general problem is logged as SourceForge
tracker item 952332<http://sf.net/support/tracker.php?aid=952332>  \(a
Feature Request in the IOCPSock project\). The Socket Channel Driver in
the core maintains state not only per channel, but on Windows also per
thread. This thread specific state is initialized during the first
usage of the **socket** command at the script-level,
i.e. _Tcl\_SocketObjCmd\(\)_ at the C-level. The relevant internal
function for this is _TclpHasSockets\(\)_.

This causes problems when transferring a socket channel into a thread
which has not performed any socket operation before, as the per-thread
state of the driver is **not** initialized at all in that case,
causing a crash when trying to use the transfered channel.

This is a general problem all channel drivers maintaining per-thread
state will run into. And on Windows most channel drivers will **have to** maintain per-thread state.
This is imposed by the design of the Tcl Notifier.
It manages Event Sources on a per-thread basis, and this implies that the Event Source for channel drivers has to maintain, per-thread, a list of the channels belonging to a thread to make setup and checking for events efficient.
A process global list would be possible, but would also not be very fast, as it would require locking for each search through it, and such searches happens per iteration per active eventloop per Tcl thread.

What is needed is some way to initialize the thread-specific state of
a channel driver for a specific thread, whenever a channel is created
within that thread, independent of the method of creation. This can be
solved without API changes, if we would restrict ourselves to the
channel drivers in the core. This however would make non-core channel
drivers second class. To avoid this an official public API is
required.

Note that the currently used fix in both 8.4 and 8.5 is an ad-hoc
solution without API changes, making external drivers second class. In
8.4 the ad-hoc solution is even incomplete, not covering the sockets,
only files.

This TIP has been written to remedy this deficiency for both 8.4 and 8.5.

# Specification

It is possible to solve the specific problem described in the last
chapter, by calling the relevant internal function, either in each
low-level socket operation, or during the transfer itself. The first
will slow down all socket operations \(one additional check for
per-thread initialization per operation \(read, write, seek, ...\)\), the
second introduces code specific to channel types into the transfer
code. Neither solution is considered acceptable; they are mere
band-aids.

Instead of using one of the band-aids described above, this TIP
proposes to solve the general problem of per-thread channel driver
initialization by extending the public structure of channel drivers
with one new function pointer.

The purpose of this function is not directly the initialization of
per-thread information, but to provide the driver with notifications
when a channel of its type is removed from or added to a thread, by
whatever means \(creation, deletion, transfer, ...\).  This can be used
not only to initialize the per-thread data of the channel driver,
but for other thread-specific actions of the driver as well.

As we are modifying a public structure, we have to distinguish between
older drivers not supporting the new function and new drivers which
do. The 'Tcl\_ChannelType' structure contains a version field just for
this purpose. Currently known versions of drivers are version 0 to 3,
where version 0 is for drivers whose structure does not contain a
version field. The modification proposed in this document now
introduces channel driver version 4.

## Details

The definition of the new version tag is

	 #define TCL_CHANNEL_VERSION_4 ((Tcl_ChannelTypeVersion) 0x4)

The signature of the new function is

	 void Tcl_DriverThreadActionProc (ClientData instanceData, int action);
	
	 /* Codes for 'action' */
	
	 #define TCL_CHANNEL_THREAD_INSERT (0)
	 #define TCL_CHANNEL_THREAD_REMOVE (1)

The _Tcl\_DriverThreadActionProc_ defined for a channel type _FOO_
will be called by the core with thread _BAR_ as current thread
whenever:

   1. a channel of type _FOO_ is created in thread _BAR_.

   1. a channel of type _FOO_ is transfered into the thread _BAR_.

   1. a channel of type _FOO_ is closed in thread _BAR_.

   1. a channel of type _FOO_ is transfered out of the thread
      _BAR_.

For the first two calls we can assert _action ==
TCL\_CHAN\_THREAD\_INSERT_, and the last two calls can assert _action
== TCL\_CHAN\_THREAD\_REMOVE_.

Note that multiple calls of _Tcl\_DriverThreadActionProc_ per thread
are possible and have to be dealt with correctly.

The new definition of structure _Tcl\_ChannelType_ is

	 typedef struct Tcl_ChannelType {
	 [... Existing Definition ...]
	     /*
	      * Only valid in TCL_CHANNEL_VERSION_4 channels or later
	      */
	     Tcl_DriverThreadActionProc *threadActionProc;
	                                       /* Procedure to call to notify
	                                        * the driver of thread specific
	                                        * activity for a channel.
	                                        * May be NULL. */
	 } Tcl_ChannelType;

A new public accessor API is provided as well, returning a pointer to
the new function \(or NULL if it does not exist\).

	 Tcl_DriverThreadActionProc *
	 Tcl_ChannelThreadActionProc(Tcl_ChannelType* typePtr);

# Discarded Solutions

It was initially proposed to extend the driver structure with a
function having only a very narrow purpose- the initialization of the
thread specific data of the driver.

This was dropped because the solution actually proposed is more
general and thus should be more stable in the long term. In other
words, we believe that the adoption of the general solution reduces
the risk of having to extend the Channel driver API again in the
future, compared to the risk of this should we adopt the narrow
solution.

Another approach uses the same model as specified here, i.e. general
cut and splice functionality, but uses two driver functions to
implement this. The problem with this approach is that an implementor
of a driver might get confused and realize only one of the two
functions, i.e. only part of the required functionality.

# Reference Implementation

A reference implementation is provided at SourceForge
<http://sourceforge.net/support/tracker.php?aid=875701> .

# Comments

David Gravereaux has recently tested this with his IOCPSOCK extension \(11/26\) and found no problems.  If it hastens the acceptance of the TIP, 
David does not need the one export in the patch \(_Tcl\_DriverThreadActionProc_\) to be exported for his extension to work.  Others that do channel chaining \(windows expect, for example\), will most likely need it.

# Copyright

This document has been placed in the public domain.

Name change from tip/219.tip to tip/219.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
TIP:            219
Title:          Tcl Channel Reflection API
Version:        $Revision: 1.27 $
Author:         Andreas Kupries <[email protected]>
Author:         Andreas Kupries <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        09-Sep-2004
Post-History:   
Tcl-Version:    8.5


~ Abstract

This document describes an API which reflects the Channel Driver API of the
core I/O system up into the Tcl level, for the implementation of channel types
in Tcl. It is built on top of [208] ('Add a chan command') and also an
independent companion to [230] ('Tcl Channel Transformation Reflection API')
and [228] ('Tcl Filesystem Reflection API'). As the later TIPs bring the
ability of writing channel transformations and filesystems in Tcl itself into
the core so this TIP provides the facilities for the implementation of new
channel types in Tcl. This document specifies version ''1'' of the channel
reflection API.

~ Motivation / Rationale

The purpose of this and the other reflection TIPs is to provide all the
facilities required for the creation and usage of wrapped files (= virtual
filesystems attached to executables and binary libraries) within the core.

While it is possible to implement and place all the proposed reflectivity in
separate and external packages, this however means that the core itself cannot
make use of wrapping technology and virtual filesystems to encapsulate and
attach its own data and library files to itself. This is something which is
desirable as it can make the deployment and embedding of the core easier, due
to having less files to deal with, and a higher degree of self-containment.
<
|
<
|
|
|
|
|
|
|
|
>

|



|
|
|


|


|


|
|








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

# TIP 219: Tcl Channel Reflection API

	Author:         Andreas Kupries <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        09-Sep-2004
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This document describes an API which reflects the Channel Driver API of the
core I/O system up into the Tcl level, for the implementation of channel types
in Tcl. It is built on top of [[208]](208.md) \('Add a chan command'\) and also an
independent companion to [[230]](230.md) \('Tcl Channel Transformation Reflection API'\)
and [[228]](228.md) \('Tcl Filesystem Reflection API'\). As the later TIPs bring the
ability of writing channel transformations and filesystems in Tcl itself into
the core so this TIP provides the facilities for the implementation of new
channel types in Tcl. This document specifies version _1_ of the channel
reflection API.

# Motivation / Rationale

The purpose of this and the other reflection TIPs is to provide all the
facilities required for the creation and usage of wrapped files \(= virtual
filesystems attached to executables and binary libraries\) within the core.

While it is possible to implement and place all the proposed reflectivity in
separate and external packages, this however means that the core itself cannot
make use of wrapping technology and virtual filesystems to encapsulate and
attach its own data and library files to itself. This is something which is
desirable as it can make the deployment and embedding of the core easier, due
to having less files to deal with, and a higher degree of self-containment.
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
give users of the core the freedom to experiment with their own ideas, instead
of constraining them to what we managed to envision.

Another use for reflected channels was found when creating the reference
implementation: As helper for testing the generic I/O system of Tcl, by
creating channels which forcibly return errors, bogus data, and the like.

~ Specification

~~ Introduction

This specification has to address two questions to make the reflection work.

 * How are the driver functions reflected into the Tcl level?

 * How are file events generated in the Tcl level communicated back to the C
   level? This includes routing to the correct channel.

~~ C Level API

Four functions are added to the public C API. See section "''Error Handling''"
for their detailed specification.

~~ Tcl Level API

The Tcl Level API consists of two new subcommands added to the ensemble
command '''chan''' specified by [208]. The new subcommands are:

 * '''chan create''' ''mode cmdprefix''

 > This subcommand creates a new script level channel using the command prefix
   ''cmdprefix'' as its handler. The ''cmdprefix'' has to be a list. The API
   this handler has to provide is specified below, in the section "Command
   Handler API". The handle of the new channel is returned as the result of
   the command, and the channel is open. Use the regular '''close''' command
   to remove the channel.

 > The argument ''mode'' specifies if the channel is opened for reading,
   writing, or both. It is a list containing any of the strings '''read''' or
   '''write'''. The list has to have at least one element, as a channel you
   can neither write to nor read from makes no sense. The handler command for
   the new channel has to support the chosen mode. An error is thrown if that
   is not the case.

 > We have chosen to use ''late binding'' of the handler command. See the
   section "''Early versus Late Binding of the Handler Command''" for more
   detailed explanations.

 * '''chan postevent''' ''channel eventspec''

 > This subcommand is for use by command handlers, it notifies the channel
   represented by ''channel'' that the event(s) listed in the ''eventspec''
   have occurred. The argument ''eventspec'' is a list containing any of
   '''read''' and '''write'''. At least one element is required (It does not
   make sense to invoke the command if there are no events to post).

 > Note that this subcommand can be used only on channel handles which were
   created/opened with the subcommand '''create'''. Application to channels
   like files, sockets, etc. is not possible and will cause the generation of
   an error.

 > As only the Tcl level of a channel, i.e. its command handler, should post
   events to it we also restrict the usage of this command to the interpreter
   the handler command is in. In other words, posting events to a reflected
   channel from a different interpreter than its implementation is in is not
   allowed.

 > Another restriction is that it is not possible to post events the I/O core
   has not registered interest in. Trying to do so will cause the method to
   throw an error. See the method '''watch''' in section "Command Handler API"
   as well.

~~ Command Handler API

The Tcl-level handler command for a reflected channel is an ensemble that has
to support the following subcommands, as listed below. Note that the term
''ensemble'' is used to generically describe all command (prefixes) which are
able to process subcommands. This TIP is ''not'' tied to the recently
introduced 'namespace ensemble's.

Of the available methods the handler '''has to''' support '''initialize''',
'''finalize''', and '''watch''', always. The other methods are optional.

 * ''handlerCmd'' '''initialize''' ''channel mode''

 > This is the first call the command handler will receive for the given new
   ''channel''. It is his responsibility to set up any internal data
   structures it needs to keep track of the channel and its state.

 > The return value of the method has to be a list containing the names of all
   methods which are supported by this handler. This implicitly tells the C
   level the version of the API used by the command handler making a separate
   version number redundant. Hence our decision to leave such a number out of
   the API. Any changes to the API will be either the elimination of methods,
   or the introduction of new ones. An existing method cannot change its
   signature (arguments, and result), a new method has to be introduced for
   this. All of this implies that this method, '''initialize''', '''is
   unchangeable''' after the TIP has been committed, as it is the entry point
   through which the C level will determine the API version before it knows
   anything else.

 > Any error thrown by the method will abort the creation of the channel and
   no channel will be created. The thrown error will appear as error thrown by
   '''chan create'''.

 > Any exception beyond ''error'', like ''break'', etc. is treated as and
   converted to an error.

 > '''Important''' - If the creation of the channel was aborted due to
   failures in '''initialize''' then the method '''finalize''' will ''not'' be
   called.

 > This method has no equivalent at the C level.

 > It was considered to return only the list of optional methods supported by
   the handler. The chosen method however should make the code in the C layer
   more regular. Another advantage of this is that it allows the C level to
   better check if the API it expects is matching the API provided by the
   handler.

 > The argument ''mode'' tells the handler if the channel was opened for
   reading, writing, or both. It is a list containing any of the strings
   '''read''' or '''write'''. The C-level doing the call will never generate
   abbreviations of these strings. The list will always contain at least one
   element, as a channel you can neither write to nor read from makes no
   sense.

 > The method has to throw an error if the chosen mode is not supported by the
   handler command.

 * ''handlerCmd'' '''finalize''' ''channel''

 > The method is called when the channel was '''close'''d, and is the last
   call a handler can receive for the given ''channel''. This happens just
   before the destruction of the C level data structures. Still, the command
   handler must not access the channel anymore in no way. It is now his
   responsibility to clean up any internal resources it allocated to this
   channel.

 > The return value of the method is ignored.

 > If the method throws an error the command which caused its invocation
   (usually '''close''') will appear to have thrown this error.

 > Any exception beyond ''error'', like ''break'', etc. is treated as and
   converted to an error.

 > The equivalent C-level function is ''Tcl_DriverCloseProc''.

 > This method is not invoked if the creation of the channel was aborted
   during '''initialize'''.

 * ''handlerCmd'' '''read''' ''channel count''

 > This method is ''optional''. It is called when the user requests data from
   a channel. ''count'' specifies how many ''bytes'' have been requested. If
   the method is not supported then it is not possible to read from the
   channel handled by the command.

 > The return value of the method is taken as the requested data. If the
   returned data contains more bytes than requested an error will be signaled
   and later thrown by the command which performed the read (usually
   '''gets''' or '''read'''). Returning less bytes than requested is
   acceptable however.

 > If the method throws an error the command which caused its invocation
   (usually '''gets''', or '''read''') will appear to have thrown this error.

 > Any exception beyond ''error'', like ''break'', etc. is treated as and
   converted to an error.

 > The equivalent C-level function is ''Tcl_DriverInputProc''.

 * ''handlerCmd'' '''write''' ''channel data''

 > This method is ''optional''. It is called when the user writes data to the
   channel. Note that the ''data'' are bytes, not characters (The underlying
   Tcl_ObjType is ''ByteArray''). Any type of transformation (EOL, encoding)
   configured for the channel has already been applied at this point. If the
   method is not supported then it is not possible to write to the channel
   handled by the command.

 > The return value of the method is taken as the number of bytes written by
   the channel. Anything non-numeric will cause an error to be signaled and
   later thrown by the command which performed the write. A negative value
   implies that the write failed. Returning a value greater than the number of
   bytes given to the handler, or zero, is forbidden and will cause the C
   level to throw errors.

 > If the method throws an error the command which caused its invocation
   (usually '''puts''') will appear to have thrown this error.

 > Any exception beyond ''error'', like ''break'', etc. is treated as and
   converted to an error.

 > The equivalent C-level function is ''Tcl_DriverOutputProc''.

 * ''handlerCmd'' '''seek''' ''channel offset base''

 > This method is ''optional''. It is responsible for the handling of seek and
   tell requests on the channel. If it is not supported then seeking will not
   be possible for the channel.

 > ''base'' is one of

 > * '''start''' - Seeking is relative to the beginning of the channel.

 > * '''current''' - Seeking is relative to the current seek position.

 > * '''end''' - Seeking is relative to the end of the channel.

 > The base argument of the builtin '''seek''' command takes the same names.

 > The ''offset'' is an integer number specifying the amount of ''bytes'' to
   seek forward or backward. A positive number will seek forward, and a
   negative number will seek backward.

 > A channel may provide only limited seeking. For example sockets can seek
   forward, but not backward.

 > The return value of the method is taken as the (new) location of the
   channel, counted from the start. This has to be an integer number greater
   than or equal to zero.

 > If the method throws an error the command which caused its invocation
   (usually '''seek''') will appear to have thrown this error.

 > Any exception beyond ''error'', like ''break'', etc. is treated as and
   converted to an error.

 > The offset/base combination of 0/"current" signals a '''tell''' request,
   i.e. seek nothing relative to the current location, making the new location
   identical to the current one, which is then returned.

 > The equivalent C-level functions are ''Tcl_DriverSeekProc'', and
   ''Tcl_DriverWideSeekProc'' (where possible).

 * ''handlerCmd'' '''configure''' ''channel option value''

 > This method is ''optional''. It is for writing the type specific options.

 > Per call one option has to be written.

 > The return value of the method is ignored.

 > If the method throws an error the command which performed the
   (re)configuration or query (usually '''fconfigure''') will appear to have
   thrown this error.

 > Any exception beyond ''error'', like ''break'', etc. is treated as and
   converted to an error.

 > The equivalent C-level function is ''Tcl_DriverSetOptionProc''.

 * ''handlerCmd'' '''cget''' ''channel option''

 > This method is ''optional''. It is used when reading a single type specific
   option. If this method is supported then the method '''cgetall''' has to be
   supported as well.

 > The call has to return the value of the specified option.

 > If the method throws an error the command which performed the
   (re)configuration or query (usually '''fconfigure''') will appear to have
   thrown this error.

 > The equivalent C-level function is ''Tcl_DriverGetOptionProc''.

 * ''handlerCmd'' '''cgetall''' ''channel''

 > This method is ''optional''. It is used for reading all type specific
   options. If this method is supported then the method '''cget''' has to be
   supported as well.

 > It has to return a list of all options and their values. This list has to
   have an even number of elements.

 > If the method throws an error the command which performed the
   (re)configuration or query (usually '''fconfigure''') will appear to have
   thrown this error.

 > Any exception beyond ''error'', like ''break'', etc. is treated as and
   converted to an error.

 > The equivalent C-level function is ''Tcl_DriverGetOptionProc''.

 * ''handlerCmd'' '''watch''' ''channel eventspec''

 > This methods notifies the Tcl level that the specified channel is
   interesting in the events listed in the ''eventspec''. This is a list
   containing any of '''read''' and '''write'''. The C-level doing the call
   will never generate abbreviations of these strings. The empty list is
   allowed as well and signals that the channel does not wish to be notified
   of any events. In other words, it has to disable event generation at the
   Tcl level.

 > Any return value of the method is ignored. This includes errors thrown by
   the method, break, continue, and custom return codes.

 > The equivalent C-level function is ''Tcl_DriverWatchProc''.

 > This method interacts with '''chan postevent'''. Trying to post an event
   not listed in the last call to this method will cause an error.

 * ''handlerCmd'' '''blocking''' ''channel mode''

 > This method is ''optional''. It handles changes to the blocking mode of the
   channel. The ''mode'' is a boolean flag. True means that the channel has to
   be set to blocking. False means that the channel should be non-blocking.

 > The return value of the method is ignored.

 > If the method throws an error the command which caused its invocation
   (usually '''fconfigure''') will appear to have thrown this error.

 > Any exception beyond ''error'', like ''break'', etc. is treated as and
   converted to an error.

 > The equivalent C-level function is ''Tcl_DriverBlockModeProc''.

Notes:

 * The function ''Tcl_DriverGetHandleProc'' is not supported. There is no
   equivalent handler method at the Tcl level.

 * The function ''Tcl_DriverHandlerProc'' is not supported. There is no
   equivalent handler method at the Tcl level. The function has no relevance
   to base channels, which we work with here, only for channel
   transformations. See [230] ('Tcl Channel Transformation Reflection API')
   for more information on the issue.

 * The function ''Tcl_DriverFlushProc'' is not supported. The reason for this:
   The current generic I/O layer of Tcl does not use this function at all,
   nowhere. Therefore support at the Tcl level makes no sense either. We can
   always extend the API defined here (and change its version number) should
   the function be used at some time in the future.

~~ Error handling

The current I/O core's ability to handle arbitrary Tcl error messages is very
limited. ''Tcl_DriverGetOptionProc'' and ''Tcl_DriverSetOptionProc'' are the
only driver functions for which this is possible directly. Everywhere else the
API is restricted to returning POSIX error codes.

This limitation makes the debugging of problems in a channel command handler
at least very difficult. As such it is considered not acceptable. It is
proposed to solve this problem through the addition of four new functions to
Tcl's public stub table.

 > void '''Tcl_SetChannelError'''(Tcl_Channel ''chan'', Tcl_Obj* ''msg'')

 > void '''Tcl_SetChannelErrorInterp'''(Tcl_Interp* ''ip'', Tcl_Obj* ''msg'')

 > > These functions store error information in a channel or interpreter.
     Previously stored information will be discarded. They have to be used by
     channel drivers wishing to pass regular Tcl error information to the
     generic layer of the I/O core.

 > > The refCount of ''msg'' is unchanged when the functions had to rewrite
     ''msg'' per the safety precautions explained below, as a properly
     modified copy of ''msg'' is stored, and not ''msg'' itself. Otherwise the
     refCount of ''msg'' is incremented by one.

 > void '''Tcl_GetChannelError'''(Tcl_Channel ''chan'', Tcl_Obj** ''msg'')

 > void '''Tcl_GetChannelErrorInterp'''(Tcl_Interp* ''ip'', Tcl_Obj** ''msg'')

 > > These function retrieve error information stored in a channel or
     interpreter O, and also resets O to have no information stored in
     it. They will return NULL if no information was stored to begin with.

 > > i.e. After an invocation of '''Tcl_GetChannelError*''' for a
     channel/interpreter object O, all following invocations will return NULL
     for that object, until an intervening invocation of
     '''Tcl_SetChannelError*''' again stored information in O.

 > > The ''msg'' argument is not allowed to be NULL. Nor are the ''chan'' and
     ''ip'' arguments.

 > > The refCount of the returned information is not touched. The reference
     previously held by the channel or interpreter is now held by the caller
     of the function and it is its responsibility to release that reference
     when it is done with the object.

This solution is not very elegant, but anything else will require an
incompatible redefinition of the whole channel driver structure and of the
driver functions.

It should also be noted that usage of '''Tcl_Obj'''ects for the information
storage binds the information to a single thread. I.e. a transfer across
thread boundaries is not possible. This however is not required here and thus
no limitation.

The four functions have been made public as I can imagine that even C level
drivers might wish to use this facility to generate more explicit and readable
error messages than is provided through POSIX error codes and the errno API.

The information talked about in the API specifications above is '''not''' a
plain string, but has to be a list of uneven length. The last element will be
interpreted as the actual error message in question, and the preceding
elements are considered as option/value pairs containing additional
information about the error, like the ''errorCode'', etc. I.e. they are an
extensible dictionary containing the details of the error beyond the basic
message.

As a '''safety precaution''' any ''-level'' specification submitted by the
driver and a non-zero value will be rewritten to a value of ''0'' to prevent
the driver from being able to force the user application into the execution of
arbitrary multi-level returns, i.e. from arbitrarily changing the control-flow
of the application itself. Analogously any ''-code'' specification with a
non-zero value which is not ''error'' is rewritten to value ''1''
(i.e. ''error'').

Below a list of driver functions, and which of the ''Tcl_SetChannelError*'''
functions they are allowed to use.

 * '''Tcl_DriverCloseProc'''

 > May use ''Tcl_SetChannelErrorInterp'', and only this function.

 * '''Tcl_DriverInputProc'''

 > May use ''Tcl_SetChannelError'', and only this function.

 * '''Tcl_DriverOutputProc'''

 > May use ''Tcl_SetChannelError'', and only this function.

 * '''Tcl_DriverSeekProc''', and '''Tcl_DriverWideSeekProc'''

 > May use ''Tcl_SetChannelError'', and only this function.

 * '''Tcl_DriverSetOptionProc'''

 > Has already the ability to pass arbitrary error messages. Must '''not'''
   use any of the new functions.

 * '''Tcl_DriverGetOptionProc'''

 > Has already the ability to pass arbitrary error messages. Must '''not'''
   use any of the new functions.

 * '''Tcl_DriverWatchProc'''

 > Must '''not''' use any of the new functions. Is internally called and has
   no ability to return any type of error whatsoever.

 * '''Tcl_DriverBlockModeProc'''

 > May use ''Tcl_SetChannelError'', and only this function.

 * '''Tcl_DriverGetHandleProc'''

 > Must '''not''' use any of the new functions. It is only a low-level
   function, and not used by Tcl commands.

 * '''Tcl_DriverHandlerProc'''

 > Must '''not''' use any of the new functions. Is internally called and has
   no ability to return any type of error whatsoever.

Given the information above the following public functions of the Tcl C API
are affected by these changes. I.e. when these functions are called the
channel may now contain a stored arbitrary error message requiring processing
by the caller.

 * '''Tcl_StackChannel'''

 * '''Tcl_Seek'''

 * '''Tcl_Tell'''

 * '''Tcl_ReadRaw'''

 * '''Tcl_Read'''

 * '''Tcl_ReadChars'''

 * '''Tcl_Gets'''

 * '''Tcl_GetsObj'''

 * '''Tcl_Flush'''

 * '''Tcl_WriteRaw'''

 * '''Tcl_WriteObj'''

 * '''Tcl_Write'''

 * '''Tcl_WriteChars'''

All other API functions are unchanged. Especially the functions below leave
all their error information in the interpreter result.

 * '''Tcl_Close'''

 * '''Tcl_UnregisterChannel'''

 * '''Tcl_UnstackChannel'''

A previous revision of this TIP specified only two functions, storing the data
only in channels. This however proved to be inadequate. It allows the transfer
of messages for most driver functions, but not ''close''. Storing an error
message in the channel structure which is destroyed is not helpful. So we need
the functions for storing data in interpreters. Conversely, providing only two
functions storing the information in an interpreter, is inadequate as well.
The circumstances for that to happen are actually very limited, but they can
happen. First, most driver functions are not given an interpreter reference
when called, and actually do not know which interpreter caused their
invocation. The only remedy we have is that the channel structure has to have
an interpreter reference to the interpreter of the command handler, for the
calls into the Tcl level. This could be used in most circumstances, except
when threads are enabled and the channel was transfered out of the thread
containing that interpreter. We are not allowed to use this interpreter from
the channel thread, and again have no other reference available. So for this
the code/message pair has to be stored in a channel as the sole place
available.

A previous revision of this TIP not only stored an error message, but also a
result code in the channel or interpreter, and used it as the return code of
the Tcl command which invoked the driver function returning the exception.
This feature has been discarded as a possible security hazard. It would allow
a malicious Tcl driver to cause ''break'' and ''continue'' exceptions at
arbitrary locations in the overall application, controlling its behaviour as
it sees fit.

I wish to thank Joe English and Vince Darley for their input with regard to
the limitations of error propagation in the I/O core and possible ideas for
solving it. Joe's discourse on the problems with the use of POSIX error codes
in an earlier revision of this TIP made me realize that I should not use them
anywhere in the API for reflected channels and rather concentrate on extending
the I/O system to properly receive Tcl error messages. And while I rejected
the '''TclSetPosixError''' function Vince proposed I hopefully kept the spirit
of that proposal in my solution as well. The main reason against setting an
arbitrary ''posix error string'' was that it invented another way of passing
error information around, whereas the specification above is based on the
existing Tcl_InterpState and attendant functionality.

~~ Interaction with Threads and Other Interpreters.

A channel created with the '''chan create''' command knows the interpreter it
was created in and executes its handler command only in that interpreter, even
if the channel is shared with and/or has been moved into a different
interpreter. This is easy to accomplish, by evaluating the handler command
only in the context of the original interpreter.

The channel also knows the thread it was created in and executes its handler
command only in that thread, even if the channel has been moved into a







|

|








|

|


|


|

|

|
|


|


|
|
|




|
|


|

|
|
|
|
|

|
|



|





|

|


|



|
|


|
|

|

|
|


|





|
|
|



|

|

|


|
|


|

|





|

|




|


|

|
|





|

|
|

|


|

|
|

|

|
|



|

|
|


|
|

|


|

|

|
|
|




|






|
|

|


|

|

|



|

|

|

|

|

|



|


|



|
|

|


|



|
|

|

|

|

|

|
|


|


|

|

|
|


|

|
|


|

|

|
|


|


|
|


|


|

|

|
|
|





|


|

|


|

|
|


|

|
|

|


|



|


|


|


|


|


|


|








|

|






|
|
|
|

|

|





|


|

|
|










|








|



|



|
|


|
|
|

|


|

|

|

|

|

|

|

|

|

|


|

|


|

|


|

|

|

|


|

|







|

|

|

|

|

|

|

|

|

|

|

|

|




|

|

|



|



















|









|

|

|

|

|







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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
give users of the core the freedom to experiment with their own ideas, instead
of constraining them to what we managed to envision.

Another use for reflected channels was found when creating the reference
implementation: As helper for testing the generic I/O system of Tcl, by
creating channels which forcibly return errors, bogus data, and the like.

# Specification

## Introduction

This specification has to address two questions to make the reflection work.

 * How are the driver functions reflected into the Tcl level?

 * How are file events generated in the Tcl level communicated back to the C
   level? This includes routing to the correct channel.

## C Level API

Four functions are added to the public C API. See section "_Error Handling_"
for their detailed specification.

## Tcl Level API

The Tcl Level API consists of two new subcommands added to the ensemble
command **chan** specified by [[208]](208.md). The new subcommands are:

 * **chan create** _mode cmdprefix_

	 > This subcommand creates a new script level channel using the command prefix
   _cmdprefix_ as its handler. The _cmdprefix_ has to be a list. The API
   this handler has to provide is specified below, in the section "Command
   Handler API". The handle of the new channel is returned as the result of
   the command, and the channel is open. Use the regular **close** command
   to remove the channel.

	 > The argument _mode_ specifies if the channel is opened for reading,
   writing, or both. It is a list containing any of the strings **read** or
   **write**. The list has to have at least one element, as a channel you
   can neither write to nor read from makes no sense. The handler command for
   the new channel has to support the chosen mode. An error is thrown if that
   is not the case.

	 > We have chosen to use _late binding_ of the handler command. See the
   section "_Early versus Late Binding of the Handler Command_" for more
   detailed explanations.

 * **chan postevent** _channel eventspec_

	 > This subcommand is for use by command handlers, it notifies the channel
   represented by _channel_ that the event\(s\) listed in the _eventspec_
   have occurred. The argument _eventspec_ is a list containing any of
   **read** and **write**. At least one element is required \(It does not
   make sense to invoke the command if there are no events to post\).

	 > Note that this subcommand can be used only on channel handles which were
   created/opened with the subcommand **create**. Application to channels
   like files, sockets, etc. is not possible and will cause the generation of
   an error.

	 > As only the Tcl level of a channel, i.e. its command handler, should post
   events to it we also restrict the usage of this command to the interpreter
   the handler command is in. In other words, posting events to a reflected
   channel from a different interpreter than its implementation is in is not
   allowed.

	 > Another restriction is that it is not possible to post events the I/O core
   has not registered interest in. Trying to do so will cause the method to
   throw an error. See the method **watch** in section "Command Handler API"
   as well.

## Command Handler API

The Tcl-level handler command for a reflected channel is an ensemble that has
to support the following subcommands, as listed below. Note that the term
_ensemble_ is used to generically describe all command \(prefixes\) which are
able to process subcommands. This TIP is _not_ tied to the recently
introduced 'namespace ensemble's.

Of the available methods the handler **has to** support **initialize**,
**finalize**, and **watch**, always. The other methods are optional.

 * _handlerCmd_ **initialize** _channel mode_

	 > This is the first call the command handler will receive for the given new
   _channel_. It is his responsibility to set up any internal data
   structures it needs to keep track of the channel and its state.

	 > The return value of the method has to be a list containing the names of all
   methods which are supported by this handler. This implicitly tells the C
   level the version of the API used by the command handler making a separate
   version number redundant. Hence our decision to leave such a number out of
   the API. Any changes to the API will be either the elimination of methods,
   or the introduction of new ones. An existing method cannot change its
   signature \(arguments, and result\), a new method has to be introduced for
   this. All of this implies that this method, **initialize**, **is
   unchangeable** after the TIP has been committed, as it is the entry point
   through which the C level will determine the API version before it knows
   anything else.

	 > Any error thrown by the method will abort the creation of the channel and
   no channel will be created. The thrown error will appear as error thrown by
   **chan create**.

	 > Any exception beyond _error_, like _break_, etc. is treated as and
   converted to an error.

	 > **Important** - If the creation of the channel was aborted due to
   failures in **initialize** then the method **finalize** will _not_ be
   called.

	 > This method has no equivalent at the C level.

	 > It was considered to return only the list of optional methods supported by
   the handler. The chosen method however should make the code in the C layer
   more regular. Another advantage of this is that it allows the C level to
   better check if the API it expects is matching the API provided by the
   handler.

	 > The argument _mode_ tells the handler if the channel was opened for
   reading, writing, or both. It is a list containing any of the strings
   **read** or **write**. The C-level doing the call will never generate
   abbreviations of these strings. The list will always contain at least one
   element, as a channel you can neither write to nor read from makes no
   sense.

	 > The method has to throw an error if the chosen mode is not supported by the
   handler command.

 * _handlerCmd_ **finalize** _channel_

	 > The method is called when the channel was **close**d, and is the last
   call a handler can receive for the given _channel_. This happens just
   before the destruction of the C level data structures. Still, the command
   handler must not access the channel anymore in no way. It is now his
   responsibility to clean up any internal resources it allocated to this
   channel.

	 > The return value of the method is ignored.

	 > If the method throws an error the command which caused its invocation
   \(usually **close**\) will appear to have thrown this error.

	 > Any exception beyond _error_, like _break_, etc. is treated as and
   converted to an error.

	 > The equivalent C-level function is _Tcl\_DriverCloseProc_.

	 > This method is not invoked if the creation of the channel was aborted
   during **initialize**.

 * _handlerCmd_ **read** _channel count_

	 > This method is _optional_. It is called when the user requests data from
   a channel. _count_ specifies how many _bytes_ have been requested. If
   the method is not supported then it is not possible to read from the
   channel handled by the command.

	 > The return value of the method is taken as the requested data. If the
   returned data contains more bytes than requested an error will be signaled
   and later thrown by the command which performed the read \(usually
   **gets** or **read**\). Returning less bytes than requested is
   acceptable however.

	 > If the method throws an error the command which caused its invocation
   \(usually **gets**, or **read**\) will appear to have thrown this error.

	 > Any exception beyond _error_, like _break_, etc. is treated as and
   converted to an error.

	 > The equivalent C-level function is _Tcl\_DriverInputProc_.

 * _handlerCmd_ **write** _channel data_

	 > This method is _optional_. It is called when the user writes data to the
   channel. Note that the _data_ are bytes, not characters \(The underlying
   Tcl\_ObjType is _ByteArray_\). Any type of transformation \(EOL, encoding\)
   configured for the channel has already been applied at this point. If the
   method is not supported then it is not possible to write to the channel
   handled by the command.

	 > The return value of the method is taken as the number of bytes written by
   the channel. Anything non-numeric will cause an error to be signaled and
   later thrown by the command which performed the write. A negative value
   implies that the write failed. Returning a value greater than the number of
   bytes given to the handler, or zero, is forbidden and will cause the C
   level to throw errors.

	 > If the method throws an error the command which caused its invocation
   \(usually **puts**\) will appear to have thrown this error.

	 > Any exception beyond _error_, like _break_, etc. is treated as and
   converted to an error.

	 > The equivalent C-level function is _Tcl\_DriverOutputProc_.

 * _handlerCmd_ **seek** _channel offset base_

	 > This method is _optional_. It is responsible for the handling of seek and
   tell requests on the channel. If it is not supported then seeking will not
   be possible for the channel.

	 > _base_ is one of

	 > \* **start** - Seeking is relative to the beginning of the channel.

	 > \* **current** - Seeking is relative to the current seek position.

	 > \* **end** - Seeking is relative to the end of the channel.

	 > The base argument of the builtin **seek** command takes the same names.

	 > The _offset_ is an integer number specifying the amount of _bytes_ to
   seek forward or backward. A positive number will seek forward, and a
   negative number will seek backward.

	 > A channel may provide only limited seeking. For example sockets can seek
   forward, but not backward.

	 > The return value of the method is taken as the \(new\) location of the
   channel, counted from the start. This has to be an integer number greater
   than or equal to zero.

	 > If the method throws an error the command which caused its invocation
   \(usually **seek**\) will appear to have thrown this error.

	 > Any exception beyond _error_, like _break_, etc. is treated as and
   converted to an error.

	 > The offset/base combination of 0/"current" signals a **tell** request,
   i.e. seek nothing relative to the current location, making the new location
   identical to the current one, which is then returned.

	 > The equivalent C-level functions are _Tcl\_DriverSeekProc_, and
   _Tcl\_DriverWideSeekProc_ \(where possible\).

 * _handlerCmd_ **configure** _channel option value_

	 > This method is _optional_. It is for writing the type specific options.

	 > Per call one option has to be written.

	 > The return value of the method is ignored.

	 > If the method throws an error the command which performed the
   \(re\)configuration or query \(usually **fconfigure**\) will appear to have
   thrown this error.

	 > Any exception beyond _error_, like _break_, etc. is treated as and
   converted to an error.

	 > The equivalent C-level function is _Tcl\_DriverSetOptionProc_.

 * _handlerCmd_ **cget** _channel option_

	 > This method is _optional_. It is used when reading a single type specific
   option. If this method is supported then the method **cgetall** has to be
   supported as well.

	 > The call has to return the value of the specified option.

	 > If the method throws an error the command which performed the
   \(re\)configuration or query \(usually **fconfigure**\) will appear to have
   thrown this error.

	 > The equivalent C-level function is _Tcl\_DriverGetOptionProc_.

 * _handlerCmd_ **cgetall** _channel_

	 > This method is _optional_. It is used for reading all type specific
   options. If this method is supported then the method **cget** has to be
   supported as well.

	 > It has to return a list of all options and their values. This list has to
   have an even number of elements.

	 > If the method throws an error the command which performed the
   \(re\)configuration or query \(usually **fconfigure**\) will appear to have
   thrown this error.

	 > Any exception beyond _error_, like _break_, etc. is treated as and
   converted to an error.

	 > The equivalent C-level function is _Tcl\_DriverGetOptionProc_.

 * _handlerCmd_ **watch** _channel eventspec_

	 > This methods notifies the Tcl level that the specified channel is
   interesting in the events listed in the _eventspec_. This is a list
   containing any of **read** and **write**. The C-level doing the call
   will never generate abbreviations of these strings. The empty list is
   allowed as well and signals that the channel does not wish to be notified
   of any events. In other words, it has to disable event generation at the
   Tcl level.

	 > Any return value of the method is ignored. This includes errors thrown by
   the method, break, continue, and custom return codes.

	 > The equivalent C-level function is _Tcl\_DriverWatchProc_.

	 > This method interacts with **chan postevent**. Trying to post an event
   not listed in the last call to this method will cause an error.

 * _handlerCmd_ **blocking** _channel mode_

	 > This method is _optional_. It handles changes to the blocking mode of the
   channel. The _mode_ is a boolean flag. True means that the channel has to
   be set to blocking. False means that the channel should be non-blocking.

	 > The return value of the method is ignored.

	 > If the method throws an error the command which caused its invocation
   \(usually **fconfigure**\) will appear to have thrown this error.

	 > Any exception beyond _error_, like _break_, etc. is treated as and
   converted to an error.

	 > The equivalent C-level function is _Tcl\_DriverBlockModeProc_.

Notes:

 * The function _Tcl\_DriverGetHandleProc_ is not supported. There is no
   equivalent handler method at the Tcl level.

 * The function _Tcl\_DriverHandlerProc_ is not supported. There is no
   equivalent handler method at the Tcl level. The function has no relevance
   to base channels, which we work with here, only for channel
   transformations. See [[230]](230.md) \('Tcl Channel Transformation Reflection API'\)
   for more information on the issue.

 * The function _Tcl\_DriverFlushProc_ is not supported. The reason for this:
   The current generic I/O layer of Tcl does not use this function at all,
   nowhere. Therefore support at the Tcl level makes no sense either. We can
   always extend the API defined here \(and change its version number\) should
   the function be used at some time in the future.

## Error handling

The current I/O core's ability to handle arbitrary Tcl error messages is very
limited. _Tcl\_DriverGetOptionProc_ and _Tcl\_DriverSetOptionProc_ are the
only driver functions for which this is possible directly. Everywhere else the
API is restricted to returning POSIX error codes.

This limitation makes the debugging of problems in a channel command handler
at least very difficult. As such it is considered not acceptable. It is
proposed to solve this problem through the addition of four new functions to
Tcl's public stub table.

 > void **Tcl\_SetChannelError**\(Tcl\_Channel _chan_, Tcl\_Obj\* _msg_\)

 > void **Tcl\_SetChannelErrorInterp**\(Tcl\_Interp\* _ip_, Tcl\_Obj\* _msg_\)

 > > These functions store error information in a channel or interpreter.
     Previously stored information will be discarded. They have to be used by
     channel drivers wishing to pass regular Tcl error information to the
     generic layer of the I/O core.

 > > The refCount of _msg_ is unchanged when the functions had to rewrite
     _msg_ per the safety precautions explained below, as a properly
     modified copy of _msg_ is stored, and not _msg_ itself. Otherwise the
     refCount of _msg_ is incremented by one.

 > void **Tcl\_GetChannelError**\(Tcl\_Channel _chan_, Tcl\_Obj\*\* _msg_\)

 > void **Tcl\_GetChannelErrorInterp**\(Tcl\_Interp\* _ip_, Tcl\_Obj\*\* _msg_\)

 > > These function retrieve error information stored in a channel or
     interpreter O, and also resets O to have no information stored in
     it. They will return NULL if no information was stored to begin with.

 > > i.e. After an invocation of **Tcl\_GetChannelError\*** for a
     channel/interpreter object O, all following invocations will return NULL
     for that object, until an intervening invocation of
     **Tcl\_SetChannelError\*** again stored information in O.

 > > The _msg_ argument is not allowed to be NULL. Nor are the _chan_ and
     _ip_ arguments.

 > > The refCount of the returned information is not touched. The reference
     previously held by the channel or interpreter is now held by the caller
     of the function and it is its responsibility to release that reference
     when it is done with the object.

This solution is not very elegant, but anything else will require an
incompatible redefinition of the whole channel driver structure and of the
driver functions.

It should also be noted that usage of **Tcl\_Obj**ects for the information
storage binds the information to a single thread. I.e. a transfer across
thread boundaries is not possible. This however is not required here and thus
no limitation.

The four functions have been made public as I can imagine that even C level
drivers might wish to use this facility to generate more explicit and readable
error messages than is provided through POSIX error codes and the errno API.

The information talked about in the API specifications above is **not** a
plain string, but has to be a list of uneven length. The last element will be
interpreted as the actual error message in question, and the preceding
elements are considered as option/value pairs containing additional
information about the error, like the _errorCode_, etc. I.e. they are an
extensible dictionary containing the details of the error beyond the basic
message.

As a **safety precaution** any _-level_ specification submitted by the
driver and a non-zero value will be rewritten to a value of _0_ to prevent
the driver from being able to force the user application into the execution of
arbitrary multi-level returns, i.e. from arbitrarily changing the control-flow
of the application itself. Analogously any _-code_ specification with a
non-zero value which is not _error_ is rewritten to value _1_
\(i.e. _error_\).

Below a list of driver functions, and which of the _Tcl\_SetChannelError\***
functions they are allowed to use.

 * **Tcl\_DriverCloseProc**

	 > May use _Tcl\_SetChannelErrorInterp_, and only this function.

 * **Tcl\_DriverInputProc**

	 > May use _Tcl\_SetChannelError_, and only this function.

 * **Tcl\_DriverOutputProc**

	 > May use _Tcl\_SetChannelError_, and only this function.

 * **Tcl\_DriverSeekProc**, and **Tcl\_DriverWideSeekProc**

	 > May use _Tcl\_SetChannelError_, and only this function.

 * **Tcl\_DriverSetOptionProc**

	 > Has already the ability to pass arbitrary error messages. Must **not**
   use any of the new functions.

 * **Tcl\_DriverGetOptionProc**

	 > Has already the ability to pass arbitrary error messages. Must **not**
   use any of the new functions.

 * **Tcl\_DriverWatchProc**

	 > Must **not** use any of the new functions. Is internally called and has
   no ability to return any type of error whatsoever.

 * **Tcl\_DriverBlockModeProc**

	 > May use _Tcl\_SetChannelError_, and only this function.

 * **Tcl\_DriverGetHandleProc**

	 > Must **not** use any of the new functions. It is only a low-level
   function, and not used by Tcl commands.

 * **Tcl\_DriverHandlerProc**

	 > Must **not** use any of the new functions. Is internally called and has
   no ability to return any type of error whatsoever.

Given the information above the following public functions of the Tcl C API
are affected by these changes. I.e. when these functions are called the
channel may now contain a stored arbitrary error message requiring processing
by the caller.

 * **Tcl\_StackChannel**

 * **Tcl\_Seek**

 * **Tcl\_Tell**

 * **Tcl\_ReadRaw**

 * **Tcl\_Read**

 * **Tcl\_ReadChars**

 * **Tcl\_Gets**

 * **Tcl\_GetsObj**

 * **Tcl\_Flush**

 * **Tcl\_WriteRaw**

 * **Tcl\_WriteObj**

 * **Tcl\_Write**

 * **Tcl\_WriteChars**

All other API functions are unchanged. Especially the functions below leave
all their error information in the interpreter result.

 * **Tcl\_Close**

 * **Tcl\_UnregisterChannel**

 * **Tcl\_UnstackChannel**

A previous revision of this TIP specified only two functions, storing the data
only in channels. This however proved to be inadequate. It allows the transfer
of messages for most driver functions, but not _close_. Storing an error
message in the channel structure which is destroyed is not helpful. So we need
the functions for storing data in interpreters. Conversely, providing only two
functions storing the information in an interpreter, is inadequate as well.
The circumstances for that to happen are actually very limited, but they can
happen. First, most driver functions are not given an interpreter reference
when called, and actually do not know which interpreter caused their
invocation. The only remedy we have is that the channel structure has to have
an interpreter reference to the interpreter of the command handler, for the
calls into the Tcl level. This could be used in most circumstances, except
when threads are enabled and the channel was transfered out of the thread
containing that interpreter. We are not allowed to use this interpreter from
the channel thread, and again have no other reference available. So for this
the code/message pair has to be stored in a channel as the sole place
available.

A previous revision of this TIP not only stored an error message, but also a
result code in the channel or interpreter, and used it as the return code of
the Tcl command which invoked the driver function returning the exception.
This feature has been discarded as a possible security hazard. It would allow
a malicious Tcl driver to cause _break_ and _continue_ exceptions at
arbitrary locations in the overall application, controlling its behaviour as
it sees fit.

I wish to thank Joe English and Vince Darley for their input with regard to
the limitations of error propagation in the I/O core and possible ideas for
solving it. Joe's discourse on the problems with the use of POSIX error codes
in an earlier revision of this TIP made me realize that I should not use them
anywhere in the API for reflected channels and rather concentrate on extending
the I/O system to properly receive Tcl error messages. And while I rejected
the **TclSetPosixError** function Vince proposed I hopefully kept the spirit
of that proposal in my solution as well. The main reason against setting an
arbitrary _posix error string_ was that it invented another way of passing
error information around, whereas the specification above is based on the
existing Tcl\_InterpState and attendant functionality.

## Interaction with Threads and Other Interpreters.

A channel created with the **chan create** command knows the interpreter it
was created in and executes its handler command only in that interpreter, even
if the channel is shared with and/or has been moved into a different
interpreter. This is easy to accomplish, by evaluating the handler command
only in the context of the original interpreter.

The channel also knows the thread it was created in and executes its handler
command only in that thread, even if the channel has been moved into a
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701

702
703
704
705
706
707

708
709
710
711
712
713
714
715
716
717

718
719
720
721
722
723
724
725

726
727
728
729
730

731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777

   original thread, able to process these events.

Note that this also allows the creation of a channel whose two endpoints live
in two different threads and provide a stream-oriented bridge between these
threads. In other words we can provide a way for regular stream communication
between threads instead of having to send commands.

When a thread or interpreter is deleted all channels created with the '''chan
create''' command using this thread/interpreter as their computing base will
be deleted as well, in all interpreters they have been shared with or moved
into, and in whatever thread they have been moved to. This pulls the rug out
under the other thread(s) and/or interpreter(s), this however cannot be
avoided. Trying to use such a channel will cause the generation of the regular
error about unknown channel handles.

~~ Interaction with Safe Interpreters

The new subcommands '''create''' and '''postevent''' of '''chan''' are safe
and therefore made accessible to safe interpreters.

While '''create''' arranges for the execution of code this code is always
executed within the safe interpreter, even if the channel was moved (See
previous section).

The subcommand '''postevent''' can trigger the execution of fileevent
handlers, however if they are executed in trusted interpreters then they were
registered by these interpreters as well. (Moving channels between threads
strips fileevent handlers, and just between interpreters keeps them, and
executes them where they were added).

~~ Early versus Late Binding of the Handler Command

We have two principal methods for using the handler command. These are called
early and late binding.

Early binding means that the command implementation to use is determined at
the time of the creation of the channel, i.e. when '''chan create''' is
executed, before any methods are called. Afterward it cannot change. The
result of the command resolution is stored internally and used until the
channel is destroyed. Renaming the handler command has no effect. In other
words, the system will automatically call the command under the new name. The
destruction of the handler command is intercepted and causes the channel to
close as well.

Late binding means that the handler command is stored internally essentially
as a string, and this string is mapped to the implementation to use for each
and every call to a method of the handler. Renaming the command, or destroying
it means that the next call of a handler method will fail, causing the higher
level channel command to fail as well. Depending on the method the error
message may not be able to explain the reason of that failure.

Another problem with this approach is that the context for the resolution of
the command name has to be specified explicitly to avoid problems with
relative names. Early binding resolves once, in the context of the '''chan
create''' call. Late binding performs resolution anywhere where channel
commands like '''puts''', '''gets''', etc. are called, i.e. in a random
context. To prevent problems with different commands of the same name in
several namespaces it becomes necessary to force the usage of a specific fixed
context for the resolution. The only context suitable for such is the global
context (per ''uplevel #0'', not ''namespace eval ::'').

Note that moving a different command into place after renaming the original
handler allows the Tcl level to change the implementation dynamically at
runtime. This however is not really an advantage over early binding as the
early bound command can be written such that it delegates to the actual
implementation, and that can then be changed dynamically as well.

However, despite all this late binding is so far the method of choice for the
implementation of callbacks, be they in Tcl, or Tk; and has been chosen for
the reflection as well.

~~ Miscellanea

The channel reflection API reserves the driver type "tclrchannel" for itself.
Usage of this driver type by other channel types is not allowed.

~ Examples

~~ Driver Implementations

A simple way of implementing new types of channels is to use any of the
various object systems for Tcl. Create a class for the channel type. Create
the new channel in the constructor for new objects and store the channel
handle. Make the new object the command handler for the channel. This
automatically translates the sub commands for the command handler into object
methods. Implement the various methods required. when the object is deleted
close the channel, and delete the object when the channel announces that it
has been '''close'''d. This part is a bit tricky, flags have to be used to
break the potential cycle.

Another possibility is to implement the command handler as a regular command,
together with a creation command wrapping around '''chan create''' and a
backend which keeps track of all handles created by it and their state,
associated data, etc.

| object based example ...
|
|  snit::type new_channel {
|      constructor {mode args} {
|          # Handle args ...
|          set chan [chan create $mode $self]
|      }

|      destructor {
|          # ... delete internal state ...
|          if {$dead} return
|          set dead 1
|          close $chan
|      }

|
|      method handle {} {return $chan}
|      variable chan
|      variable dead 0
|
|      method finalize {dummy} {
|          if {$dead} return
|          set dead 1
|          $self destroy
|      }

|      method initialize {dummy mode} {}
|      method read       {dummy count} {}
|      method write      {dummy data} {}
|      method seek       {dummy offset base} {}
|      method configure  {dummy args} {}
|      method watch      {dummy events} {}
|      method blocking   {dummy isblocking} {}
|  }

|
|  proc newchannel_open {args} {
|      return [[new_channel %AUTO% {expand}$args] handle]
|  }


~~ Other Possible Drivers

 * Memory channel based on a string. Block and/or FIFO oriented.

 * Null device. Writable, not writable. WOM device. Data sink.

 * Random data (Writing to it may re-seed the PRNG).

 * Zero channel. Readable, returns a stream of binary 0s. Not writable.

 * FIFO channel between different threads.

 * Optimized virtual filesystem implementations.

 > Current VFS implementations have to use the package ''memchan'' to provide
   the channels when a file in them is opened, which necessitates that for all
   open files all of their data is in memory, possibly even more than once
   (when several channels are open on the same file). A reflected driver
   however allows implementations which keep only part of the data in
   memory. Or nearly none at all if the VFS provides computed information / is
   based on some data structure.

 > A more concrete example would be a driver which provides access to files
   stored in some archive file. Using a reflect driver the archive file can be
   memory mapped and the driver will then read whatever data is needed when
   requested. Currently it will have to copy the data into a ''memchan''
   channel, i.e duplicate it in memory.

 > Note that of course the internals of the archive file may limit the amount
   of memory savings we can achieve. If for example the file we wish to access
   is stored in a compressed form we will have to decompress it in memory at
   least to the highest location requested so far. And any write operation (if
   allowed) will have to keep the data in memory until it has been compressed
   and committed.

~ Reference Implementation

A reference implementation is provided at SourceForge
[http://sourceforge.net/support/tracker.php?aid=1025294].

~ Comments

''[[ Add comments on the document here ]]''

~ Copyright

This document has been placed in the public domain.








|
|


|



|

|


|
|
|

|

|

|

|





|
















|
|
|



|











|




|

|








|



|



|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
<
|
>
|





|







|


|




|


|


|


|
|


|


|

|

|

|


>
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699

700
701
702
703
704
705

706
707
708
709
710
711
712
713
714
715

716
717
718
719
720
721
722
723

724
725
726
727

728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
   original thread, able to process these events.

Note that this also allows the creation of a channel whose two endpoints live
in two different threads and provide a stream-oriented bridge between these
threads. In other words we can provide a way for regular stream communication
between threads instead of having to send commands.

When a thread or interpreter is deleted all channels created with the **chan
create** command using this thread/interpreter as their computing base will
be deleted as well, in all interpreters they have been shared with or moved
into, and in whatever thread they have been moved to. This pulls the rug out
under the other thread\(s\) and/or interpreter\(s\), this however cannot be
avoided. Trying to use such a channel will cause the generation of the regular
error about unknown channel handles.

## Interaction with Safe Interpreters

The new subcommands **create** and **postevent** of **chan** are safe
and therefore made accessible to safe interpreters.

While **create** arranges for the execution of code this code is always
executed within the safe interpreter, even if the channel was moved \(See
previous section\).

The subcommand **postevent** can trigger the execution of fileevent
handlers, however if they are executed in trusted interpreters then they were
registered by these interpreters as well. \(Moving channels between threads
strips fileevent handlers, and just between interpreters keeps them, and
executes them where they were added\).

## Early versus Late Binding of the Handler Command

We have two principal methods for using the handler command. These are called
early and late binding.

Early binding means that the command implementation to use is determined at
the time of the creation of the channel, i.e. when **chan create** is
executed, before any methods are called. Afterward it cannot change. The
result of the command resolution is stored internally and used until the
channel is destroyed. Renaming the handler command has no effect. In other
words, the system will automatically call the command under the new name. The
destruction of the handler command is intercepted and causes the channel to
close as well.

Late binding means that the handler command is stored internally essentially
as a string, and this string is mapped to the implementation to use for each
and every call to a method of the handler. Renaming the command, or destroying
it means that the next call of a handler method will fail, causing the higher
level channel command to fail as well. Depending on the method the error
message may not be able to explain the reason of that failure.

Another problem with this approach is that the context for the resolution of
the command name has to be specified explicitly to avoid problems with
relative names. Early binding resolves once, in the context of the **chan
create** call. Late binding performs resolution anywhere where channel
commands like **puts**, **gets**, etc. are called, i.e. in a random
context. To prevent problems with different commands of the same name in
several namespaces it becomes necessary to force the usage of a specific fixed
context for the resolution. The only context suitable for such is the global
context \(per _uplevel \#0_, not _namespace eval ::_\).

Note that moving a different command into place after renaming the original
handler allows the Tcl level to change the implementation dynamically at
runtime. This however is not really an advantage over early binding as the
early bound command can be written such that it delegates to the actual
implementation, and that can then be changed dynamically as well.

However, despite all this late binding is so far the method of choice for the
implementation of callbacks, be they in Tcl, or Tk; and has been chosen for
the reflection as well.

## Miscellanea

The channel reflection API reserves the driver type "tclrchannel" for itself.
Usage of this driver type by other channel types is not allowed.

# Examples

## Driver Implementations

A simple way of implementing new types of channels is to use any of the
various object systems for Tcl. Create a class for the channel type. Create
the new channel in the constructor for new objects and store the channel
handle. Make the new object the command handler for the channel. This
automatically translates the sub commands for the command handler into object
methods. Implement the various methods required. when the object is deleted
close the channel, and delete the object when the channel announces that it
has been **close**d. This part is a bit tricky, flags have to be used to
break the potential cycle.

Another possibility is to implement the command handler as a regular command,
together with a creation command wrapping around **chan create** and a
backend which keeps track of all handles created by it and their state,
associated data, etc.

	 object based example ...
	
	  snit::type new_channel {
	      constructor {mode args} {
	          # Handle args ...
	          set chan [chan create $mode $self]

	      }
	      destructor {
	          # ... delete internal state ...
	          if {$dead} return
	          set dead 1
	          close $chan

	      }
	
	      method handle {} {return $chan}
	      variable chan
	      variable dead 0
	
	      method finalize {dummy} {
	          if {$dead} return
	          set dead 1
	          $self destroy

	      }
	      method initialize {dummy mode} {}
	      method read       {dummy count} {}
	      method write      {dummy data} {}
	      method seek       {dummy offset base} {}
	      method configure  {dummy args} {}
	      method watch      {dummy events} {}
	      method blocking   {dummy isblocking} {}

	  }
	
	  proc newchannel_open {args} {
	      return [[new_channel %AUTO% {expand}$args] handle]

	  }

## Other Possible Drivers

 * Memory channel based on a string. Block and/or FIFO oriented.

 * Null device. Writable, not writable. WOM device. Data sink.

 * Random data \(Writing to it may re-seed the PRNG\).

 * Zero channel. Readable, returns a stream of binary 0s. Not writable.

 * FIFO channel between different threads.

 * Optimized virtual filesystem implementations.

	 > Current VFS implementations have to use the package _memchan_ to provide
   the channels when a file in them is opened, which necessitates that for all
   open files all of their data is in memory, possibly even more than once
   \(when several channels are open on the same file\). A reflected driver
   however allows implementations which keep only part of the data in
   memory. Or nearly none at all if the VFS provides computed information / is
   based on some data structure.

	 > A more concrete example would be a driver which provides access to files
   stored in some archive file. Using a reflect driver the archive file can be
   memory mapped and the driver will then read whatever data is needed when
   requested. Currently it will have to copy the data into a _memchan_
   channel, i.e duplicate it in memory.

	 > Note that of course the internals of the archive file may limit the amount
   of memory savings we can achieve. If for example the file we wish to access
   is stored in a compressed form we will have to decompress it in memory at
   least to the highest location requested so far. And any write operation \(if
   allowed\) will have to keep the data in memory until it has been compressed
   and committed.

# Reference Implementation

A reference implementation is provided at SourceForge
<http://sourceforge.net/support/tracker.php?aid=1025294> .

# Comments

_[ Add comments on the document here ]_

# Copyright

This document has been placed in the public domain.

Name change from tip/22.tip to tip/22.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342

TIP:            22
Title:          Multiple Index Arguments to lindex
Version:        $Revision: 1.22 $
Author:         David Cuthbert <[email protected]>
Author:         Kevin Kenny <[email protected]>
Author:         Don Porter <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        19-Jan-2001
Post-History:   
Discussions-To: news:comp.lang.tcl,mailto:[email protected]
Keywords:       lindex,multiple arguments,sublists
Tcl-Version:    8.4a2


~ Abstract

Obtaining access to elements of sublists in Tcl often requires nested
calls to the ''lindex'' command.  The indices are syntactically listed
in most-nested to least-nested order, which is the reverse from other
notations.  In addition, the nesting of command substitution brackets
further decreases readability.  This proposal describes an extension
to the ''lindex'' command that allows it to accept multiple index
arguments, in least-nested to most-nested order, to automatically
extract elements of sublists.

~ Rationale

The heterogeneous nature of Tcl lists allows them to be applied to a
number of useful data structures.  In particular, lists can contain
elements that are, themselves, valid lists.  In this document, these
elements are referred to as ''sublists.''

Extracting elements from sublists often requires nested calls to
''lindex.''  Consider, for example, the following Tcl script that
prints the center element of a 3-by-3 matrix:

|    set A {{1 2 3} {4 5 6} {7 8 9}}
|    puts [lindex [lindex $A 2] 2]

When these calls are deeply nested - e.g., embedded in an ''expr''
arithmetic expression, having results extracted through ''lrange,''
etc. - the results are difficult to read:

|# Print the sum of the center indices of two 3x3 matrices
|set p [expr {[lindex [lindex $A 2] 2] + [lindex [lindex $A 2] 2]}]
|
|# Get all but the last font in the following parsed structure:
|set pstruct {text {ignored-data
|                      { ... }
|		       }

|		       {valid-styles
|			   {justifiction {left centered right full}}
|			   {font {courier helvetica times}}
|		       }
|		 }


|return [lrange [lindex [lindex [lindex $pstruct 1] 2] 2] 0 end-1]

Note that the list of indices in the latter example is listed in the
reverse order of vector indices.  In most other languages/domains, the
last line might take on one of the following forms:

|return list_range(pstruct[2][2][1], 0, end-1);
|
|return pstruct[[2, 2, 1]][[0:-1]]
|
|temp = pstruct(2, 2, 1);
|result = range(temp, 0, length(temp) - 1);

Allowing the ''lindex'' command to accept multiple arguments would
allow this more-natural style of coding to be written in Tcl.

~ Specification

 1. Under this proposal, the syntax for the ''lindex'' command is to be
    modified to accept one of two forms:

|     lindex list indexList

    or

|     lindex list index1 index2...

    > In either form of the command, the ''list'' parameter is
      expected to be a well-formed Tcl list.

    > In the first form of the command, the ''indexList'' argument is
      expected to be a Tcl list comprising one or more list indices,
      each of which must be an integer, the literal string ''end'', or
      the literal string ''end-'' followed by an integer with no
      intervening whitespace.  The existing ''lindex'' command is a
      degenerate form of this first form, where the list comprises a
      single index.

    > In the second form of the command, each of the ''index''
      arguments is expected to be a list index, which again may be an
      integer, the literal string ''end'', or the literal string
      ''end-'' followed by an integer with no intervening whitespace.

 2. In either form of the command, once the ''indexList'' parameter
    is expanded, there is a single ''list'' parameter and one or
    more ''index'' parameters.  If there is a single ''index''
    parameter ''N'', the behavior is identical to today's ''lindex''
    command, and the command returns the ''N''th element of
    ''list''; if ''N'' is less than zero or at least the length of
    the list, a null string is returned.

 3. If more than one ''index'' parameter is given, then the behavior is
    defined recursively; the result of

|   lindex $list $index0 $index1 ...

  > or

|   lindex $list [list $index0 $index1 ...]

  > is indentical to that of

|   lindex [lindex $list $index0] $index1...

  > or, equivalently,

|   lindex [lindex $list $index0] [list $index1...]

  > (This specification does not constrain the implementation, which
    may be iterative, recursive, or even expanded inline.)

 4. When an invalid index is given, an error of the form, ''bad index
    "invalid_index": must be integer or end?-integer?'', where
    ''invalid_index'' is the first invalid index encountered, must be
    returned.

 5. If the list argument is malformed, the error resulting from an
    attempt to convert the list argument to a list must be returned.
    This behaviour is unchanged from the current implementation.

~ Side Effects

 1. Whether the result of the ''lindex'' operation is successful, the
    underlying Tcl_Obj that represents the list argument may have its
    internal representation invalidated or changed to that of a list.

~ Discussion

Some attention must be paid to giving the ''lindex'' command adequate
performance.  In particular, the implementation should address the
common case of

|    lindex $list $i

where ''$i'' is a "pure" integer (that is, one whose string
representation has not yet been formed).  If the above specification
is followed naively, the flow will be as follows.

Since ''objc'' is three, ''objv[[2]]'' is expected to be a list.
Since it is not, it must be converted from its string representation.
It does not have one yet, so the string representation must be formed.
Now the string representation is parsed as a list.  An array (of
length one) of Tcl_Obj pointers is allocated to hold the list in
question, and a Tcl_Obj is allocated to hold the single element.
Memory is allocated to hold the element's string representation.
Now the ''lindex'' command converts the first element of the list to
an index (in this case an integer).

This elaborate ballet of type shimmering requires converting the
integer to a string and back again.  It also requires four calls to
''ckalloc:''

 1. Allocate a buffer for the string representation.

 2. Allocate the array of Tcl_Obj pointers for the list
    representation.

 3. Allocate the Tcl_Obj that represents the first (and only) element
    of the list.

 4. Allocate a buffer for the string representation of that element.

And at the end, the result is the same integer that was passed as a
parameter originally.

To avoid all this overhead in the common case, the proposed
implementation shall (in the case where ''objc==3'')

 1. Test whether ''objv[[2]]'' designates an object whose internal
    representation holds an integer.  If so, simply use it as an
    index.

 2. Test whether ''objv[[2]]'' designates an object whose internal
    representation holds a list.  If so, perform the recursive
    extraction of indexed elements from sublists described above.

 3. Form the string representation of ''objv[[2]]'' and test whether
    it is ''end'' or ''end-'' followed by an integer.  If so, use it
    as an index.

 4. Attempt to coerce ''objv[[2]]'' to an integer; if successful, use
    the result as an integer.

 5. Attempt to coerce ''objv[[2]]'' to a list; if successful, use the
    result as an index list.

 6. Report a malformed ''index'' argument; the ''indexList'' parameter
    is not a well-formed list.

This logic handles all the cases of singleton lists transparently; it
is effectively a simple-minded type inference that optimizes away
needless conversions.

Assuming that the related [33] is approved, this logic will most
likely be combined with the identical logic required in that proposal
for parsing ''index'' arguments to the ''lset'' command.

----

~ Comments

''Don Porter <[email protected]>''

 > I agree that it would be helpful to many programmers to
   provide a multi-dimensional array data structure that can
   be accessed in the manner described in this TIP.  In the
   ''struct'' module of ''tcllib'', several other data structures
   are being developed: graph, tree, queue, stack.  I would support
   adding another data structure to that module that provides an
   interface like the one described in this TIP, with the intent that
   all of these helpful data structures find their way into the
   BI distribution.

 > I don't see any advantage to adding complexity to [[lindex]]
   as an alternative to development of a multi-dimensional array
   structure.  Without a compelling advantage, I'm inclined against
   making [[lindex]] more complex.  I like having Tcl's built-in
   commands provide primitive operations, and leave it to
   packages to combine the primitives into more useful, more
   complex resources.

 > This TIP should also consider how any changes to [[lindex]] mesh
   with the whole [[listx]] overhaul of Tcl's [[list]] command that
   has been discussed.

''Dave Cuthbert <[email protected]> responds''

 > Don makes a good point -- with a good set of data structures in
   tcllib, the need for this TIP is lessened or even eliminated.
   Nonetheless, I see this as a way of implementing the structures he
   describes.  In other words, a more powerful primitive (which, in
   reality, adds fairly little complexity when measured in number of
   lines of code changed) would benefit these structures.

 > As for the [[listx]] overhaul, there are many competing proposals
   for the specification it is difficult to come up with a metric.  In
   writing this TIP, I assumed a vacuum -- that is, a listx command
   would not be added to the core in the near future.

''Donal K. Fellows <[email protected]> points out''

 > Although there is tcllib and [[listx]] to think about, they are
   certainly not reasons for rejecting this TIP out of hand.  The
   availability of tcllib is not currently anything like universal
   (not stating whether this is a good, bad or ugly thing) and all the
   [[listx]] work will need its own TIP to make it into the core (you
   tend to have availability problems if it is an extension.)  It is
   not as if the core is short of syntactic sugar right now (the
   [[foreach]] command is ample demonstration of this.)

''Don Porter <[email protected]> follows up''

 > I'll leave the discussion above in place so the history
   of this TIP is preserved, but I have withdrawn my
   objection.

----

There was quite a discussion on news:comp.lang.tcl about using lindex
to return multiple arguments.  For example:

| % set list {a {b1 b2} c d e}
| % lindex $list 1
| b1 b2
| % lindex $list 1 0
| {b1 b2} a
| % lindex $list {1 0}
| b1

In other words, the list index arguments can, themselves, be lists.
Only when the argument is a list would the "recursive selection"
procedure of the TIP be used.  For multiple arguments, the behaviour
is akin to

| lindex $list a b c  ->
|      list [lindex $list a] [lindex $list b] [lindex $list c]

''Summarised by Dave Cuthbert <[email protected]>''

''Donal K. Fellows <[email protected]> points out''

 > The problems with the above version of multiple indexing are that
   it loses the property that [[lindex]] always returns a single
   element (making writing robust code harder) and that it forces use
   of the [[list]] constructor a lot or inefficient type handling when
   some of the indices must be computed.  Then there is the whole
   question of what happens when you have indexes that are lists of
   lists, which is a major can of worms.

 > Luckily, we could always put this sort of behaviour into a separate
   command (e.g. called [[lselect]]) which addresses at least the
   majority of my concerns, and which (in my opinion) need not even
   form part of this TIP.

''Dave Cuthbert <[email protected]> adds''

 > I intentionally left [[lselect]] out of the original TIP (and it
   is still not present in the 02-April-2001 version).  As Donal points
   out, it is a major can of worms and, though there was general
   agreement on c.l.t that such a command would be useful, people had
   differing opinions on what form it should take.

 > Perhaps my view on TIPs is incorrect, but I try to include only
   sure-fire "yeah, we ought to have done that a few versions ago"
   items.

----

~ Notes on History of this TIP

''This TIP was originally written by Dave Cuthbert <[email protected]>,
but ownership has passed (beginning of April) to Kevin Kenny
<[email protected]>.''

This TIP underwent substantial revision in May of 2001, to add the
syntax where all the ''index'' parameters could be grouped as a list
rather than placed inline on the command line.

~ See Also

[33].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
|
>

|


|



|



|




|


|


|
|

|
|


|
|
|
|
|
|
<
>
|
|
|
<
<
>
>
|





|
|
|
|
|
|

|


|

|


|



|

|


|

|
|
|



|

|
|

|
|
|
|
|
|


|


|

|

|

|

|

|

|

|
|

|
|
|






|

|
|


|

|



|

|
|


|


|
|
|

|
|



|



|


|








|

|



|



|
|


|


|


|






|

|



|

|




|






|


|




|
|


|




|

|

|




|

|


|
|
|
|
|

|










|
|
|
|
|
|
|






|
|

|

|


|
|
|





|
|


|

|
|










|

|
|
|


|


|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342

# TIP 22: Multiple Index Arguments to lindex

	Author:         David Cuthbert <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	Author:         Don Porter <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        19-Jan-2001
	Post-History:   
	Discussions-To: news:comp.lang.tcl,mailto:[email protected]
	Keywords:       lindex,multiple arguments,sublists
	Tcl-Version:    8.4a2
-----

# Abstract

Obtaining access to elements of sublists in Tcl often requires nested
calls to the _lindex_ command.  The indices are syntactically listed
in most-nested to least-nested order, which is the reverse from other
notations.  In addition, the nesting of command substitution brackets
further decreases readability.  This proposal describes an extension
to the _lindex_ command that allows it to accept multiple index
arguments, in least-nested to most-nested order, to automatically
extract elements of sublists.

# Rationale

The heterogeneous nature of Tcl lists allows them to be applied to a
number of useful data structures.  In particular, lists can contain
elements that are, themselves, valid lists.  In this document, these
elements are referred to as _sublists._

Extracting elements from sublists often requires nested calls to
_lindex._  Consider, for example, the following Tcl script that
prints the center element of a 3-by-3 matrix:

	    set A {{1 2 3} {4 5 6} {7 8 9}}
	    puts [lindex [lindex $A 2] 2]

When these calls are deeply nested - e.g., embedded in an _expr_
arithmetic expression, having results extracted through _lrange,_
etc. - the results are difficult to read:

	# Print the sum of the center indices of two 3x3 matrices
	set p [expr {[lindex [lindex $A 2] 2] + [lindex [lindex $A 2] 2]}]
	
	# Get all but the last font in the following parsed structure:
	set pstruct {text {ignored-data
	                      { ... }

			       }
			       {valid-styles
				   {justifiction {left centered right full}}
				   {font {courier helvetica times}}


			       }
			 }
	return [lrange [lindex [lindex [lindex $pstruct 1] 2] 2] 0 end-1]

Note that the list of indices in the latter example is listed in the
reverse order of vector indices.  In most other languages/domains, the
last line might take on one of the following forms:

	return list_range(pstruct[2][2][1], 0, end-1);
	
	return pstruct[[2, 2, 1]][[0:-1]]
	
	temp = pstruct(2, 2, 1);
	result = range(temp, 0, length(temp) - 1);

Allowing the _lindex_ command to accept multiple arguments would
allow this more-natural style of coding to be written in Tcl.

# Specification

 1. Under this proposal, the syntax for the _lindex_ command is to be
    modified to accept one of two forms:

		     lindex list indexList

    or

		     lindex list index1 index2...

	    > In either form of the command, the _list_ parameter is
      expected to be a well-formed Tcl list.

	    > In the first form of the command, the _indexList_ argument is
      expected to be a Tcl list comprising one or more list indices,
      each of which must be an integer, the literal string _end_, or
      the literal string _end-_ followed by an integer with no
      intervening whitespace.  The existing _lindex_ command is a
      degenerate form of this first form, where the list comprises a
      single index.

	    > In the second form of the command, each of the _index_
      arguments is expected to be a list index, which again may be an
      integer, the literal string _end_, or the literal string
      _end-_ followed by an integer with no intervening whitespace.

 2. In either form of the command, once the _indexList_ parameter
    is expanded, there is a single _list_ parameter and one or
    more _index_ parameters.  If there is a single _index_
    parameter _N_, the behavior is identical to today's _lindex_
    command, and the command returns the _N_th element of
    _list_; if _N_ is less than zero or at least the length of
    the list, a null string is returned.

 3. If more than one _index_ parameter is given, then the behavior is
    defined recursively; the result of

		   lindex $list $index0 $index1 ...

	  > or

		   lindex $list [list $index0 $index1 ...]

	  > is indentical to that of

		   lindex [lindex $list $index0] $index1...

	  > or, equivalently,

		   lindex [lindex $list $index0] [list $index1...]

	  > \(This specification does not constrain the implementation, which
    may be iterative, recursive, or even expanded inline.\)

 4. When an invalid index is given, an error of the form, _bad index
    "invalid\_index": must be integer or end?-integer?_, where
    _invalid\_index_ is the first invalid index encountered, must be
    returned.

 5. If the list argument is malformed, the error resulting from an
    attempt to convert the list argument to a list must be returned.
    This behaviour is unchanged from the current implementation.

# Side Effects

 1. Whether the result of the _lindex_ operation is successful, the
    underlying Tcl\_Obj that represents the list argument may have its
    internal representation invalidated or changed to that of a list.

# Discussion

Some attention must be paid to giving the _lindex_ command adequate
performance.  In particular, the implementation should address the
common case of

	    lindex $list $i

where _$i_ is a "pure" integer \(that is, one whose string
representation has not yet been formed\).  If the above specification
is followed naively, the flow will be as follows.

Since _objc_ is three, _objv[[2]](2.md)_ is expected to be a list.
Since it is not, it must be converted from its string representation.
It does not have one yet, so the string representation must be formed.
Now the string representation is parsed as a list.  An array \(of
length one\) of Tcl\_Obj pointers is allocated to hold the list in
question, and a Tcl\_Obj is allocated to hold the single element.
Memory is allocated to hold the element's string representation.
Now the _lindex_ command converts the first element of the list to
an index \(in this case an integer\).

This elaborate ballet of type shimmering requires converting the
integer to a string and back again.  It also requires four calls to
_ckalloc:_

 1. Allocate a buffer for the string representation.

 2. Allocate the array of Tcl\_Obj pointers for the list
    representation.

 3. Allocate the Tcl\_Obj that represents the first \(and only\) element
    of the list.

 4. Allocate a buffer for the string representation of that element.

And at the end, the result is the same integer that was passed as a
parameter originally.

To avoid all this overhead in the common case, the proposed
implementation shall \(in the case where _objc==3_\)

 1. Test whether _objv[[2]](2.md)_ designates an object whose internal
    representation holds an integer.  If so, simply use it as an
    index.

 2. Test whether _objv[[2]](2.md)_ designates an object whose internal
    representation holds a list.  If so, perform the recursive
    extraction of indexed elements from sublists described above.

 3. Form the string representation of _objv[[2]](2.md)_ and test whether
    it is _end_ or _end-_ followed by an integer.  If so, use it
    as an index.

 4. Attempt to coerce _objv[[2]](2.md)_ to an integer; if successful, use
    the result as an integer.

 5. Attempt to coerce _objv[[2]](2.md)_ to a list; if successful, use the
    result as an index list.

 6. Report a malformed _index_ argument; the _indexList_ parameter
    is not a well-formed list.

This logic handles all the cases of singleton lists transparently; it
is effectively a simple-minded type inference that optimizes away
needless conversions.

Assuming that the related [[33]](33.md) is approved, this logic will most
likely be combined with the identical logic required in that proposal
for parsing _index_ arguments to the _lset_ command.

----

# Comments

_Don Porter <[email protected]>_

 > I agree that it would be helpful to many programmers to
   provide a multi-dimensional array data structure that can
   be accessed in the manner described in this TIP.  In the
   _struct_ module of _tcllib_, several other data structures
   are being developed: graph, tree, queue, stack.  I would support
   adding another data structure to that module that provides an
   interface like the one described in this TIP, with the intent that
   all of these helpful data structures find their way into the
   BI distribution.

 > I don't see any advantage to adding complexity to [lindex]
   as an alternative to development of a multi-dimensional array
   structure.  Without a compelling advantage, I'm inclined against
   making [lindex] more complex.  I like having Tcl's built-in
   commands provide primitive operations, and leave it to
   packages to combine the primitives into more useful, more
   complex resources.

 > This TIP should also consider how any changes to [lindex] mesh
   with the whole [listx] overhaul of Tcl's [list] command that
   has been discussed.

_Dave Cuthbert <[email protected]> responds_

 > Don makes a good point -- with a good set of data structures in
   tcllib, the need for this TIP is lessened or even eliminated.
   Nonetheless, I see this as a way of implementing the structures he
   describes.  In other words, a more powerful primitive \(which, in
   reality, adds fairly little complexity when measured in number of
   lines of code changed\) would benefit these structures.

 > As for the [listx] overhaul, there are many competing proposals
   for the specification it is difficult to come up with a metric.  In
   writing this TIP, I assumed a vacuum -- that is, a listx command
   would not be added to the core in the near future.

_Donal K. Fellows <[email protected]> points out_

 > Although there is tcllib and [listx] to think about, they are
   certainly not reasons for rejecting this TIP out of hand.  The
   availability of tcllib is not currently anything like universal
   \(not stating whether this is a good, bad or ugly thing\) and all the
   [listx] work will need its own TIP to make it into the core \(you
   tend to have availability problems if it is an extension.\)  It is
   not as if the core is short of syntactic sugar right now \(the
   [foreach] command is ample demonstration of this.\)

_Don Porter <[email protected]> follows up_

 > I'll leave the discussion above in place so the history
   of this TIP is preserved, but I have withdrawn my
   objection.

----

There was quite a discussion on news:comp.lang.tcl about using lindex
to return multiple arguments.  For example:

	 % set list {a {b1 b2} c d e}
	 % lindex $list 1
	 b1 b2
	 % lindex $list 1 0
	 {b1 b2} a
	 % lindex $list {1 0}
	 b1

In other words, the list index arguments can, themselves, be lists.
Only when the argument is a list would the "recursive selection"
procedure of the TIP be used.  For multiple arguments, the behaviour
is akin to

	 lindex $list a b c  ->
	      list [lindex $list a] [lindex $list b] [lindex $list c]

_Summarised by Dave Cuthbert <[email protected]>_

_Donal K. Fellows <[email protected]> points out_

 > The problems with the above version of multiple indexing are that
   it loses the property that [lindex] always returns a single
   element \(making writing robust code harder\) and that it forces use
   of the [list] constructor a lot or inefficient type handling when
   some of the indices must be computed.  Then there is the whole
   question of what happens when you have indexes that are lists of
   lists, which is a major can of worms.

 > Luckily, we could always put this sort of behaviour into a separate
   command \(e.g. called [lselect]\) which addresses at least the
   majority of my concerns, and which \(in my opinion\) need not even
   form part of this TIP.

_Dave Cuthbert <[email protected]> adds_

 > I intentionally left [lselect] out of the original TIP \(and it
   is still not present in the 02-April-2001 version\).  As Donal points
   out, it is a major can of worms and, though there was general
   agreement on c.l.t that such a command would be useful, people had
   differing opinions on what form it should take.

 > Perhaps my view on TIPs is incorrect, but I try to include only
   sure-fire "yeah, we ought to have done that a few versions ago"
   items.

----

# Notes on History of this TIP

_This TIP was originally written by Dave Cuthbert <[email protected]>,
but ownership has passed \(beginning of April\) to Kevin Kenny
<[email protected]>._

This TIP underwent substantial revision in May of 2001, to add the
syntax where all the _index_ parameters could be grouped as a list
rather than placed inline on the command line.

# See Also

[[33]](33.md).

# Copyright

This document has been placed in the public domain.

Name change from tip/220.tip to tip/220.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

TIP:            220
Title:          Escalate Privileges in VFS Close Callback
Version:        $Revision: 1.18 $
Author:         Colin McCormack <[email protected]>
Author:         Andreas Kupries <[email protected]>
Author:         Vince Darley <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        12-Sep-2004
Post-History:   
Tcl-Version:    8.7


~ Abstract

This tip allows the creator and opener of a channel to cast away
privileges and have them restored on close, to permit last-minute
processing.  It is sufficient to resolve a ''tclvfs'' bug, minimal,
and safe.

~ Abstract

This tip allows the creator and opener of a channel to cast away
privileges and have them restored on close, to permit last-minute
processing.  It is sufficient to resolve a ''tclvfs'' bug, minimal,
and safe.

~ Rationale

''Tclvfs'' has a bug '''[[1004273]]''' ''Can't read from channel in
close callback''
[http://sourceforge.net/support/tracker.php?aid=1004273]
that is due in part to the core channel handler behaviour.

The problem is that the user has requested a read-only or write-only
channel, but the ''tclvfs'' close process absolutely requires fuller
access to the channel.

Use case one: A user's write-only channel has to be read by close in
order to be processed.

The second relevant use case: A user's read-only channel has to be
written, i.e. loaded with data, before it is passed to the user.

The first use case can be modelled by the ''owner'' of a channel (in
this case, the ''tclvfs'' code) by opening it with minimal
permissions, handing the channel to a user, then subsequently
re-aquiring full possible channel permissions at the point where the
channel needs to be closed - that is, immediately before the
''tclvfs'' close callback is invoked.

The second use case can be modelled by the ''owner'' of a channel (in
this case, the ''tclvfs'' code) by opening it with maximal
permissions, loading the data, and handing the channel to a user
'''after''' removing the unwanted permissions from the channel.

~ Safety

   * Escalation of privilege is controlled with the Tcl core, and is
     unavailable to extensions except in their role as vfs
     implementations.

   * Privilege is only granted to the entity which opened the channel,
     because only that entity implements the close callback.

   * The creator/opener can't operate with any permissions it could
     not have obtained at creation/opening time, since they are
     granted by the OS and not Tcl.

   * Privilege escalation occurs only at a point immediately before
     the Tcl core is about to completely close the channel, so the
     privileges can't leak.

   * The operation of releasing privileges only restricts the user of
     a channel, it cannot be used to reaquire privileges which are not
     granted by the channel.

~ Proposed Changes

Immediately prior to invoking the VFS close callback on a channel,
Tcl core should set channel's permissions to the maximum possible.

Export a new function as part of the public API which allows a user to
remove privileges from channel, but not to add them.

~ Details

The signature of the new function is

| int Tcl_RemoveChannelMode (Tcl_Interp* interp, Tcl_Channel chan, int mode);
|
| /* Codes for 'mode', already defined, _not_ new */
|
| #define TCL_READABLE	(1<<1)
| #define TCL_WRITABLE	(1<<2)

The argument ''mode'' determines which privilege to release, and is
set to one of the two specified codes. It is '''not''' a bitset. It is
not allowed to release all privileges of the channel, as this would
make the channel completely inacessible. Trying to do so will
therefore cause the generation of an error, without changing the
channel. The function will return a regular Tcl result code, either
TCL_OK, or TCL_ERROR. If the ''interp'' argument is set an error
message will be left in the interp in the error case. If the
''interp'' argument is NULL it will be ignored.

~ History

This TIP was originally written to allow C code to modify permissions,
but this makes the permissions system mean nothing, as a channel's
permissions could then be freely modified in an ''ad hoc'' manner.
The TIP now specifies a weaker modification that is still powerful
enough to implemenent the desired channel semantics.

~ Reference Implementation

A reference implementation will be provided at SourceForge
[http://sourceforge.net/support/tracker.php?aid=1057093].

~ Comments

It may be preferable for the new function to be in tclInt.h and therefore in the non-public interfaces (tclvfs already makes use of tclInt.h anyway): TclRemoveChannelMode.

''[[ Add more comments on the document here ]]''

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|



|


|



|


|

|
|
|



|








|
|



|

|
|

|

|




















|







|



|
|
|
|
|
|

|
|




|

|

|



|



|


|

|

|

|

|


>

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

# TIP 220: Escalate Privileges in VFS Close Callback

	Author:         Colin McCormack <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	Author:         Vince Darley <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        12-Sep-2004
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This tip allows the creator and opener of a channel to cast away
privileges and have them restored on close, to permit last-minute
processing.  It is sufficient to resolve a _tclvfs_ bug, minimal,
and safe.

# Abstract

This tip allows the creator and opener of a channel to cast away
privileges and have them restored on close, to permit last-minute
processing.  It is sufficient to resolve a _tclvfs_ bug, minimal,
and safe.

# Rationale

_Tclvfs_ has a bug **[[1004273]](1004273.md)** _Can't read from channel in
close callback_
<http://sourceforge.net/support/tracker.php?aid=1004273> 
that is due in part to the core channel handler behaviour.

The problem is that the user has requested a read-only or write-only
channel, but the _tclvfs_ close process absolutely requires fuller
access to the channel.

Use case one: A user's write-only channel has to be read by close in
order to be processed.

The second relevant use case: A user's read-only channel has to be
written, i.e. loaded with data, before it is passed to the user.

The first use case can be modelled by the _owner_ of a channel \(in
this case, the _tclvfs_ code\) by opening it with minimal
permissions, handing the channel to a user, then subsequently
re-aquiring full possible channel permissions at the point where the
channel needs to be closed - that is, immediately before the
_tclvfs_ close callback is invoked.

The second use case can be modelled by the _owner_ of a channel \(in
this case, the _tclvfs_ code\) by opening it with maximal
permissions, loading the data, and handing the channel to a user
**after** removing the unwanted permissions from the channel.

# Safety

   * Escalation of privilege is controlled with the Tcl core, and is
     unavailable to extensions except in their role as vfs
     implementations.

   * Privilege is only granted to the entity which opened the channel,
     because only that entity implements the close callback.

   * The creator/opener can't operate with any permissions it could
     not have obtained at creation/opening time, since they are
     granted by the OS and not Tcl.

   * Privilege escalation occurs only at a point immediately before
     the Tcl core is about to completely close the channel, so the
     privileges can't leak.

   * The operation of releasing privileges only restricts the user of
     a channel, it cannot be used to reaquire privileges which are not
     granted by the channel.

# Proposed Changes

Immediately prior to invoking the VFS close callback on a channel,
Tcl core should set channel's permissions to the maximum possible.

Export a new function as part of the public API which allows a user to
remove privileges from channel, but not to add them.

# Details

The signature of the new function is

	 int Tcl_RemoveChannelMode (Tcl_Interp* interp, Tcl_Channel chan, int mode);
	
	 /* Codes for 'mode', already defined, _not_ new */
	
	 #define TCL_READABLE	(1<<1)
	 #define TCL_WRITABLE	(1<<2)

The argument _mode_ determines which privilege to release, and is
set to one of the two specified codes. It is **not** a bitset. It is
not allowed to release all privileges of the channel, as this would
make the channel completely inacessible. Trying to do so will
therefore cause the generation of an error, without changing the
channel. The function will return a regular Tcl result code, either
TCL\_OK, or TCL\_ERROR. If the _interp_ argument is set an error
message will be left in the interp in the error case. If the
_interp_ argument is NULL it will be ignored.

# History

This TIP was originally written to allow C code to modify permissions,
but this makes the permissions system mean nothing, as a channel's
permissions could then be freely modified in an _ad hoc_ manner.
The TIP now specifies a weaker modification that is still powerful
enough to implemenent the desired channel semantics.

# Reference Implementation

A reference implementation will be provided at SourceForge
<http://sourceforge.net/support/tracker.php?aid=1057093> .

# Comments

It may be preferable for the new function to be in tclInt.h and therefore in the non-public interfaces \(tclvfs already makes use of tclInt.h anyway\): TclRemoveChannelMode.

_[ Add more comments on the document here ]_

# Copyright

This document has been placed in the public domain.

Name change from tip/221.tip to tip/221.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174

TIP:            221
Title:          Allow Background Error Handlers to Accept Return Options
Version:        $Revision: 2.10 $
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        15-Sep-2004
Post-History:   
Keywords:       bgerror,return,options
Tcl-Version:    8.5


~ Abstract

This TIP proposes a new system for registering a background error
handler of an interp so that the full set of return options ([90]) can
be passed to it.

~ Background

Whenever a script is evaluated as part of handling an event, and
that script evaluation returns TCL_ERROR or some other non-TCL_OK
return code it is not equipped to handle, then the code that
evaluates that script is expected to call ''Tcl_BackgroundError''
to report the exceptional code to the application.

Then ''Tcl_BackgroundError'' will arrange for the command
'''bgerror''' to be called during an idle event.  It is intended
that each application will define a '''::bgerror''' command to its
liking so that background errors are reported (or ignored) as
the application prefers.

The defined syntax for '''bgerror''' is 

 > '''bgerror''' ''message''

The '''bgerror''' command receives as its only argument a copy of
what the interp result was when ''Tcl_BackgroundError'' was called.
This is presumably an error message.

When '''bgerror''' is called, it is also arranged that the
variables '''::errorInfo''' and '''::errorCode''' are set to
the same values they had when ''Tcl_BackgroundError'' was called.
This is effectively another set of arguments passed through a
side channel.

Note that the non-TCL_OK return code that triggered
the ''Tcl_BackgroundError'' call is not itself made known to 
'''bgerror'''.  Nor is the ''-level'', ''-errorline'', or other
return option information made possible by [90] passed along
to '''bgerror''' in any way.

~ Proposal

A new subcommand, '''interp bgerror''' will be created that
allows for registration of a handler command to react to
background errors.  Its syntax will be:

 > '''interp bgerror''' ''path'' ?''cmdPrefix''?

Here ''path'' is the path of an interp, interpreted the same way
as the ''path'' argument to the existing '''interp aliases'''
subcommand.  This argument determines which interp's background
error handler we are interested in.  The value of an empty list
for ''path'' indicates the current interp.

As is the case with other '''interp''' subcommands, an alternative
means to access the same functionality will be made available
as the '''bgerror''' subcommand of the ''slave'' command of
an interp with syntax:

 > ''slave'' '''bgerror''' ?''cmdPrefix''?

When no ''cmdPrefix'' argument is present, the command prefix
currently registered to handle background errors in the ''path''
interp will be returned.  The returned value will be
the ''cmdPrefix'' argument most recently successfully passed
to '''interp bgerror''' ''path'', or the default
background error handler command of the interp.

When a ''cmdPrefix'' argument is present, it must be a valid Tcl
list of length at least one.  An invalid list or an empty list
is an error.  A ''cmdPrefix'' list argument of
length ''N'' will become the first ''N'' substituted words of
the handler command invoked to handle calls to ''Tcl_BackgroundError''.
That is, if the ''cmdPrefix'' argument is stored in a variable
'''cmdPrefix''', subsequent calls to ''Tcl_BackgroundError'' will
lead to evaluation of a command like so:

 > '''{expand}$cmdPrefix''' ''message'' ''returnOptionsDictionary''

The ''message'' argument is the interp result at the time
''Tcl_BackgroundError'' is called.
The ''returnOptionsDictionary'' argument is a Tcl dict value ([111])
holding the value of the interp's return options dictionary at the
time ''Tcl_BackgroundError'' was called.  Specifically,
the ''returnOptionsDictionary'' argument is the value
returned by ''Tcl_GetReturnOptions'' ([227]) at the time
''Tcl_BackgroundError'' is called.

Stored in the ''returnOptionsDictionary'' argument will be values
for the ''-level'' and ''-code'' keys, and when those values
indicate a TCL_ERROR triggered the ''Tcl_BackgroundError'' call,
the ''-errorinfo'', ''-errorcode'', and ''-errorline'' keys will
have values as well.  Any other return options present in the
interp's return options  dictionary at the time ''Tcl_BackgroundError''
is called will also be available in the ''returnOptionsDictionary'' argument.

Note that after this change, applications will be able to
register a background error handling command that has no need
to consult the variables '''::errorInfo''' or '''::errorCode''' at all.

~ Compatibility

Existing applications making use of the '''bgerror''' interface
provide a '''bgerror''' command that expects exactly one argument.

To continue to compatibly support these applications, the default
background error handler command prefix registered in each interp
will be a command that sets the values of '''::errorInfo'''
and '''::errorCode''' to the values of the corresponding keys in
the return options dictionary, if appropriate.  Then it will
invoke the command '''bgerror''' ''message'' in the global namespace.
For complete compatibility, the existing fallbacks will also
be honored in the default handler, including the
invoking a hidden command '''bgerror''' ''message''
in safe interps, and the ultimate fallback (in trusted interps only)
being a message written to the stderr channel of the process as determined
by ''Tcl_GetStdChannel(TCL_STDERR)''.

~ Rejected Alternatives

The first draft of this proposal proposed several attempts to
call '''bgerror''', first with two arguments, then with one.
It was rejected because an error due to calling '''bgerror'''
with the wrong number of arguments could not be distinguished
(easily and reliably) from an error for other reasons.  This
fallback strategy was prone to the masking of errors.

The new proposal is also preferred over the first draft as
it empowers Tcl programmers to leave behind '''bgerror'''
as a ''magic'' command name with special significance to Tcl.
Callback registration is a cleaner mechanism then giving
particular command names privileged status, and we should
move in that direction when the opportunity arises.

An alternative syntax for '''interp bgerror''',

 > '''interp bgerror''' ''path target cmdPrefix''

was considered.  This alternative would have allowed background
errors in the ''path'' interp to be handled in the ''target''
interp.  The difficulty with this alternative was in how to
define the introspection form of the command.  Introspection
would need to return ''target'' information, and it would be
possible that the target interp of the handler would be 
an interp for which no ''target'' path could be constructed
to be returned (a sibling, parent, or uncle interp, etc.).

The proposed form can be combined with '''interp alias''' to
still allow background errors in one interp to (ultimately)
be handled by a command evaluation in a different interp.

~ Reference Implementation

See Tcl Patch 1060579.

~ Comments

Please make any comments here.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|


|


|

|


|
|
|
|


|

|

|
|


|
|
|



|
|
|
|
|

|

|



|

|
|


|

|

|


|

|
|

|
|


|

|
|
|
|
|


|

|
|
|

|
|
|
|

|
|
|
|

|
|



|

|

|
|



|
|

|


|
|

|

|


|
|

|



|
|




|

|


|


|

|
|

|
|


|



|



|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174

# TIP 221: Allow Background Error Handlers to Accept Return Options

	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        15-Sep-2004
	Post-History:   
	Keywords:       bgerror,return,options
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes a new system for registering a background error
handler of an interp so that the full set of return options \([[90]](90.md)\) can
be passed to it.

# Background

Whenever a script is evaluated as part of handling an event, and
that script evaluation returns TCL\_ERROR or some other non-TCL\_OK
return code it is not equipped to handle, then the code that
evaluates that script is expected to call _Tcl\_BackgroundError_
to report the exceptional code to the application.

Then _Tcl\_BackgroundError_ will arrange for the command
**bgerror** to be called during an idle event.  It is intended
that each application will define a **::bgerror** command to its
liking so that background errors are reported \(or ignored\) as
the application prefers.

The defined syntax for **bgerror** is 

 > **bgerror** _message_

The **bgerror** command receives as its only argument a copy of
what the interp result was when _Tcl\_BackgroundError_ was called.
This is presumably an error message.

When **bgerror** is called, it is also arranged that the
variables **::errorInfo** and **::errorCode** are set to
the same values they had when _Tcl\_BackgroundError_ was called.
This is effectively another set of arguments passed through a
side channel.

Note that the non-TCL\_OK return code that triggered
the _Tcl\_BackgroundError_ call is not itself made known to 
**bgerror**.  Nor is the _-level_, _-errorline_, or other
return option information made possible by [[90]](90.md) passed along
to **bgerror** in any way.

# Proposal

A new subcommand, **interp bgerror** will be created that
allows for registration of a handler command to react to
background errors.  Its syntax will be:

 > **interp bgerror** _path_ ?_cmdPrefix_?

Here _path_ is the path of an interp, interpreted the same way
as the _path_ argument to the existing **interp aliases**
subcommand.  This argument determines which interp's background
error handler we are interested in.  The value of an empty list
for _path_ indicates the current interp.

As is the case with other **interp** subcommands, an alternative
means to access the same functionality will be made available
as the **bgerror** subcommand of the _slave_ command of
an interp with syntax:

 > _slave_ **bgerror** ?_cmdPrefix_?

When no _cmdPrefix_ argument is present, the command prefix
currently registered to handle background errors in the _path_
interp will be returned.  The returned value will be
the _cmdPrefix_ argument most recently successfully passed
to **interp bgerror** _path_, or the default
background error handler command of the interp.

When a _cmdPrefix_ argument is present, it must be a valid Tcl
list of length at least one.  An invalid list or an empty list
is an error.  A _cmdPrefix_ list argument of
length _N_ will become the first _N_ substituted words of
the handler command invoked to handle calls to _Tcl\_BackgroundError_.
That is, if the _cmdPrefix_ argument is stored in a variable
**cmdPrefix**, subsequent calls to _Tcl\_BackgroundError_ will
lead to evaluation of a command like so:

 > **\{expand\}$cmdPrefix** _message_ _returnOptionsDictionary_

The _message_ argument is the interp result at the time
_Tcl\_BackgroundError_ is called.
The _returnOptionsDictionary_ argument is a Tcl dict value \([[111]](111.md)\)
holding the value of the interp's return options dictionary at the
time _Tcl\_BackgroundError_ was called.  Specifically,
the _returnOptionsDictionary_ argument is the value
returned by _Tcl\_GetReturnOptions_ \([[227]](227.md)\) at the time
_Tcl\_BackgroundError_ is called.

Stored in the _returnOptionsDictionary_ argument will be values
for the _-level_ and _-code_ keys, and when those values
indicate a TCL\_ERROR triggered the _Tcl\_BackgroundError_ call,
the _-errorinfo_, _-errorcode_, and _-errorline_ keys will
have values as well.  Any other return options present in the
interp's return options  dictionary at the time _Tcl\_BackgroundError_
is called will also be available in the _returnOptionsDictionary_ argument.

Note that after this change, applications will be able to
register a background error handling command that has no need
to consult the variables **::errorInfo** or **::errorCode** at all.

# Compatibility

Existing applications making use of the **bgerror** interface
provide a **bgerror** command that expects exactly one argument.

To continue to compatibly support these applications, the default
background error handler command prefix registered in each interp
will be a command that sets the values of **::errorInfo**
and **::errorCode** to the values of the corresponding keys in
the return options dictionary, if appropriate.  Then it will
invoke the command **bgerror** _message_ in the global namespace.
For complete compatibility, the existing fallbacks will also
be honored in the default handler, including the
invoking a hidden command **bgerror** _message_
in safe interps, and the ultimate fallback \(in trusted interps only\)
being a message written to the stderr channel of the process as determined
by _Tcl\_GetStdChannel\(TCL\_STDERR\)_.

# Rejected Alternatives

The first draft of this proposal proposed several attempts to
call **bgerror**, first with two arguments, then with one.
It was rejected because an error due to calling **bgerror**
with the wrong number of arguments could not be distinguished
\(easily and reliably\) from an error for other reasons.  This
fallback strategy was prone to the masking of errors.

The new proposal is also preferred over the first draft as
it empowers Tcl programmers to leave behind **bgerror**
as a _magic_ command name with special significance to Tcl.
Callback registration is a cleaner mechanism then giving
particular command names privileged status, and we should
move in that direction when the opportunity arises.

An alternative syntax for **interp bgerror**,

 > **interp bgerror** _path target cmdPrefix_

was considered.  This alternative would have allowed background
errors in the _path_ interp to be handled in the _target_
interp.  The difficulty with this alternative was in how to
define the introspection form of the command.  Introspection
would need to return _target_ information, and it would be
possible that the target interp of the handler would be 
an interp for which no _target_ path could be constructed
to be returned \(a sibling, parent, or uncle interp, etc.\).

The proposed form can be combined with **interp alias** to
still allow background errors in one interp to \(ultimately\)
be handled by a command evaluation in a different interp.

# Reference Implementation

See Tcl Patch 1060579.

# Comments

Please make any comments here.

# Copyright

This document has been placed in the public domain.

Name change from tip/222.tip to tip/222.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

TIP:		222
Title:		Add [wm attributes -alpha] Attribute on Windows
Version:	$Revision: 1.8 $
Author:		Jeff Hobbs <[email protected]>
Author:		Andreas Kupries <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	16-Sep-2004
Post-History:	
Tcl-Version:	8.5
Keywords:	Tk


~ Abstract

This TIP proposes a new controlled attribute '''-alpha''' to control toplevel
alpha transparency for the '''wm attributes''' command on Windows.

~ Rationale

Windows 2000/XP+ has the ability to create windows with alpha
transparency.  This attribute would expose control for that functionality
for Tk users.  This is mostly an eye candy feature, but could be useful
for fade-in splash screens or fancy demos.

~ Specification

A new attribute '''-alpha''' will be recognized by '''wm attributes'''.  It will
take a double value from 0.0 (completely transparent) to 1.0 (opaque) that signifies the
percentage transparency of the toplevel.  Thus, '''-alpha 0.9''' would make the toplevel 90% visible (10% transparent).  Any value outside [0.0..1.0] will be constrained to the nearest bound.

There are some special considerations for this feature.  It only works on
Windows 2000/XP+.  The code handles the dynamic lookup of the necessary
functionality.  If you do not have the functionality, then any attempt to
set the '''-alpha''' value will be ignored, and queries to '''-alpha'''
will always return 0 (opaque).

Layered windows cannot use the CS_CLASSDC class style, so an alternative
class must be made available.  This is handled in the implementation
transparently, with ''UpdateWrapper'' choosing the appropriate class as
necessary.  Transparent windows will use '''TkToplevelNoDC''' as their
class name (normal is '''TkToplevel''').

Efforts have been made to reduce calls to ''UpdateWrapper''.

~ Reference Implementation

See Tk Patch 892194 [http://sf.net/support/tracker.php?aid=892194]

The reference patch implements the functionality along with one bug fix to
''UpdateWrapper'' - correct setting of the Z order of the window based on the
previous wrapper window.

While this patch addresses Windows alpha transparency, it is available for other platforms.  It is recommended that the same syntax be used across platforms.

~ Comments

Discussion focused around the use of ''-alpha'' versus ''-transparency''.  Some felt that the latter was more familiar to end users.  The author refutes this with several points.  First, the existing TIP#166 uses ''-alpha'' as well, for the same functionality specific to Tk images (using the same [0..1] value as well).  Also, the underlying APIs for each platform refer to the alpha level as well.  In looking over various documentation, transparency is often a boolean concept, which alpha is the gradual level.  This is how it will be used in Tk.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|
|

|

|




|

|
|
|


|

|
|

|

|
|
|

|

|

|


|




|

|

|


>

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

# TIP 222: Add [wm attributes -alpha] Attribute on Windows

	Author:		Jeff Hobbs <[email protected]>
	Author:		Andreas Kupries <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	16-Sep-2004
	Post-History:	
	Tcl-Version:	8.5
	Keywords:	Tk
-----

# Abstract

This TIP proposes a new controlled attribute **-alpha** to control toplevel
alpha transparency for the **wm attributes** command on Windows.

# Rationale

Windows 2000/XP\+ has the ability to create windows with alpha
transparency.  This attribute would expose control for that functionality
for Tk users.  This is mostly an eye candy feature, but could be useful
for fade-in splash screens or fancy demos.

# Specification

A new attribute **-alpha** will be recognized by **wm attributes**.  It will
take a double value from 0.0 \(completely transparent\) to 1.0 \(opaque\) that signifies the
percentage transparency of the toplevel.  Thus, **-alpha 0.9** would make the toplevel 90% visible \(10% transparent\).  Any value outside [0.0..1.0] will be constrained to the nearest bound.

There are some special considerations for this feature.  It only works on
Windows 2000/XP\+.  The code handles the dynamic lookup of the necessary
functionality.  If you do not have the functionality, then any attempt to
set the **-alpha** value will be ignored, and queries to **-alpha**
will always return 0 \(opaque\).

Layered windows cannot use the CS\_CLASSDC class style, so an alternative
class must be made available.  This is handled in the implementation
transparently, with _UpdateWrapper_ choosing the appropriate class as
necessary.  Transparent windows will use **TkToplevelNoDC** as their
class name \(normal is **TkToplevel**\).

Efforts have been made to reduce calls to _UpdateWrapper_.

# Reference Implementation

See Tk Patch 892194 <http://sf.net/support/tracker.php?aid=892194> 

The reference patch implements the functionality along with one bug fix to
_UpdateWrapper_ - correct setting of the Z order of the window based on the
previous wrapper window.

While this patch addresses Windows alpha transparency, it is available for other platforms.  It is recommended that the same syntax be used across platforms.

# Comments

Discussion focused around the use of _-alpha_ versus _-transparency_.  Some felt that the latter was more familiar to end users.  The author refutes this with several points.  First, the existing TIP\#166 uses _-alpha_ as well, for the same functionality specific to Tk images \(using the same [0..1] value as well\).  Also, the underlying APIs for each platform refer to the alpha level as well.  In looking over various documentation, transparency is often a boolean concept, which alpha is the gradual level.  This is how it will be used in Tk.

# Copyright

This document has been placed in the public domain.

Name change from tip/223.tip to tip/223.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
TIP:            223
Title:          Full-Screen Toplevel Support for Tk
Version:        $Revision: 1.6 $
Author:         Mo DeJong <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        21-Sep-2004
Post-History:   
Tcl-Version:    8.5


~ Abstract

Tk lacks an optimal method for creating a full-screen '''toplevel'''.
A full-screen toplevel is one that has no borders and a client drawing
area that covers the entire screen.  On some UNIX systems, one can
create a normal toplevel that is a little larger than size of the
screen and place the upper left corner of the client drawing area at
at (0,0).  This option is not available under Windows as the position
and dimensions of normal windows are constrained to keep them from
covering up the start menu and task bar. Under Windows, a zoomed toplevel
with the ''overrideredirect'' flag set avoids this size restriction and
displays with no borders, both desirable properties. Unfortunately,
setting the ''overrideredirect'' flag also keeps an icon for the
toplevel from being displayed in the task bar and in the programs list
accessed via Alt-Tab. There are also some UNIX systems that restrict
the placement of a normal toplevel window. For example, the default
window manager for the KDE desktop restricts size and placement of a
normal toplevel in much the same way as Windows. This TIP and its associated patch implement full-screen functionality that also
displays an icon in the taskbar and is accessible via Alt-Tab.
The implementation adds a new '''-fullscreen''' option to the '''wm attributes''' subcommand.

~ Motivation

A Tk developer will at some point need to create a full-screen
application.  Existing Tk commands under Windows can be used to create
a mostly working full-screen application, but the edge cases where it
does not work well make the application look unprofessional. The
example code[http://wiki.tcl.tk/12506] was created to support a native
looking full-screen Windows application using only existing Tk commands.

The main problem this example attempts to work around is that a
toplevel with the overrideredirect flag set does not show an icon in
the Windows taskbar. To address this issue, a second fake window was
created and certain events for the fake window are redirected to the
full-screen window. This approach works for the most part but there
<
|
<
|
|
|
|
|
|
|
>

|

|




|


|

|






|

|





|








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

# TIP 223: Full-Screen Toplevel Support for Tk

	Author:         Mo DeJong <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        21-Sep-2004
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

Tk lacks an optimal method for creating a full-screen **toplevel**.
A full-screen toplevel is one that has no borders and a client drawing
area that covers the entire screen.  On some UNIX systems, one can
create a normal toplevel that is a little larger than size of the
screen and place the upper left corner of the client drawing area at
at \(0,0\).  This option is not available under Windows as the position
and dimensions of normal windows are constrained to keep them from
covering up the start menu and task bar. Under Windows, a zoomed toplevel
with the _overrideredirect_ flag set avoids this size restriction and
displays with no borders, both desirable properties. Unfortunately,
setting the _overrideredirect_ flag also keeps an icon for the
toplevel from being displayed in the task bar and in the programs list
accessed via Alt-Tab. There are also some UNIX systems that restrict
the placement of a normal toplevel window. For example, the default
window manager for the KDE desktop restricts size and placement of a
normal toplevel in much the same way as Windows. This TIP and its associated patch implement full-screen functionality that also
displays an icon in the taskbar and is accessible via Alt-Tab.
The implementation adds a new **-fullscreen** option to the **wm attributes** subcommand.

# Motivation

A Tk developer will at some point need to create a full-screen
application.  Existing Tk commands under Windows can be used to create
a mostly working full-screen application, but the edge cases where it
does not work well make the application look unprofessional. The
example code<http://wiki.tcl.tk/12506>  was created to support a native
looking full-screen Windows application using only existing Tk commands.

The main problem this example attempts to work around is that a
toplevel with the overrideredirect flag set does not show an icon in
the Windows taskbar. To address this issue, a second fake window was
created and certain events for the fake window are redirected to the
full-screen window. This approach works for the most part but there
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
136
137
138
139

The final user visible issue shows up when a full-screen window is
first mapped. The window gets mapped in the normal state and is then
resized to full-screen instead of being mapped at the size of the
screen. These application behaviors do not match native Windows apps
and just look unprofessional. As a result, a project was undertaken to
create a Tk patch to address these issues.

~ Proposal

The implementation adds a '''-fullscreen''' attribute that can be
set to a boolean value of 0 or 1. Example code to switch a window
from normal to full-screen mode is as follows.

|proc fullscreen_switch { top } {
|    if {[wm attributes $top -fullscreen]} {
|        wm attributes $top -fullscreen 0
|    } else {
|        wm attributes $top -fullscreen 0
|    }
|}



An implementation for Windows has been created to support this
new '''-fullscreen''' attribute. The list of changed files
is as follows:

 > ''doc/wm.n, tests/winWm.test, tests/wm.test, win/tkWinWm.c''

Tk patch 1032982 has been created to track these modifications. The
patch mostly duplicates the way an overrideredirect window is created
with some modifications so that the window is the proper size and has
an icon in the taskbar. In ''UpdateWrapper'' the Win32
''CreateWindowEx'' function is invoked with the WS_EX_APPWINDOW flag
passed as the ''dwExStyle'' argument and
(WS_POPUP|WS_CLIPCHILDREN|CS_DBLCLKS) passed as the ''dwStyle''
argument. Example Win32 code to create a standalone example
of such a window is also attached and can be found in the file
named ''full_screen.c''. The patch also includes additions to the
Tk test suite and documentation to cover these modifications.

~ Alternatives

One alternative is to do nothing. The existing pure Tcl implementation
works for most cases. Reasons for rejecting this alternative have
already been covered in this TIP.

An earlier approach that added a new '''fullscreen''' state available
via the '''wm state''' subcommand was abandoned based on advice
from Joe English. After implementing it both ways, both the Tk,
and the end user code seemed cleaner using the attributes approach.

Assuming the TIP is accepted and a new attribute is added, there
is one implementation alternative that might be useful to explore.
There may be a way to pass a window manager hint to the Windows OS so
that it allows the creation of a normal window that is larger than the
height of the screen minus the height of the task bar.  That would
mean a regular window class could be used instead of a popup
class. The only user visible change would be that right clicking on
the icon in the taskbar would show a context menu with the Restore,
Minimize, Maximise, and Close options. The current patch creates a
taskbar icon that always pops the full-screen window to the top on a
left or right click. It is not clear that this minor detail is
important enough to worry about.

~ Risks

The complexity of Unix and Mac implementation of this TIP is currently
not known.

~ See Also

SourceForge patch: 1032982

~ Copyright

This document has been placed in the public domain.








|

|



|
|
|
|
|
<
<
|
>
>

|


|




|
|
|
|


|


|





|
|
















|




|



|


>
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
136
137
138
139
The final user visible issue shows up when a full-screen window is
first mapped. The window gets mapped in the normal state and is then
resized to full-screen instead of being mapped at the size of the
screen. These application behaviors do not match native Windows apps
and just look unprofessional. As a result, a project was undertaken to
create a Tk patch to address these issues.

# Proposal

The implementation adds a **-fullscreen** attribute that can be
set to a boolean value of 0 or 1. Example code to switch a window
from normal to full-screen mode is as follows.

	proc fullscreen_switch { top } {
	    if {[wm attributes $top -fullscreen]} {
	        wm attributes $top -fullscreen 0
	    } else {
	        wm attributes $top -fullscreen 0


	    }
	}

An implementation for Windows has been created to support this
new **-fullscreen** attribute. The list of changed files
is as follows:

 > _doc/wm.n, tests/winWm.test, tests/wm.test, win/tkWinWm.c_

Tk patch 1032982 has been created to track these modifications. The
patch mostly duplicates the way an overrideredirect window is created
with some modifications so that the window is the proper size and has
an icon in the taskbar. In _UpdateWrapper_ the Win32
_CreateWindowEx_ function is invoked with the WS\_EX\_APPWINDOW flag
passed as the _dwExStyle_ argument and
\(WS\_POPUP\|WS\_CLIPCHILDREN\|CS\_DBLCLKS\) passed as the _dwStyle_
argument. Example Win32 code to create a standalone example
of such a window is also attached and can be found in the file
named _full\_screen.c_. The patch also includes additions to the
Tk test suite and documentation to cover these modifications.

# Alternatives

One alternative is to do nothing. The existing pure Tcl implementation
works for most cases. Reasons for rejecting this alternative have
already been covered in this TIP.

An earlier approach that added a new **fullscreen** state available
via the **wm state** subcommand was abandoned based on advice
from Joe English. After implementing it both ways, both the Tk,
and the end user code seemed cleaner using the attributes approach.

Assuming the TIP is accepted and a new attribute is added, there
is one implementation alternative that might be useful to explore.
There may be a way to pass a window manager hint to the Windows OS so
that it allows the creation of a normal window that is larger than the
height of the screen minus the height of the task bar.  That would
mean a regular window class could be used instead of a popup
class. The only user visible change would be that right clicking on
the icon in the taskbar would show a context menu with the Restore,
Minimize, Maximise, and Close options. The current patch creates a
taskbar icon that always pops the full-screen window to the top on a
left or right click. It is not clear that this minor detail is
important enough to worry about.

# Risks

The complexity of Unix and Mac implementation of this TIP is currently
not known.

# See Also

SourceForge patch: 1032982

# Copyright

This document has been placed in the public domain.

Name change from tip/224.tip to tip/224.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

TIP:            224
Title:          Add New [array] Subcommands 'incr' and 'value'
Version:        $Revision: 1.12 $
Author:         Peter MacDonald <[email protected]>
Author:         Robert Seeger <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        28-Sep-2004
Post-History:   
Tcl-Version:    8.7


~ Abstract

The TIP proposes the addition to two new subcommands to the
'''array''' command: '''incr''' and '''value'''.  The '''incr''
subcommand would increment an element in an array.  The '''value'''
subcommand would query, reference, and/or initialize an array element.

~ Rationale

[215] proposed modifying the '''incr''' command to auto-initialize
variables which do not exist, rather than throwing an error.  After
some debate, it was identified that frequency counting in arrays was
the primary area of interest.  In particular, the excessive use of
''if/info exists'' constructs in such code is inefficient, verbose and
rather difficult to read.  The addition of these two subcommands could
substantially reduce the complexity of much Tcl code.

~ Specification

Two new subcommands will be added to '''array''', being '''incr''' and
'''value'''.
Both commands take an array name and an elem parameter, but, no string match is performed on elem.

~~ array incr

 > '''array incr''' ''var elem'' ?''value''? ?''init''?

The '''array incr''' subcommand would increment ''var''(''elem''), if
it exists, by ''value'', otherwise, initializes it to ''init''.  The
default for ''value'' is 1, and the default for ''init'' is 0.  The
subcommand will return the new value and will support both integer and
double values (based on the rules for addition in '''expr''').

~~ array value

 > '''array value''' ''var elem'' ?''value''? ?''init''?

The '''array value''' would just return the current contents of
''var''(''elem'') if it exists, or ''value'' otherwise.   If the
''init'' parameter resolves to true (as determined by
''Tcl_GetBooleanFromObj()'' of course), the variable is initialized to
''value'' if it doesn't already exist.  The default for ''value'' is
the empty string, and the default for ''init'' is false.

~ Reference Implementation

Following is a Tcl only implementation of the '''incr'''/'''value'''
subcommands:

|proc Array {cmd var elem {amt {}} {init 0}} {
|   # Implement the Array subcmds incr and value on var(elem):
|   #  - incr   increment a variable by amt or initialize
|   #           to init if undefined.
|   #  - value  return the value if defined, else return amt
|   #           initializing if init.
|   upvar $var uvar
|   if {[string match $cmd* incr]} {
|      if {$amt == {}} { set amt 1 }
|      if {[info exists uvar($elem)]} {
|         return [set uvar($elem) [expr {$uvar($elem)+$amt}]]
|      }

|      return [set uvar($elem) $init]
|   } elseif {[string match $cmd* value]} {
|      if {[info exists uvar($elem)]} {
|         return $uvar($elem)
|      }

|      if {$init} {
|         return [set uvar($elem) $amt]
|      }

|      return $amt
|   } else {
|      error "usage: Array incr|value var elem ?amt? ?init?"
|   }
|}



~Discussion

 * Wangnic notes:

 > '''array value''' ''var elem'' '''"" false''' can be written as
   '''array get''' ''var elem''

 > Array get returns name/value pairs.  Array value returns just the
   value.  Also if elem has a * in it, there may be multiple matches.

 * Hobbs notes:

 > [200] already rejected ''array values''

 > A single item is returned from ''array value'', not a list, as
   there is no string match on elem.

 > The problem domain is not list processing (which is expected to be
   relatively expensive), but rather frequency counting and set
   matching.

 * RHSeeger notes:

 > It would seem more consistant to push for the ''incr'' command to
   include a way to initialize a variable if it doesn't exist (as per
   [215] or the discussed options contained therein), rather than add
   an incr subcommand to array.

 > Being a fan or reintroducing the ''array values'' TIP (since the
   core mailing list indicates it was never fully rejected), I think
   ''array value'' might be a bit confusing, being only off by the
   lack of plurality. (I was one of the people pushing for [200]
   though, so take that aspect with a grain of salt)

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|
|


|

|



|



|

|
|


|

|

|
|
|

|

|

|

|
|
|
|
|
|

|

|


|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
<
>
|
|
|
<
<
|
>
>
|



|
|

|
|



|

|


|
|




|
|
|


|
|
|
|
|

|


>

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

# TIP 224: Add New [array] Subcommands 'incr' and 'value'

	Author:         Peter MacDonald <[email protected]>
	Author:         Robert Seeger <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        28-Sep-2004
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

The TIP proposes the addition to two new subcommands to the
**array** command: **incr** and **value**.  The **incr_
subcommand would increment an element in an array.  The **value**
subcommand would query, reference, and/or initialize an array element.

# Rationale

[[215]](215.md) proposed modifying the **incr** command to auto-initialize
variables which do not exist, rather than throwing an error.  After
some debate, it was identified that frequency counting in arrays was
the primary area of interest.  In particular, the excessive use of
_if/info exists_ constructs in such code is inefficient, verbose and
rather difficult to read.  The addition of these two subcommands could
substantially reduce the complexity of much Tcl code.

# Specification

Two new subcommands will be added to **array**, being **incr** and
**value**.
Both commands take an array name and an elem parameter, but, no string match is performed on elem.

## array incr

 > **array incr** _var elem_ ?_value_? ?_init_?

The **array incr** subcommand would increment _var_\(_elem_\), if
it exists, by _value_, otherwise, initializes it to _init_.  The
default for _value_ is 1, and the default for _init_ is 0.  The
subcommand will return the new value and will support both integer and
double values \(based on the rules for addition in **expr**\).

## array value

 > **array value** _var elem_ ?_value_? ?_init_?

The **array value** would just return the current contents of
_var_\(_elem_\) if it exists, or _value_ otherwise.   If the
_init_ parameter resolves to true \(as determined by
_Tcl\_GetBooleanFromObj\(\)_ of course\), the variable is initialized to
_value_ if it doesn't already exist.  The default for _value_ is
the empty string, and the default for _init_ is false.

# Reference Implementation

Following is a Tcl only implementation of the **incr**/**value**
subcommands:

	proc Array {cmd var elem {amt {}} {init 0}} {
	   # Implement the Array subcmds incr and value on var(elem):
	   #  - incr   increment a variable by amt or initialize
	   #           to init if undefined.
	   #  - value  return the value if defined, else return amt
	   #           initializing if init.
	   upvar $var uvar
	   if {[string match $cmd* incr]} {
	      if {$amt == {}} { set amt 1 }
	      if {[info exists uvar($elem)]} {
	         return [set uvar($elem) [expr {$uvar($elem)+$amt}]]

	      }
	      return [set uvar($elem) $init]
	   } elseif {[string match $cmd* value]} {
	      if {[info exists uvar($elem)]} {
	         return $uvar($elem)

	      }
	      if {$init} {
	         return [set uvar($elem) $amt]

	      }
	      return $amt
	   } else {
	      error "usage: Array incr|value var elem ?amt? ?init?"


	   }
	}

# Discussion

 * Wangnic notes:

	 > **array value** _var elem_ **"" false** can be written as
   **array get** _var elem_

	 > Array get returns name/value pairs.  Array value returns just the
   value.  Also if elem has a \* in it, there may be multiple matches.

 * Hobbs notes:

	 > [[200]](200.md) already rejected _array values_

	 > A single item is returned from _array value_, not a list, as
   there is no string match on elem.

	 > The problem domain is not list processing \(which is expected to be
   relatively expensive\), but rather frequency counting and set
   matching.

 * RHSeeger notes:

	 > It would seem more consistant to push for the _incr_ command to
   include a way to initialize a variable if it doesn't exist \(as per
   [[215]](215.md) or the discussed options contained therein\), rather than add
   an incr subcommand to array.

	 > Being a fan or reintroducing the _array values_ TIP \(since the
   core mailing list indicates it was never fully rejected\), I think
   _array value_ might be a bit confusing, being only off by the
   lack of plurality. \(I was one of the people pushing for [[200]](200.md)
   though, so take that aspect with a grain of salt\)

# Copyright

This document has been placed in the public domain.

Name change from tip/225.tip to tip/225.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
136
137
138
139
140
141
142

143
144
145
146
147
148
149
150
151
152
153

154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

230
231
232
233
234
235

236
237
238
239

240
241

242
243
244
245
246
247
248
249
250
251
252
253

TIP:            225
Title:          Arithmetic Series with Optimized Space Complexity
Version:        $Revision: 1.14 $
Author:         Salvatore Sanfilippo <[email protected]>
Author:         Miguel Sofer <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        25-Oct-2004
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes to add a new command to generate arithmetic
sequences as Tcl lists that may be stored in constant space in many
practical situations.  The only change from the point of view of the
Tcl programmer is the addition of a new command named '''range'''.

~ Rationale

An idiomatic way to assign successive elements of an arithmetic series
to a variable is to use the '''for''' command. Usually the loop
variable is initialized to the first element of the sequence, and
incremented at every iteration of a given step using '''incr'''. The
'''for''' test condition is used to limit the sequence generation to a
given element, like in the following example:

|for {set i 0} {$i < 10} {incr i} {
|    puts $i
|}


The Tcl programming language is at higher level than the C language,
where this idiom firstly appeared, so it may be desiderable to be able
to generate arithmetic sequences of integer numbers in a more
comfortable way. Being the Tcl list a central data structure of the
Tcl language, it apperas natural to generate a Tcl list of integers,
and possibly use the '''foreach''' command to loop over every element,
so that the above '''for''' loop can be translated into the following
fragment of code:

|foreach i [range 0 10] {
|    puts $i
|}


The '''range''' command can be also conveniently used in different
contexts. The following code generates a list of squares of 0, 1, 2,
3, ... 9.

|proc map {varname script mylist} {
|    upvar $varname var
|    set res {}
|    foreach var $mylist {
|        lappend res [uplevel 1 $script]
|    }

|    return $res
|}

|
|puts [map x {expr {$x*$x}} [range 0 10]]
|
|# Will output "0 1 4 9 16 25 36 49 64 81"

The '''range''' command can be implemented in a way that makes it
possible to internally store the arithmetic sequences genereated in
constant space if they are only accessed using '''foreach''',
'''llength''' and '''lindex''' commands ('''lrange''' may also be
handled in a special way).  When needed, the object will be converted
into a List object automatically.  From the Tcl programmer point of
view this optimization is transparent.

~ Specification of the Behaviour

The '''range''' command takes three arguments in the complete format,
named ''start'', ''end'' and ''step'', and generates a sequence of
integers accordingly to the following algorithm in pseudo code:

|RangeLen(start, end, step)
|1. if step = 0
|2.     then ERROR
|3. if start = end
|4.     then return 0
|5. if step > 0 AND start > end
|6.     then ERROR
|7. if setp < 0 AND end > start
|8.     then ERROR
|9. return 1+((ABS(end-start)-1)/ABS(step))
|
|Range(start, end, step)
|1. result <- EMPTY LIST
|2. len <- RangeLen(start, end, step)
|3. for i <- 0 to len - 1
|4.     result.append(start+(i*step))
|6. return result

The ''step'' argument can be omitted, and default to the value of 1,
so [['''range''' 0 10 1]] is the same as [['''range''' 0 10]]. It's
also possible to call the '''range''' command with a single argument,
omitting both the ''start'' and ''step'' argument that will default
respectively to 0 and 1, so that the following three commands will
generate the same sequence of integers:

|range 0 10 1
|range 0 10
|range 10

The following are examples of outputs.

|[range 0 10 1] => 0 1 2 3 4 5 6 7 8 9
|[range 10 0 -2] => 10 8 6 4 2
|[range 10 10] => empty list
|[range 10 20 -3] => ERROR
|[range 5] -> 0 1 2 3 4

Infinite series and series resulting in lists bigger than the maximum
list length that the Tcl code can handle are detected and reported as
an error. ''start'', ''end'', and ''step'' can be anything can fit
into a Tcl wide integer.

Note that there is a practical justification for the fact that the
elements generated never reach the value of the End argument, with the
effect of [['''range''' 0 10 1]] generating the sequence 0, 1, 2, ...,
9 and a range with the same value of ''start'' and ''end'' always
generating an emtpy list. This is needed in order to make it
comfortable to use '''range''' and '''foreach''' instead of '''for'''
loops like in the following example:

|foreach i [range [llength $mylist]] {
|    foobar [lindex $mylist $i]
|}


Because Tcl indexes are mostly zero-based, and it is often useful to
access every element of a sequence given it's length, this appears to
be the more sensible behaviour (this semantic is very similar to the
range() function of the Python programming language, where range() is
fully used to replace C-like ''for'' loops.)

Unfortunately this behaviour is not as comfortable to run the indexes
in reverse order:

|foreach i [range [expr {[llength $mylist]-1}] -1 -1] {
|    foobar [lindex $mylist $i]
|}


But the access from the first to the last element is far more common
in programs, and the range command needs to be consistent when the
step is negative.

An alternative syntax for reverse-indexing is:

|foreach i [range [llength $mylist]] {
|   foobar [lindex $mylist end-$i]
|}


~ Proposed Change

The change proposed is to modify the Tcl core in order to handle a new
object type called ArithSeries, that is recongnized and handled as a
special case by at least the '''llength''', '''lindex''' and
'''foreach''' commands. Syntactically, the ArithSeries object will
have the string representation that is exactly that that would be
produced by creating a list with the elements that would be iterated
over by '''foreach''' as previously described. This TIP also proposes
to add logic into ''SetListFromAny'' method of the List type in order
to convert an Arithmetic Series object into a List directly without to
pass from the string representation.

This TIP proposes to add a '''range''' command to the Tcl core having
the semantics specified above, and returning an Arithmetic Series
object.  Formally, the syntax is:

 > '''range''' ?''start''? ''end'' ?''step''?

The proposed changes are available as a Patch against HEAD that can be
found in the SourceForge Tcl patch 1052584
[http://sf.net/tracker/?func=detail&aid=1052584&group_id=10894&atid=310894]

~ Copyright

This document has been placed in the public domain.

----

~ Appendix: Reference Pure-Tcl Implementation

It may be useful to test the behaviour of the '''range''' command
without having to apply the Patch, so the following is a pure Tcl
implementation that should be exactly equivalent in the semantic to
the specification in this TIP, but of course not able to store ranges
in O(1) space.

|# RangeLen(start, end, step)
|# 1. if step = 0
|# 2.     then ERROR
|# 3. if start = end
|# 4.     then return 0
|# 5. if step > 0 AND start > end
|# 6.     then ERROR
|# 7. if setp < 0 AND end > start
|# 8.     then ERROR
|# 9. return 1+((ABS(end-start)-1)/ABS(step))
|proc rangeLen {start end step} {
|    if {$step == 0} {return -1}
|    if {$start == $end} {return 0}
|    if {$step > 0 && $start > $end} {return -1}
|    if {$step < 0 && $end > $start} {return -1}
|    expr {1+((abs($end-$start)-1)/abs($step))}
|}

|
|# Range(start, end, step)
|# 1. result <- EMPTY LIST
|# 2. len <- RangeLen(start, end, step)
|# 3. for i <- 0 to len - 1
|# 4.     result.append(start+(i*step))
|# 6. return result
|proc range args {
|    # Check arity
|    set l [llength $args]
|    if {$l == 1} {
|        set start 0
|        set step 1
|        set end [lindex $args 0]
|    } elseif {$l == 2} {
|        set step 1
|        foreach {start end} $args break
|    } elseif {$l == 3} {
|        foreach {start end step} $args break
|    } else {
|        error {wrong # of args: should be "range ?start? end ?step?"}
|    }

|
|    # Generate the range
|    set rlen [rangeLen $start $end $step]
|    if {$rlen == -1} {
|        error {invalid (infinite?) range specified}
|    }

|    set result {}
|    for {set i 0} {$i < $rlen} {incr i} {
|        lappend result [expr {$start+($i*$step)}]
|    }

|    return $result
|}


----

~ Appendix: Discussion

Does the TIP include a C-level api to ranges, or are they transparent also in C - in the sense that they are addressable with any of the list-oriented functions of the Tcl api? What if any changes and caveats are necessary in the documentation of Tcl's C api? ''Miguel''

Ranges are transparent to C level too, in the proposed patch,
because the logic is put inside the commands,
so directly in the code implementing lindex, foreach, ...
In all the other cases, when a SetListFromAny() call occurs the
range is converted into a normal Tcl list object. ''Salvatore''

<
|
<
|
|
|
|
|
|
|
|
>

|




|

|


|

|
|


|
|
<
>






|
|


|
|
<
|
>
|



|
|
|
|
|
<
>
|
<
>
|
|
|
|

|

|
|
|



|

|
|


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|



|
|
|



|
|
|
|
|



|




|
|

|


|
|
<
>



|
|
|




|
|
<
>







|
|
<
|
>
|



|
|


|
|



|



|



|

|





|

|



|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
<
>
|
<
>



|

|




|
|
>

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
136
137
138
139
140

141
142
143
144
145
146
147
148
149
150

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205

206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

228
229
230
231
232
233

234
235
236
237

238
239

240
241
242
243
244
245
246
247
248
249
250
251
252
253

# TIP 225: Arithmetic Series with Optimized Space Complexity

	Author:         Salvatore Sanfilippo <[email protected]>
	Author:         Miguel Sofer <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        25-Oct-2004
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to add a new command to generate arithmetic
sequences as Tcl lists that may be stored in constant space in many
practical situations.  The only change from the point of view of the
Tcl programmer is the addition of a new command named **range**.

# Rationale

An idiomatic way to assign successive elements of an arithmetic series
to a variable is to use the **for** command. Usually the loop
variable is initialized to the first element of the sequence, and
incremented at every iteration of a given step using **incr**. The
**for** test condition is used to limit the sequence generation to a
given element, like in the following example:

	for {set i 0} {$i < 10} {incr i} {
	    puts $i

	}

The Tcl programming language is at higher level than the C language,
where this idiom firstly appeared, so it may be desiderable to be able
to generate arithmetic sequences of integer numbers in a more
comfortable way. Being the Tcl list a central data structure of the
Tcl language, it apperas natural to generate a Tcl list of integers,
and possibly use the **foreach** command to loop over every element,
so that the above **for** loop can be translated into the following
fragment of code:

	foreach i [range 0 10] {
	    puts $i

	}

The **range** command can be also conveniently used in different
contexts. The following code generates a list of squares of 0, 1, 2,
3, ... 9.

		proc map {varname script mylist} {
		    upvar $varname var
		    set res {}
		    foreach var $mylist {
		        lappend res [uplevel 1 $script]

		    }
		    return $res

		}
		
		puts [map x {expr {$x*$x}} [range 0 10]]
		
		# Will output "0 1 4 9 16 25 36 49 64 81"

The **range** command can be implemented in a way that makes it
possible to internally store the arithmetic sequences genereated in
constant space if they are only accessed using **foreach**,
**llength** and **lindex** commands \(**lrange** may also be
handled in a special way\).  When needed, the object will be converted
into a List object automatically.  From the Tcl programmer point of
view this optimization is transparent.

# Specification of the Behaviour

The **range** command takes three arguments in the complete format,
named _start_, _end_ and _step_, and generates a sequence of
integers accordingly to the following algorithm in pseudo code:

	RangeLen(start, end, step)
	1. if step = 0
	2.     then ERROR
	3. if start = end
	4.     then return 0
	5. if step > 0 AND start > end
	6.     then ERROR
	7. if setp < 0 AND end > start
	8.     then ERROR
	9. return 1+((ABS(end-start)-1)/ABS(step))
	
	Range(start, end, step)
	1. result <- EMPTY LIST
	2. len <- RangeLen(start, end, step)
	3. for i <- 0 to len - 1
	4.     result.append(start+(i*step))
	6. return result

The _step_ argument can be omitted, and default to the value of 1,
so [**range** 0 10 1] is the same as [**range** 0 10]. It's
also possible to call the **range** command with a single argument,
omitting both the _start_ and _step_ argument that will default
respectively to 0 and 1, so that the following three commands will
generate the same sequence of integers:

	range 0 10 1
	range 0 10
	range 10

The following are examples of outputs.

	[range 0 10 1] => 0 1 2 3 4 5 6 7 8 9
	[range 10 0 -2] => 10 8 6 4 2
	[range 10 10] => empty list
	[range 10 20 -3] => ERROR
	[range 5] -> 0 1 2 3 4

Infinite series and series resulting in lists bigger than the maximum
list length that the Tcl code can handle are detected and reported as
an error. _start_, _end_, and _step_ can be anything can fit
into a Tcl wide integer.

Note that there is a practical justification for the fact that the
elements generated never reach the value of the End argument, with the
effect of [**range** 0 10 1] generating the sequence 0, 1, 2, ...,
9 and a range with the same value of _start_ and _end_ always
generating an emtpy list. This is needed in order to make it
comfortable to use **range** and **foreach** instead of **for**
loops like in the following example:

	foreach i [range [llength $mylist]] {
	    foobar [lindex $mylist $i]

	}

Because Tcl indexes are mostly zero-based, and it is often useful to
access every element of a sequence given it's length, this appears to
be the more sensible behaviour \(this semantic is very similar to the
range\(\) function of the Python programming language, where range\(\) is
fully used to replace C-like _for_ loops.\)

Unfortunately this behaviour is not as comfortable to run the indexes
in reverse order:

	foreach i [range [expr {[llength $mylist]-1}] -1 -1] {
	    foobar [lindex $mylist $i]

	}

But the access from the first to the last element is far more common
in programs, and the range command needs to be consistent when the
step is negative.

An alternative syntax for reverse-indexing is:

	foreach i [range [llength $mylist]] {
	   foobar [lindex $mylist end-$i]

	}

# Proposed Change

The change proposed is to modify the Tcl core in order to handle a new
object type called ArithSeries, that is recongnized and handled as a
special case by at least the **llength**, **lindex** and
**foreach** commands. Syntactically, the ArithSeries object will
have the string representation that is exactly that that would be
produced by creating a list with the elements that would be iterated
over by **foreach** as previously described. This TIP also proposes
to add logic into _SetListFromAny_ method of the List type in order
to convert an Arithmetic Series object into a List directly without to
pass from the string representation.

This TIP proposes to add a **range** command to the Tcl core having
the semantics specified above, and returning an Arithmetic Series
object.  Formally, the syntax is:

 > **range** ?_start_? _end_ ?_step_?

The proposed changes are available as a Patch against HEAD that can be
found in the SourceForge Tcl patch 1052584
<http://sf.net/tracker/?func=detail&aid=1052584&group_id=10894&atid=310894> 

# Copyright

This document has been placed in the public domain.

----

# Appendix: Reference Pure-Tcl Implementation

It may be useful to test the behaviour of the **range** command
without having to apply the Patch, so the following is a pure Tcl
implementation that should be exactly equivalent in the semantic to
the specification in this TIP, but of course not able to store ranges
in O\(1\) space.

	# RangeLen(start, end, step)
	# 1. if step = 0
	# 2.     then ERROR
	# 3. if start = end
	# 4.     then return 0
	# 5. if step > 0 AND start > end
	# 6.     then ERROR
	# 7. if setp < 0 AND end > start
	# 8.     then ERROR
	# 9. return 1+((ABS(end-start)-1)/ABS(step))
	proc rangeLen {start end step} {
	    if {$step == 0} {return -1}
	    if {$start == $end} {return 0}
	    if {$step > 0 && $start > $end} {return -1}
	    if {$step < 0 && $end > $start} {return -1}
	    expr {1+((abs($end-$start)-1)/abs($step))}

	}
	
	# Range(start, end, step)
	# 1. result <- EMPTY LIST
	# 2. len <- RangeLen(start, end, step)
	# 3. for i <- 0 to len - 1
	# 4.     result.append(start+(i*step))
	# 6. return result
	proc range args {
	    # Check arity
	    set l [llength $args]
	    if {$l == 1} {
	        set start 0
	        set step 1
	        set end [lindex $args 0]
	    } elseif {$l == 2} {
	        set step 1
	        foreach {start end} $args break
	    } elseif {$l == 3} {
	        foreach {start end step} $args break
	    } else {
	        error {wrong # of args: should be "range ?start? end ?step?"}

	    }
	
	    # Generate the range
	    set rlen [rangeLen $start $end $step]
	    if {$rlen == -1} {
	        error {invalid (infinite?) range specified}

	    }
	    set result {}
	    for {set i 0} {$i < $rlen} {incr i} {
	        lappend result [expr {$start+($i*$step)}]

	    }
	    return $result

	}

----

# Appendix: Discussion

Does the TIP include a C-level api to ranges, or are they transparent also in C - in the sense that they are addressable with any of the list-oriented functions of the Tcl api? What if any changes and caveats are necessary in the documentation of Tcl's C api? _Miguel_

Ranges are transparent to C level too, in the proposed patch,
because the logic is put inside the commands,
so directly in the code implementing lindex, foreach, ...
In all the other cases, when a SetListFromAny\(\) call occurs the
range is converted into a normal Tcl list object. _Salvatore_

Name change from tip/226.tip to tip/226.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

TIP:            226
Title:          Interface to Save and Restore Interpreter State
Version:        $Revision: 1.5 $
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        30-Oct-2004
Post-History:   
Keywords:       Tcl
Tcl-Version:    8.5


~ Abstract

This TIP proposes new public C routines to allow the dynamic state
of an interp, including the return options, and error logging in progress
as well as the interp result, to be saved and later restored.

~ Background

The Tcl C library has long recognized the need for some routines
to be able to make use of a ''Tcl_Interp'' without leaving any
lasting footprints behind, and without interfering with whatever
operations that ''Tcl_Interp'' might be in the midst of performing.
The longstanding routines used to address this need have been
''Tcl_SaveResult'', ''Tcl_RestoreResult'', and ''Tcl_DiscardResult''.

These existing routines also have known limitations.  The documentation
warns that they should not be used when an error is in progress,
because they are not able to preserve the extra error information
in the ''Tcl_Interp'', only the result.

The existing routines are also showing their age.  Because they
focus on the result of the ''Tcl_Interp'', and because they date
from at least the Tcl 7 days, they spend an inordinate amount
of effort tending to the needs of the long-deprecated
''interp->result'' field.  Also, they make use of the transparent
definition of a public struct, ''Tcl_SavedResult'', and expect
the caller to allocate such structs itself, a practice now frowned
upon, and replaced with the use of opaque structs.

The Itcl extension has long worked around the limitations of
''Tcl_SaveResult'', etc. by defining its own set of routines
that more completely save and restore the state of a ''Tcl_Interp''.
These routines are ''Itcl_SaveInterpState'', ''Itcl_RestoreInterpState'',
and ''Itcl_DiscardInterpState''.  These routines are able to handle the
case of an error in progress, and have an interface making use of
an opaque struct, ''Itcl_InterpState''.  In order to create these
routines, however, the Itcl extension makes direct access to some of
the private fields of Tcl's ''Interp'' struct.

In Tcl 8.5, the proposal of [90] have already extended further
the values that make up the state of a ''Tcl_Interp'', including
a return level, and a dictionary of return options.  Also, some
of the internal fields of the ''Interp'' struct have been reworked,
so that the Itcl routines no longer function without modification.

It it time for Tcl to provide public interfaces that perform
the functions of the ''Itcl_*InterpState'' routines, and in fact,
Tcl should provide exactly those routines.

~ Proposal

Three new routines will be added to Tcl's public stub table:

 > Tcl_InterpState '''Tcl_SaveInterpState'''(Tcl_Interp *''interp'', int ''status'')

 > int '''Tcl_RestoreInterpState'''(Tcl_Interp *''interp'', Tcl_InterpState ''state'')

 > void '''Tcl_DiscardInterpState'''(Tcl_InterpState ''state'')

Also an opaque struct will be declared in '''tcl.h''':

 > typedef struct Tcl_InterpState_ *'''Tcl_InterpState''';

These routines are to have the same function as their existing
Itcl counterparts.

These declarations and routines already exist in the HEAD
of Tcl's development sources, but as private routines.  The Tcl
source code itself has already had an upgrade to replace all 
uses of the old ''Tcl_SaveResult'' calls with these new routines.
This TIP merely proposes making these routines available as
part of the public interface.

~ Compatibility

Strictly speaking, there are no compatibility issues, since these
are new additions to the public interface.

Callers of the ''Tcl_SaveResult'' family of routines should be
encouraged to update to use the new routines, as they perform
the same function and more.  The ''Tcl_SaveResult'' family of
routines should be kept in the public interface at least through
the Tcl 8 series of releases, though.  Consideration of their
removal for Tcl 9 is left for another proposal.

Itcl will have compatibility issues with Tcl 8.5 because of
the changes to the internal fields of Tcl's ''Interp'' struct.
Itcl should make use of these new routines as the implementation
of its corresponding routines whenever compiling against a
Tcl 8.5 set of headers.  When doing that, of course, version 8.5
of the Tcl stubs table will need to be required.

~ Reference Implementation

See Tcl Patch 1060579.

~ Comments

Please make any comments here.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|


|

|

|




|


|


|
|




|
|
|
|

|

|

|
|

|



|


|



|

|

|

|

|







|



|




|

|





|





|



|



|


>

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

# TIP 226: Interface to Save and Restore Interpreter State

	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        30-Oct-2004
	Post-History:   
	Keywords:       Tcl
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes new public C routines to allow the dynamic state
of an interp, including the return options, and error logging in progress
as well as the interp result, to be saved and later restored.

# Background

The Tcl C library has long recognized the need for some routines
to be able to make use of a _Tcl\_Interp_ without leaving any
lasting footprints behind, and without interfering with whatever
operations that _Tcl\_Interp_ might be in the midst of performing.
The longstanding routines used to address this need have been
_Tcl\_SaveResult_, _Tcl\_RestoreResult_, and _Tcl\_DiscardResult_.

These existing routines also have known limitations.  The documentation
warns that they should not be used when an error is in progress,
because they are not able to preserve the extra error information
in the _Tcl\_Interp_, only the result.

The existing routines are also showing their age.  Because they
focus on the result of the _Tcl\_Interp_, and because they date
from at least the Tcl 7 days, they spend an inordinate amount
of effort tending to the needs of the long-deprecated
_interp->result_ field.  Also, they make use of the transparent
definition of a public struct, _Tcl\_SavedResult_, and expect
the caller to allocate such structs itself, a practice now frowned
upon, and replaced with the use of opaque structs.

The Itcl extension has long worked around the limitations of
_Tcl\_SaveResult_, etc. by defining its own set of routines
that more completely save and restore the state of a _Tcl\_Interp_.
These routines are _Itcl\_SaveInterpState_, _Itcl\_RestoreInterpState_,
and _Itcl\_DiscardInterpState_.  These routines are able to handle the
case of an error in progress, and have an interface making use of
an opaque struct, _Itcl\_InterpState_.  In order to create these
routines, however, the Itcl extension makes direct access to some of
the private fields of Tcl's _Interp_ struct.

In Tcl 8.5, the proposal of [[90]](90.md) have already extended further
the values that make up the state of a _Tcl\_Interp_, including
a return level, and a dictionary of return options.  Also, some
of the internal fields of the _Interp_ struct have been reworked,
so that the Itcl routines no longer function without modification.

It it time for Tcl to provide public interfaces that perform
the functions of the _Itcl\_\*InterpState_ routines, and in fact,
Tcl should provide exactly those routines.

# Proposal

Three new routines will be added to Tcl's public stub table:

 > Tcl\_InterpState **Tcl\_SaveInterpState**\(Tcl\_Interp \*_interp_, int _status_\)

 > int **Tcl\_RestoreInterpState**\(Tcl\_Interp \*_interp_, Tcl\_InterpState _state_\)

 > void **Tcl\_DiscardInterpState**\(Tcl\_InterpState _state_\)

Also an opaque struct will be declared in **tcl.h**:

 > typedef struct Tcl\_InterpState\_ \***Tcl\_InterpState**;

These routines are to have the same function as their existing
Itcl counterparts.

These declarations and routines already exist in the HEAD
of Tcl's development sources, but as private routines.  The Tcl
source code itself has already had an upgrade to replace all 
uses of the old _Tcl\_SaveResult_ calls with these new routines.
This TIP merely proposes making these routines available as
part of the public interface.

# Compatibility

Strictly speaking, there are no compatibility issues, since these
are new additions to the public interface.

Callers of the _Tcl\_SaveResult_ family of routines should be
encouraged to update to use the new routines, as they perform
the same function and more.  The _Tcl\_SaveResult_ family of
routines should be kept in the public interface at least through
the Tcl 8 series of releases, though.  Consideration of their
removal for Tcl 9 is left for another proposal.

Itcl will have compatibility issues with Tcl 8.5 because of
the changes to the internal fields of Tcl's _Interp_ struct.
Itcl should make use of these new routines as the implementation
of its corresponding routines whenever compiling against a
Tcl 8.5 set of headers.  When doing that, of course, version 8.5
of the Tcl stubs table will need to be required.

# Reference Implementation

See Tcl Patch 1060579.

# Comments

Please make any comments here.

# Copyright

This document has been placed in the public domain.

Name change from tip/227.tip to tip/227.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

TIP:            227
Title:          Interface to Get and Set the Return Options of an Interpreter
Version:        $Revision: 1.5 $
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        30-Oct-2004
Post-History:   
Keywords:       Tcl
Tcl-Version:    8.5


~ Abstract

This TIP proposes new public C routines to allow the same access to
interpreter return options [90] as are provided at the script level
by the '''catch''' and '''return''' commands.

~ Background

In Tcl 8.5, the '''return''' command has aready been extended to
accept all option value pairs passed to it as arguments, to permit
extensions to augment any custom return code values with whatever
additional data values are appropriate.  The '''errorInfo''' and
'''errorCode''' values associated with the '''TCL_ERROR''' return
code are already converted to this mechanism.

The ability to set custom return options in the interp has been
limited to the script level though.  For extension commands
implemented entirely in C, it is inconvenient and somewhat
unreliable to perform a ''Tcl_Eval("return ...")'' to be able
to access this capability.

Likewise, the '''catch''' command is able to capture the
current set of return options in the interp, but doing so
requires both a script level command, and use of a variable.
Extension commands implemented in C are better served with
a direct interface to fetch the dictionary value.

~ Proposal

Two new routines will be added to Tcl's public stub table:

 > int '''Tcl_SetReturnOptions'''(Tcl_Interp *''interp'', Tcl_Obj *''options'')

 > Tcl_Obj *'''Tcl_GetReturnOptions'''(Tcl_Interp *''interp'', int ''result'')

These routines already exist in the HEAD of Tcl's development sources,
but as private routines.  The Tcl source code itself already makes calls
to these routines where appropriate, and their functioning is tested by
the test suite.  This TIP merely proposes making these routines available
as part of the public interface.

The ''Tcl_SetReturnOptions'' routine is essentially equivalent to
the '''return -options''' command.  The ''int'' value returned is
the return code that the '''return''' command would return given
the same options.  In fact, a valid implementation for the '''return'''
command would be:

| int Tcl_ReturnObjCmd(ClientData cd, Tcl_Interp *interp,
|			int objc, Tcl_Obj *const objv[])
| {

|     int explicitResult = (0 == (objc %2));
|     int numOptions = objc - 1 - explicitResult;
|     if (explicitResult) Tcl_SetObjResult(interp, objv[objc-1]);
|     return Tcl_SetReturnOptions(interp, Tcl_NewListObj(numOptions, objv+1));
| }

Note that ''Tcl_SetReturnOptions'' is like ''Tcl_SetObjResult''

and ''Tcl_SetVar2Ex'' in that you can pass it a newly created
Tcl_Obj confident that it will be freed later.  No refCount
manipulation is required.

The ''Tcl_GetReturnOptions'' routine is used by '''catch''' to
fetch the value to be stored in the ''optionsVarName'' variable,
if any.  The ''result'' argument should be whatever return code
was returned by the script evaluation, or other ''interp'' activity
whose return options you wish to retrieve.

The ''(Tcl_Obj *)'' returned by ''Tcl_GetReturnOptions'' points
to a newly created, unshared '''Tcl_Obj'''.  It can be written
to as returned; no need to implement copy-on-write checks.  In
particular, new key value pairs can be added to the dictionary,
or existing ones changed or removed.  As noted above, such a
value is also suitable for passing right back to ''Tcl_SetReturnOptions''.

~ Compatibility

Some extensions provide commands that offer the ability to evaluate a
Tcl script in some other context, and return the complete result of
that evaluation.  For example, the '''Thread''' package provides
the '''thread::send''' command that evaluates a script in another
interp in a different thread.  The '''thread::send''' command
ultimately has a return code and a result that matches those produced
by the script evaluation in the other thread.  Furthermore, the
'''::errorInfo''' and '''::errorCode''' variables are set according
to the script evaluation outcome in the other thread as well.
Extensions that accomplish such passing of full evaluation results
achieve it now with copies of all portions of the full evaluation results:
the return code, the interp result, and when appropriate, the values
of '''::errorInfo''' and '''::errorCode'''.  

Such mechanisms will continue to work unchanged in Tcl 8.5.
However, they will no longer represent the ''complete'' evaluation
results of the script.  In order to continue to communicate back
the full outcome of script evaluation, these extensions will want
to call ''Tcl_GetReturnOptions'' after the script completes,
transport that value back, and call ''Tcl_SetReturnOptions''
in the original interp.  Note that use of
these routines will automatically take care of '''::errorInfo'''
and '''::errorCode''', so the complete outcome of script evaluation
will be able to be communicated by the return code, the interp result,
and the dictionary of return options.  Because the return options
dictionary is itself extensible, this interface will not need to
change again.

~ Reference Implementation

See Tcl Patch 1060579.

~ Comments

Please make any comments here.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|
|

|

|


|
|





|


|





|



|

|







|
|
|
|


|
|
<
>
|
|
|
|
<
|
|
>
|
|


|
|
|
|


|
|



|

|



|
|
|


|




|


|


|
|

|
|





|



|



|


>

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

# TIP 227: Interface to Get and Set the Return Options of an Interpreter

	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        30-Oct-2004
	Post-History:   
	Keywords:       Tcl
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes new public C routines to allow the same access to
interpreter return options [[90]](90.md) as are provided at the script level
by the **catch** and **return** commands.

# Background

In Tcl 8.5, the **return** command has aready been extended to
accept all option value pairs passed to it as arguments, to permit
extensions to augment any custom return code values with whatever
additional data values are appropriate.  The **errorInfo** and
**errorCode** values associated with the **TCL\_ERROR** return
code are already converted to this mechanism.

The ability to set custom return options in the interp has been
limited to the script level though.  For extension commands
implemented entirely in C, it is inconvenient and somewhat
unreliable to perform a _Tcl\_Eval\("return ..."\)_ to be able
to access this capability.

Likewise, the **catch** command is able to capture the
current set of return options in the interp, but doing so
requires both a script level command, and use of a variable.
Extension commands implemented in C are better served with
a direct interface to fetch the dictionary value.

# Proposal

Two new routines will be added to Tcl's public stub table:

 > int **Tcl\_SetReturnOptions**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_options_\)

 > Tcl\_Obj \***Tcl\_GetReturnOptions**\(Tcl\_Interp \*_interp_, int _result_\)

These routines already exist in the HEAD of Tcl's development sources,
but as private routines.  The Tcl source code itself already makes calls
to these routines where appropriate, and their functioning is tested by
the test suite.  This TIP merely proposes making these routines available
as part of the public interface.

The _Tcl\_SetReturnOptions_ routine is essentially equivalent to
the **return -options** command.  The _int_ value returned is
the return code that the **return** command would return given
the same options.  In fact, a valid implementation for the **return**
command would be:

	 int Tcl_ReturnObjCmd(ClientData cd, Tcl_Interp *interp,
				int objc, Tcl_Obj *const objv[])

	 {
	     int explicitResult = (0 == (objc %2));
	     int numOptions = objc - 1 - explicitResult;
	     if (explicitResult) Tcl_SetObjResult(interp, objv[objc-1]);
	     return Tcl_SetReturnOptions(interp, Tcl_NewListObj(numOptions, objv+1));

	 }

Note that _Tcl\_SetReturnOptions_ is like _Tcl\_SetObjResult_
and _Tcl\_SetVar2Ex_ in that you can pass it a newly created
Tcl\_Obj confident that it will be freed later.  No refCount
manipulation is required.

The _Tcl\_GetReturnOptions_ routine is used by **catch** to
fetch the value to be stored in the _optionsVarName_ variable,
if any.  The _result_ argument should be whatever return code
was returned by the script evaluation, or other _interp_ activity
whose return options you wish to retrieve.

The _\(Tcl\_Obj \*\)_ returned by _Tcl\_GetReturnOptions_ points
to a newly created, unshared **Tcl\_Obj**.  It can be written
to as returned; no need to implement copy-on-write checks.  In
particular, new key value pairs can be added to the dictionary,
or existing ones changed or removed.  As noted above, such a
value is also suitable for passing right back to _Tcl\_SetReturnOptions_.

# Compatibility

Some extensions provide commands that offer the ability to evaluate a
Tcl script in some other context, and return the complete result of
that evaluation.  For example, the **Thread** package provides
the **thread::send** command that evaluates a script in another
interp in a different thread.  The **thread::send** command
ultimately has a return code and a result that matches those produced
by the script evaluation in the other thread.  Furthermore, the
**::errorInfo** and **::errorCode** variables are set according
to the script evaluation outcome in the other thread as well.
Extensions that accomplish such passing of full evaluation results
achieve it now with copies of all portions of the full evaluation results:
the return code, the interp result, and when appropriate, the values
of **::errorInfo** and **::errorCode**.  

Such mechanisms will continue to work unchanged in Tcl 8.5.
However, they will no longer represent the _complete_ evaluation
results of the script.  In order to continue to communicate back
the full outcome of script evaluation, these extensions will want
to call _Tcl\_GetReturnOptions_ after the script completes,
transport that value back, and call _Tcl\_SetReturnOptions_
in the original interp.  Note that use of
these routines will automatically take care of **::errorInfo**
and **::errorCode**, so the complete outcome of script evaluation
will be able to be communicated by the return code, the interp result,
and the dictionary of return options.  Because the return options
dictionary is itself extensible, this interface will not need to
change again.

# Reference Implementation

See Tcl Patch 1060579.

# Comments

Please make any comments here.

# Copyright

This document has been placed in the public domain.

Name change from tip/228.tip to tip/228.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
TIP:            228
Title:          Tcl Filesystem Reflection API
Version:        $Revision: 1.10 $
Author:         Andreas Kupries <[email protected]>
Author:         Andreas Kupries <[email protected]>
Author:         Vince Darley <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        02-Nov-2004
Post-History:   
Tcl-Version:    8.7


~ Abstract

This document describes an API which reflects the Filesystem Driver
API of the core Virtual Filesystem Layer up into the Tcl level, for
the implementation of filesystems in Tcl. It is an independent
companion to [219] ('Tcl Channel Reflection API') and [230] ('Tcl
Channel Transformation Reflection API'). As the latter TIPs bring the
ability of writing channel drivers and transformations in Tcl itself
into the core so this TIP provides the facilities for the
implementation of filesystems in Tcl. This document specifies version
''1'' of the filesystem reflection API.

~ Motivation / Rationale

The purpose of this and the other reflection TIPs is to provide all
the facilities required for the creation and usage of wrapped files (=
virtual filesystems attached to executables and binary libraries)
within the core.

While it is possible to implement and place all the proposed
reflectivity in separate and external packages, this however means
that the core itself cannot make use of wrapping technology and
virtual filesystems to encapsulate and attach its own data and library
files to itself. Something which is desirable as it can make the
<
|
<
|
|
|
|
|
|
|
|
|
>

|




|
|



|

|


|
|








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

# TIP 228: Tcl Filesystem Reflection API

	Author:         Andreas Kupries <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	Author:         Vince Darley <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        02-Nov-2004
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This document describes an API which reflects the Filesystem Driver
API of the core Virtual Filesystem Layer up into the Tcl level, for
the implementation of filesystems in Tcl. It is an independent
companion to [[219]](219.md) \('Tcl Channel Reflection API'\) and [[230]](230.md) \('Tcl
Channel Transformation Reflection API'\). As the latter TIPs bring the
ability of writing channel drivers and transformations in Tcl itself
into the core so this TIP provides the facilities for the
implementation of filesystems in Tcl. This document specifies version
_1_ of the filesystem reflection API.

# Motivation / Rationale

The purpose of this and the other reflection TIPs is to provide all
the facilities required for the creation and usage of wrapped files \(=
virtual filesystems attached to executables and binary libraries\)
within the core.

While it is possible to implement and place all the proposed
reflectivity in separate and external packages, this however means
that the core itself cannot make use of wrapping technology and
virtual filesystems to encapsulate and attach its own data and library
files to itself. Something which is desirable as it can make the
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
we managed to envision.

Another use for reflected filesystems is as a helper for testing the
generic filesystem layer of Tcl, by creating filesystems which
forcibly return errors, bogus data, and the like.

An implementation of this TIP exists already as a package,
'''TclVfs'''.  This TIP asks to make that mechanism publicly available
to script and package authors, with a bit of cleanup regarding the Tcl
level API.

~ Specification of Tcl-Level API

The Tcl level API consists of a single new command, '''filesystem''',
and one change to the existing command '''file'''.  The new command is
an ensemble command providing five subcommands. These subcommands are
'''mount''', '''unmount''', '''info''', '''posixerror''', and
'''internalerror'''.

(Note that this TIP does not introduce a new C API, but rather exposes
an existing C API to Tcl scripts.)

~~ The mount Subcommand

 > '''filesystem mount''' ?''-volume''? ''path cmdprefix''

This subcommand creates a new filesystem using the command prefix
''cmdprefix'' as its handler. The API this handler has to provide is
specified below, in the section "Command Handler API".

The new filesystem is immediately mounted at ''path''. After
completion of the call any access to a subdirectory of ''path'' will
be handled by that filesystem, through its handler. The filesystem is
represented here by the command prefix which will be executed whenever
an operation on a file or directory within path has to be performed.

If the option '''-volume''' is specified then the new mount point is
also registered with Tcl as a new volume and will therefore from then
on appear in the output of the command '''file volumes'''.

This is useful (and actually required for reasonable operation) when
mounting paths like '''ftp://'''. It should not be used for paths
mounted inside the native filesystem.

The new filesystem will be immediately accessible in ''all''
interpreters executed by the current process.

The command returns the empty string as its result. Returning a handle
or token is not required despite the fact that the handler command can
be used in more than one mount operation. The different instances can
be clearly distinguished through the ''root'' argument given to each
called method. This ''root'' is identical to the ''path'' specified
here. In other words, the chosen ''path'' (= mount point) is the
handle as well.

We have chosen to use ''early binding'' of the handler command. See
the section "Early versus late binding of the handler command" for
more detailed explanations.

'''Important note''': The handler command for the filesystem resides
in the interpreter performing the mount operation. This interpreter is
the '''filesystem interpreter''' mentioned in the section "Interaction
with threads and other interpreters".

~~ The unmount Subcommand

 > '''filesystem unmount''' ''path''

This methods unmounts the reflected filesystem which was mounted at
''path''. An error is thrown if no reflected filesystem was mounted at
that location. After the completion of the operation the filesystem
which was mounted at that location is not visible anymore, and any
previous filesystem accessible through this path becomes accessible
again.

The command returns the empty string as its result.

~~ The info Subcommand

 > '''filesystem info''' ?''path''?

This method will return a list of all filesystems mounted in all
interpreters, if it was called without arguments.

When called with a ''path'' the reflected filesystem responsible for
that path is examined and the command prefix used to handle all
filesystem operations is returned. An error is thrown if no reflected
filesystem is mounted for that path.

There is currently no facility to determine the '''filesystem
interpreter''' (nor its thread).

~~ The posixerror Subcommand

 > '''filesystem posixerror''' ''error''

This command can be called by a handler command during the execution
of a filesystem operation to signal the POSIX error code of a failure.
This also aborts execution immediately, behaving like '''return -code
-1'''.

The argument ''error'' is either the integer number of the POSIX error
to signal, or its symbolic name, like "EEXIST", "ENOENT", etc.

~~ The internalerror Subcommand

 > '''filesystem internalerror''' ''cmdprefix''

This method registers the provided command prefix as the command to
call when the core has to report internal errors thrown by a handler
command for a reflected filesystem.

If no such command is registered, then internal errors will stay
invisible, as the core currently does not provide a way for reporting
them through the regular VFS layer.

We have chosen to use ''early binding'' of the handler command. See
the section "Early versus late binding of the handler command" for
more detailed explanations.

~~ Modifications to the file Command

The existing command '''file'' is modified. Its method '''normalize'''
is extended to recognize a new switch, ''-full''. When this switch is
specified the method performs a normal expansion of ''path'' first ,
followed by an expansion of any links in the last element of ''path''.
It returns the result of the expansion as its own result.

The new signature of the method is

  * '''file normalize''' ?''-full''? ''path''

~ Command Handler API

The Tcl-level handler command for a reflected filesystem has to
support the following subcommands, as listed below. Note that the term
''ensemble'' is used to generically describe all command (prefixes)
which are able to process subcommands. This TIP is ''not'' tied to the
recently introduced 'namespace ensemble's.

There are three arguments whose meaning does not change across the
methods. They are explained now, and left out of the specifications of
the various methods.

 root: This is always the path the filesystem is mounted at, i.e. the
   handle of the filesystem. In other words, it is the part of the
   absolute path we are operating upon which is 'outside' of the
   control of this filesystem.

 relative: This is always the full path to the file or directory the
   operation has to work on, relative to ''root'' (s.a.). In other
   words, it is the part of the absolute path we are operating upon
   which is 'inside' of the control of the reflected filesystem.

 actualpath: This is the exact path which was given to the file
   command which caused the invocation of the handler command. This
   path can be absolute or relative. If it is absolute then
   ''actualpath'' is identical to "root/relative". Otherwise it can be
   a sub- or super-path of ''relative'', depending on the current
   working directory.

And finally the list of methods and their detailed specification.

~~ The initialize Method

 > ''handler'' '''initalize''' ''root''

This method is called first, and then never again (for the given
''root'').  Its responsibility is to initialize all parts of the
filesystem at the Tcl level.

The return value of the method has to be a list containing two
elements, the version of the reflection API, and a list containing the
names of all methods which are supported by this handler. Any error
thrown by the method will prevent the creation of the filesystem and
aborts the mount operation which caused the call. The thrown error
will appear as error thrown by '''filesystem mount'''.

The current version is ''1''.

~~ The finalize Method

 > ''handler'' '''finalize''' ''root''

The method is called when the filesystem was '''unmount'''ed, and is
the last call a handler can receive for a specific ''root''.  This
happens just before the destruction of the C level data structures.
Still, the command handler must not access the filesystem anymore in
no way. It is now his responsibility to clean up any internal
resources it allocated to this filesystem.

The return value of the method is ignored. Any error thrown by the
method is returned as the error of the '''unmount''' command.

~~ The access Method

 * ''handler'' '''access''' ''root relative actualpath mode''

This method is called to determine the "access" permissions for the
file (''relative'').

It has to either return successfully, or signal a POSIX error (See
'''filesystem posixerror'''. The latter means that the permissions
asked for via ''mode'' are not compatible with the file.

Any result returned by the method is ignored.

Regular errors thrown by the method are reported through the
registered handler for internal errors, if there is any. They are
ignored if no such handler is present.

The argument ''mode'' is a list containing any of the strings
'''read''', '''write''', and '''exe''', the permissions the file has
to have for the request to succeed.

  * '''write''' contained in ''mode'' implies "writable".

  * '''read''' contained in ''mode'' implies "readable".

  * '''exe''' contained in ''mode'' implies "executable".

~~ The createdirectory Method

 > ''handler'' '''createdirectory''' ''root relative actualpath''

This method has to create a directory with the given name
(''relative'').  The command can assume that ''relative'' does not
exist yet, but the directory ''relative'' is in does. The C level of
the reflection takes care of this.

Any result returned by the method is ignored.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

~~ The deletefile Method

 > ''handler'' '''deletefile''' ''root relative actualpath''

This method has to delete the file ''relative''.

Any result returned by the method is ignored.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

~~ The fileattributes Method

 > ''handler'' '''fileattributes''' ''root relative actualpath'' ?''index''? ?''value''?

The command has to return a list containing the names of all
acceptable attributes, if neither ''index'' nor ''value'' were
specified.

The command has to return the value of the ''index'''th attribute if
the ''index'' is specified, but not the ''value''. The attributes are
counted in the same order as their names appear in the list returned
by a call where neither ''index'' nor ''value'' were specified. The
first attribute is has the index 0.

The command has to set the value of the ''index'''th attribute to
''value'' if both ''index'' and ''value'' were specified for the call.
Any result returned by the method is ignored for this case.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

~~ The matchindirectory Method

 > ''handler''  '''matchindirectory''' ''root relative actualpath pattern types perm mac''

This method has to return the list of files or directories in the path
''relative'' which match the glob ''pattern'', are compatible with the
specified list of ''types'', have the given ''perm''issions and
''mac'' creator/type data. The specified path is always the name of an
existing directory.

'''Note''': As the core VFS layer generates requests for
directory-only matches from the filesystems involved when performing
any type of recursive globbing this subcommand absolutely has to
handle such (and file-only) requests correctly or bad things (TM) will
happen.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

''types'' is a list of strings, interpreted as set. The strings are
the names of the types of files the caller is looking for. Allowed
strings are: '''files''', and '''dirs'''. The command has to return
all files which match '''at least one''' of the types. If ''types'' is
empty then all types are valid.

''perm'' is a list of permission strings (i.e. a set), i.e.
'''read''', '''write''', and '''exe'''. The command has to return all
files which have '''at least all''' the given permissions. If ''perm''
is empty then no permissions are required.

''mac'' is a list containing 2 strings, for Macintosh creator and
type.  If ''mac'' is empty then the data is irrelevant.

~~ The open Method

 > ''handler'' '''open''' ''root relative actualpath mode permissions''

This command has to return a list describing the successfully opened
file ''relative'', or throw an error describing how the operation
failed. The thrown error will appear as error thrown by the ''open''
command which caused the invocation of the handler.

The list returned upon success contains at least one and at most two
elements. The first element is obligatory and is always the handle of
the channel which was created to allow access to the contents of the
file.

If the second element is present it will be interpreted as a callback,
i.e. a command prefix. This prefix will always be executed as is, i.e.
without additional arguments. Any required arguments have to be
returned as part of the result of the call to '''open'''. This
callback is fully specified in section "The channel close callback".

The argument ''mode'' specifies if the file is opened for read, write,
both, appending, etc. Its value is a string in the set '''r''',
'''w''', '''a''', '''w+''', or '''a+'''.

The argument ''permissions'' determines the native mode the opened
file is created with. This is relevant only if the ''mode'' actually
requests the creation of a non-existing file, i.e. is not '''r'''.

'''Note''': it is possible to return a channel implemented through
reflection here. See also section "The channel close callback" for
more.

~~ The removedirectory Method

 > ''handler'' '''removedirectory''' ''root relative actualpath recursive''

This method has to delete the given directory. The argument
''recursive'' is a boolean value. The method has to signal the POSIX
error "EEXIST" if ''recursive'' is '''false''' and the directory is
not empty. Otherwise it has to attempt to recursively delete the
directory and its contents.

Any result returned by the method is ignored.

Regular errors thrown by the method are reported through the
registered handler for internal errors, if there is any. They are
ignored if no such handler is present.

~~ The stat Method

 > ''handler'' '''stat''' ''root relative actualpath''

This method has to return a dictionary containing the stat structure
for the file ''relative''.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

The following keys and their values have to be provided by the
filesystem:

 dev: A long integer number, the device number of the path stat was
   called for. This number is optional and always overwritten by the C
   level of the filesystem reflection.

 ino: A long integer number, the inode number of the path stat was
   called for.

 mode: An integer number, the encoded access mode of the path. It is
   this mode which is checked by the method '''access'''.

 nlink: A long integer number, the number of hard links to the
   specified path.

 uid: A long integer number, the id of the user owning the virtual
   path.

 gid: A long integer number, the id of the user group the virtual path
   belongs to.

 size: A long integer number, the true size of the virtual path, in
   bytes.

 atime: A long integer number, the time of the latest access to the
   path, in seconds since the epoch. Convertible into a readable
   date/time by the command '''clock format'''.

 mtime: A long integer number, the time of the latest modification of
   the path, in seconds since the epoch. Convertible into a readable
   date/time by the command '''clock format'''.

 ctime: A long integer number, the time of the path was created, in
   seconds since the epoch. Convertible into a readable date/time by
   the command '''clock format'''.

 type: A string, either '''directory''', or '''file''', describing the
   type of the given path.

Notes: The stat data is highly Unix-centric, especially device node,
inode, and the various ids for file ownership.

While the latter are not that important both device and inode number
can be crucial to higher-level algorithms. An example would be a







|



|

|
|

|
|

|
|

|

|


|


|
|




|

|

|
|


|





|
|
|


|



|

|


|

|


|







|

|




|




|
|

|

|



|
|

|


|

|









|



|

|
|
|
|




|

|



|
|












|






|
|




|

|

|
|







|

|

|

|

|
|






|

|

|


|

|
|
|







|
|


|

|

|

|

|


|
|








|

|

|







|

|


|


|
|

|


|
|






|

|


|
|
|


|


|






|

|
|


|
|
|


|
|

|

|


|
|










|


|
|
|

|
|
|

|



|

|


|
|









|

|


|
















|















|



|



|

|







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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
we managed to envision.

Another use for reflected filesystems is as a helper for testing the
generic filesystem layer of Tcl, by creating filesystems which
forcibly return errors, bogus data, and the like.

An implementation of this TIP exists already as a package,
**TclVfs**.  This TIP asks to make that mechanism publicly available
to script and package authors, with a bit of cleanup regarding the Tcl
level API.

# Specification of Tcl-Level API

The Tcl level API consists of a single new command, **filesystem**,
and one change to the existing command **file**.  The new command is
an ensemble command providing five subcommands. These subcommands are
**mount**, **unmount**, **info**, **posixerror**, and
**internalerror**.

\(Note that this TIP does not introduce a new C API, but rather exposes
an existing C API to Tcl scripts.\)

## The mount Subcommand

 > **filesystem mount** ?_-volume_? _path cmdprefix_

This subcommand creates a new filesystem using the command prefix
_cmdprefix_ as its handler. The API this handler has to provide is
specified below, in the section "Command Handler API".

The new filesystem is immediately mounted at _path_. After
completion of the call any access to a subdirectory of _path_ will
be handled by that filesystem, through its handler. The filesystem is
represented here by the command prefix which will be executed whenever
an operation on a file or directory within path has to be performed.

If the option **-volume** is specified then the new mount point is
also registered with Tcl as a new volume and will therefore from then
on appear in the output of the command **file volumes**.

This is useful \(and actually required for reasonable operation\) when
mounting paths like **ftp://**. It should not be used for paths
mounted inside the native filesystem.

The new filesystem will be immediately accessible in _all_
interpreters executed by the current process.

The command returns the empty string as its result. Returning a handle
or token is not required despite the fact that the handler command can
be used in more than one mount operation. The different instances can
be clearly distinguished through the _root_ argument given to each
called method. This _root_ is identical to the _path_ specified
here. In other words, the chosen _path_ \(= mount point\) is the
handle as well.

We have chosen to use _early binding_ of the handler command. See
the section "Early versus late binding of the handler command" for
more detailed explanations.

**Important note**: The handler command for the filesystem resides
in the interpreter performing the mount operation. This interpreter is
the **filesystem interpreter** mentioned in the section "Interaction
with threads and other interpreters".

## The unmount Subcommand

 > **filesystem unmount** _path_

This methods unmounts the reflected filesystem which was mounted at
_path_. An error is thrown if no reflected filesystem was mounted at
that location. After the completion of the operation the filesystem
which was mounted at that location is not visible anymore, and any
previous filesystem accessible through this path becomes accessible
again.

The command returns the empty string as its result.

## The info Subcommand

 > **filesystem info** ?_path_?

This method will return a list of all filesystems mounted in all
interpreters, if it was called without arguments.

When called with a _path_ the reflected filesystem responsible for
that path is examined and the command prefix used to handle all
filesystem operations is returned. An error is thrown if no reflected
filesystem is mounted for that path.

There is currently no facility to determine the **filesystem
interpreter** \(nor its thread\).

## The posixerror Subcommand

 > **filesystem posixerror** _error_

This command can be called by a handler command during the execution
of a filesystem operation to signal the POSIX error code of a failure.
This also aborts execution immediately, behaving like **return -code
-1**.

The argument _error_ is either the integer number of the POSIX error
to signal, or its symbolic name, like "EEXIST", "ENOENT", etc.

## The internalerror Subcommand

 > **filesystem internalerror** _cmdprefix_

This method registers the provided command prefix as the command to
call when the core has to report internal errors thrown by a handler
command for a reflected filesystem.

If no such command is registered, then internal errors will stay
invisible, as the core currently does not provide a way for reporting
them through the regular VFS layer.

We have chosen to use _early binding_ of the handler command. See
the section "Early versus late binding of the handler command" for
more detailed explanations.

## Modifications to the file Command

The existing command **file_ is modified. Its method **normalize**
is extended to recognize a new switch, _-full_. When this switch is
specified the method performs a normal expansion of _path_ first ,
followed by an expansion of any links in the last element of _path_.
It returns the result of the expansion as its own result.

The new signature of the method is

  * **file normalize** ?_-full_? _path_

# Command Handler API

The Tcl-level handler command for a reflected filesystem has to
support the following subcommands, as listed below. Note that the term
_ensemble_ is used to generically describe all command \(prefixes\)
which are able to process subcommands. This TIP is _not_ tied to the
recently introduced 'namespace ensemble's.

There are three arguments whose meaning does not change across the
methods. They are explained now, and left out of the specifications of
the various methods.

 root: This is always the path the filesystem is mounted at, i.e. the
   handle of the filesystem. In other words, it is the part of the
   absolute path we are operating upon which is 'outside' of the
   control of this filesystem.

 relative: This is always the full path to the file or directory the
   operation has to work on, relative to _root_ \(s.a.\). In other
   words, it is the part of the absolute path we are operating upon
   which is 'inside' of the control of the reflected filesystem.

 actualpath: This is the exact path which was given to the file
   command which caused the invocation of the handler command. This
   path can be absolute or relative. If it is absolute then
   _actualpath_ is identical to "root/relative". Otherwise it can be
   a sub- or super-path of _relative_, depending on the current
   working directory.

And finally the list of methods and their detailed specification.

## The initialize Method

 > _handler_ **initalize** _root_

This method is called first, and then never again \(for the given
_root_\).  Its responsibility is to initialize all parts of the
filesystem at the Tcl level.

The return value of the method has to be a list containing two
elements, the version of the reflection API, and a list containing the
names of all methods which are supported by this handler. Any error
thrown by the method will prevent the creation of the filesystem and
aborts the mount operation which caused the call. The thrown error
will appear as error thrown by **filesystem mount**.

The current version is _1_.

## The finalize Method

 > _handler_ **finalize** _root_

The method is called when the filesystem was **unmount**ed, and is
the last call a handler can receive for a specific _root_.  This
happens just before the destruction of the C level data structures.
Still, the command handler must not access the filesystem anymore in
no way. It is now his responsibility to clean up any internal
resources it allocated to this filesystem.

The return value of the method is ignored. Any error thrown by the
method is returned as the error of the **unmount** command.

## The access Method

 * _handler_ **access** _root relative actualpath mode_

This method is called to determine the "access" permissions for the
file \(_relative_\).

It has to either return successfully, or signal a POSIX error \(See
**filesystem posixerror**. The latter means that the permissions
asked for via _mode_ are not compatible with the file.

Any result returned by the method is ignored.

Regular errors thrown by the method are reported through the
registered handler for internal errors, if there is any. They are
ignored if no such handler is present.

The argument _mode_ is a list containing any of the strings
**read**, **write**, and **exe**, the permissions the file has
to have for the request to succeed.

  * **write** contained in _mode_ implies "writable".

  * **read** contained in _mode_ implies "readable".

  * **exe** contained in _mode_ implies "executable".

## The createdirectory Method

 > _handler_ **createdirectory** _root relative actualpath_

This method has to create a directory with the given name
\(_relative_\).  The command can assume that _relative_ does not
exist yet, but the directory _relative_ is in does. The C level of
the reflection takes care of this.

Any result returned by the method is ignored.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

## The deletefile Method

 > _handler_ **deletefile** _root relative actualpath_

This method has to delete the file _relative_.

Any result returned by the method is ignored.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

## The fileattributes Method

 > _handler_ **fileattributes** _root relative actualpath_ ?_index_? ?_value_?

The command has to return a list containing the names of all
acceptable attributes, if neither _index_ nor _value_ were
specified.

The command has to return the value of the _index**th attribute if
the _index_ is specified, but not the _value_. The attributes are
counted in the same order as their names appear in the list returned
by a call where neither _index_ nor _value_ were specified. The
first attribute is has the index 0.

The command has to set the value of the _index**th attribute to
_value_ if both _index_ and _value_ were specified for the call.
Any result returned by the method is ignored for this case.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

## The matchindirectory Method

 > _handler_  **matchindirectory** _root relative actualpath pattern types perm mac_

This method has to return the list of files or directories in the path
_relative_ which match the glob _pattern_, are compatible with the
specified list of _types_, have the given _perm_issions and
_mac_ creator/type data. The specified path is always the name of an
existing directory.

**Note**: As the core VFS layer generates requests for
directory-only matches from the filesystems involved when performing
any type of recursive globbing this subcommand absolutely has to
handle such \(and file-only\) requests correctly or bad things \(TM\) will
happen.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

_types_ is a list of strings, interpreted as set. The strings are
the names of the types of files the caller is looking for. Allowed
strings are: **files**, and **dirs**. The command has to return
all files which match **at least one** of the types. If _types_ is
empty then all types are valid.

_perm_ is a list of permission strings \(i.e. a set\), i.e.
**read**, **write**, and **exe**. The command has to return all
files which have **at least all** the given permissions. If _perm_
is empty then no permissions are required.

_mac_ is a list containing 2 strings, for Macintosh creator and
type.  If _mac_ is empty then the data is irrelevant.

## The open Method

 > _handler_ **open** _root relative actualpath mode permissions_

This command has to return a list describing the successfully opened
file _relative_, or throw an error describing how the operation
failed. The thrown error will appear as error thrown by the _open_
command which caused the invocation of the handler.

The list returned upon success contains at least one and at most two
elements. The first element is obligatory and is always the handle of
the channel which was created to allow access to the contents of the
file.

If the second element is present it will be interpreted as a callback,
i.e. a command prefix. This prefix will always be executed as is, i.e.
without additional arguments. Any required arguments have to be
returned as part of the result of the call to **open**. This
callback is fully specified in section "The channel close callback".

The argument _mode_ specifies if the file is opened for read, write,
both, appending, etc. Its value is a string in the set **r**,
**w**, **a**, **w\+**, or **a\+**.

The argument _permissions_ determines the native mode the opened
file is created with. This is relevant only if the _mode_ actually
requests the creation of a non-existing file, i.e. is not **r**.

**Note**: it is possible to return a channel implemented through
reflection here. See also section "The channel close callback" for
more.

## The removedirectory Method

 > _handler_ **removedirectory** _root relative actualpath recursive_

This method has to delete the given directory. The argument
_recursive_ is a boolean value. The method has to signal the POSIX
error "EEXIST" if _recursive_ is **false** and the directory is
not empty. Otherwise it has to attempt to recursively delete the
directory and its contents.

Any result returned by the method is ignored.

Regular errors thrown by the method are reported through the
registered handler for internal errors, if there is any. They are
ignored if no such handler is present.

## The stat Method

 > _handler_ **stat** _root relative actualpath_

This method has to return a dictionary containing the stat structure
for the file _relative_.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

The following keys and their values have to be provided by the
filesystem:

 dev: A long integer number, the device number of the path stat was
   called for. This number is optional and always overwritten by the C
   level of the filesystem reflection.

 ino: A long integer number, the inode number of the path stat was
   called for.

 mode: An integer number, the encoded access mode of the path. It is
   this mode which is checked by the method **access**.

 nlink: A long integer number, the number of hard links to the
   specified path.

 uid: A long integer number, the id of the user owning the virtual
   path.

 gid: A long integer number, the id of the user group the virtual path
   belongs to.

 size: A long integer number, the true size of the virtual path, in
   bytes.

 atime: A long integer number, the time of the latest access to the
   path, in seconds since the epoch. Convertible into a readable
   date/time by the command **clock format**.

 mtime: A long integer number, the time of the latest modification of
   the path, in seconds since the epoch. Convertible into a readable
   date/time by the command **clock format**.

 ctime: A long integer number, the time of the path was created, in
   seconds since the epoch. Convertible into a readable date/time by
   the command **clock format**.

 type: A string, either **directory**, or **file**, describing the
   type of the given path.

Notes: The stat data is highly Unix-centric, especially device node,
inode, and the various ids for file ownership.

While the latter are not that important both device and inode number
can be crucial to higher-level algorithms. An example would be a
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
other with regard to device ids this information will be generated by
the common C level of the filesystem reflection.

The inode numbers however have to be assigned by the filesystem
itself.

It is possible to make a higher-level algorithm depending on
device/inode data aware of the problem with virtual filesystems (and
has actually been done, see the Tcllib directory walker), this however
is a kludgey solution and should be avoided.

~~ The utime Method

 > ''handler'' '''utime''' ''root relative actualpath atime ctime mtime''

This method has to set the access and modification times of the file
''relative''. The access time is set to ''atime'', creation time to
''ctime'', and the modification time is set to ''mtime''.  The
arguments are positive integer numbers, the number of seconds since
the epoch.

Any result returned by the method is ignored.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

~~ The copyfile Method

 > ''handler'' '''copyfile''' ''root relative_src actualpath_src relative_dst
   actualpath_dst''

This method is optional. It has to create a copy of a file in the
filesystem under a different name, in the ''same'' filesystem. This
method is not for copying of files between different filesystems and
won't be called for such.

Any result returned by the method is ignored.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

If this method is not supported the core filesystem layer will fall
back to a Tcl & channel based method of copying the file.

The same fallback will happen if the method is available, but signals
the POSIX error "EXDEV".

~~ The copydir Method

 > ''handler'' '''copydir''' ''root relative_src actualpath_src relative_dst
   actualpath_dst''

This method is optional. It has to create a recursive copy of a
directory in the filesystem under a different name, in the '''same'''
filesystem. This method is not for copying of directories between
different filesystems and won't be called for such.

Any result returned by the method is ignored.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

If this method is not supported the core filesystem layer will fall
back to a Tcl based method of copying the directory file by file..

The same fallback will happen if the method is available, but signals
the POSIX error "EXDEV".

~~ The rename Method

 > ''handler'' '''rename''' ''root relative_src actualpath_src relative_dst
   actualpath_dst''

This method is optional. It has to rename a file in the filesystem,
giving it a different name in the '''same''' filesystem. This method
is not for the renaming of files between different filesystems and
won't be called for such.

Any result returned by the method is ignored.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

If this method is not supported the core filesystem layer will fall
back to a Tcl & channel based method of renaming the file.

The same fallback will happen if the method is available, but signals
the POSIX error "EXDEV".

~ Interaction with Threads and Other Interpreters.

Virtual filesystems in Tcl are process global structures. In other
words, they are seen and accessible by all interpreters, and all
threads in the current process. For filesystems implemented completely
at the C-level this is not that big a problem.

However a filesystem implemented based on the reflection here will







|
|


|

|


|
|









|

|
|


|















|

|
|


|















|

|
|


|















|







463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
other with regard to device ids this information will be generated by
the common C level of the filesystem reflection.

The inode numbers however have to be assigned by the filesystem
itself.

It is possible to make a higher-level algorithm depending on
device/inode data aware of the problem with virtual filesystems \(and
has actually been done, see the Tcllib directory walker\), this however
is a kludgey solution and should be avoided.

## The utime Method

 > _handler_ **utime** _root relative actualpath atime ctime mtime_

This method has to set the access and modification times of the file
_relative_. The access time is set to _atime_, creation time to
_ctime_, and the modification time is set to _mtime_.  The
arguments are positive integer numbers, the number of seconds since
the epoch.

Any result returned by the method is ignored.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

## The copyfile Method

 > _handler_ **copyfile** _root relative\_src actualpath\_src relative\_dst
   actualpath\_dst_

This method is optional. It has to create a copy of a file in the
filesystem under a different name, in the _same_ filesystem. This
method is not for copying of files between different filesystems and
won't be called for such.

Any result returned by the method is ignored.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

If this method is not supported the core filesystem layer will fall
back to a Tcl & channel based method of copying the file.

The same fallback will happen if the method is available, but signals
the POSIX error "EXDEV".

## The copydir Method

 > _handler_ **copydir** _root relative\_src actualpath\_src relative\_dst
   actualpath\_dst_

This method is optional. It has to create a recursive copy of a
directory in the filesystem under a different name, in the **same**
filesystem. This method is not for copying of directories between
different filesystems and won't be called for such.

Any result returned by the method is ignored.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

If this method is not supported the core filesystem layer will fall
back to a Tcl based method of copying the directory file by file..

The same fallback will happen if the method is available, but signals
the POSIX error "EXDEV".

## The rename Method

 > _handler_ **rename** _root relative\_src actualpath\_src relative\_dst
   actualpath\_dst_

This method is optional. It has to rename a file in the filesystem,
giving it a different name in the **same** filesystem. This method
is not for the renaming of files between different filesystems and
won't be called for such.

Any result returned by the method is ignored.

Errors thrown by the method are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

If this method is not supported the core filesystem layer will fall
back to a Tcl & channel based method of renaming the file.

The same fallback will happen if the method is available, but signals
the POSIX error "EXDEV".

# Interaction with Threads and Other Interpreters.

Virtual filesystems in Tcl are process global structures. In other
words, they are seen and accessible by all interpreters, and all
threads in the current process. For filesystems implemented completely
at the C-level this is not that big a problem.

However a filesystem implemented based on the reflection here will
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816

executing the driver functionality in the filesystem interpreter
instead. In the case of requests coming from a different thread the C
level part of the reflection will post specialized events to the
filesystem thread, essentially forwarding the invocations of the
driver.

When a thread or interpreter is deleted all filesystems mounted with
the '''filesystem mount''' command using this thread/interpreter as
their computing base will be automatically unmounted and deleted as
well. This pulls the rug out under the other thread(s) and/or
interpreter(s), this however cannot be avoided. Future accesses will
either fail because the virtual files are now missing, or will access
different files provided by a different filesystem now owning the
path.

~ Interaction with Safe Interpreters

The command '''filesystem''' is unsafe and safe interpreters are not
allowed to use it. The reason behind this restriction: The ability of
mounting filesystems gives a safe interpreter the ability to inject
code into a trusted interpreter. The mechanism is as follows:

 * An application using a trusted master interpreter and safe slaves
   for plugins reads and evaluates a file '''foo''' directly in the
   trusted interpreter.

 * A malicious plugin loaded into one of the safe slaves knows about
   this file '''foo''', and its actual location. It mounts a virtual
   filesystem using a driver which is part of its own code, over the
   directory '''foo''' is in.

 * When the trusted interpreter reads '''foo''', it does not go to the
   native filesystem anymore, but the mounted filesystem. In other
   words the driver in the slave provides the contents, the code which
   is executed in the trusted environment. From here on the slave can
   do anything it wishes in the trusted environment.

 * Access to any other file in the directory can be passed through
   unchanged to the filesystem originally owning the path.

~ The Channel Close Callback

The channel close callback is an optional callback which can be set up
by the Tcl layer when a file is opened. This is done in the '''open'''
method, by returning a 2-element list. The first element is the
channel handle as usual and the second element the command prefix of
the callback.

The command prefix is early-bound, i.e. the command will be resolved
when the callback is set up. The resolution happens in the current
context, and thus can be anywhere in the application. Because of this
it is strongly recommended to use a fully-qualified command name in
the callback.

The callback is executed in the current context of the operation which
caused the channel to close. It is executed just before the channel is
closed '''by the generic filesystem layer'''. The callback itself
'''must not''' call '''close'''. It will always be executed as is,
i.e. without additional arguments. Any required arguments have to be
made part of the prefix when it is set up.

The channel is still live enough at the time of the call to allow
'''seek''' and '''read''' operations. In addition all available data
will have been flushed into it already. This means, for example, that
the callback can seek to the beginning of the said channel, read its
contents and then store the gathered data elsewhere. In other words,
this callback is not only crucial to the cleanup of any resources
associated with an opened file, but also for the ability to implement
a filesystem which can be written to. This does assume that the
filesystem does not use a reflected channel to access the contents of
the virtual file. If a reflected channel is used however, the close
callback is not required, as the ''finalize'' method of the channel
can be used for the same purpose.

Under normal circumstances return code and any errors thrown by the
callback itself are ignored. In that case errors have to be signaled
asynchronously, for example by calling ''bgerror''.

Any result returned by the callback is ignored.

Errors thrown by the callback are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

'''Note''' that it is possible that the channel we are working with
here is implemented through reflection.

The order in which the various callbacks are called during closing is
this:

 * The channel for the file is closed via ''close'' by the VFS.

 * The channel close callback has been set up as a regular close
   handler, and is called now.

 * The close function of the channel driver is called, reflected into
   the Tcl level and cleans it up.

 * The close operation completes.

The important point here is that the channel close callback set up by
the filesystem is definitely called before the reflected channel
cleans up its Tcl layer, so the assertion above about the channel
being live enough to be read and saved from the filesystem Tcl layer
holds even if both filesystem and channel are reflected. It also holds
if reflected transformations are involved.

~ Early versus Late Binding of the Handler Command

We have two principal methods for using the handler command. These are
called early and late binding.

Early binding means that the command implementation to use is
determined at the time of the creation of the channel, i.e. when
''chan create'' is executed, before any methods are called. Afterward
it cannot change. The result of the command resolution is stored
internally and used until the channel is destroyed. Renaming the
handler command has no effect. In other words, the system will
automatically call the command under the new name. The destruction of
the handler command is intercepted and causes the channel to close as
well.

Late binding means that the handler command is stored internally
essentially as a string, and this string is mapped to the
implementation to use for each and every call to a method of the
handler. Renaming the command, or destroying it means that the next
call of a handler method will fail, causing the higher level channel
command to fail as well. Depending on the method the error message may
not be able to explain the reason of that failure.

Another problem with this approach is that the context for the
resolution of the command name has to be specified explicitly to avoid
problems with relative names. Early binding resolves once, in the
context of the ''chan create''. Late binding performs resolution
anywhere where channel commands like '''puts''', '''gets''', etc.  are
called, i.e. in a random context. To prevent problems with different
commands of the same name in several namespaces it becomes necessary
to force the usage of a specific fixed context for the resolution.

Note that moving a different command into place after renaming the
original handler allows the Tcl level to change the implementation
dynamically at runtime. This however is not really an advantage over
early binding as the early bound command can be written such that it
delegates to the actual implementation, and that can then be changed
dynamically as well.

~ Limitations

For now this section documents the existing limitations of the
reflection.

The code of the package '''TclVfs''' has only a few limitations.

 * One subtlety one has to be aware of is that mixing
   case-(in)sensitive filesystems and application code may yield
   unexpected results.

 > For example mounting a case-sensitive virtual filesystem into a
   case-insensitive system (like the standard Windows or MacOS
   filesystems) and then using this with code relying on
   case-insensitivity problems will appear when accessing the virtual
   filesystem.

 > Note that application code relying on case-insensitivity will not
   under Unix either, i.e. is inherently non-portable, and should be
   fixed.

 * The C-API's for the methods '''link''' and '''lstat''' are currently
   not exposed to the Tcl level. This may be done in the future to
   allow virtual filesystems implemented in Tcl to support the reading
   and writing of links.

 > '''Note''' - Exposure of links may require path normalization and
   native path generation, something the TclVfs implementation does
   not support. This limitation regarding any type of link, hard or or
   soft, is quite deeply entrenched in the TclVfs code.

 * The public C-API filesystem function '''Tcl_FSUtime''' is
   Unix-centric, its main data argument is a ''struct utimbuf *''. This
   structure contains only a single value for both ''atime'' and
   ''ctime''. The method '''utime''' of the handler command was
   nevertheless defined to take separate values for access and
   creation times, in case that this changes in the future.

 * The Tcl core VFS layer was written very near to regular filesystems
   and has no way to transport regular Tcl error messages through it.
   This is the reason for the introduction of the internal error
   callback. This problem cannot be fixed within the 8.5 line as it
   requires more extensive changes to the public API. Note that when
   such changes are done the reflection API has to change as well, as
   it then allows the direct passing of errors. At that point the C
   layer of the reflection will have to support both this and the new
   version of the API.

~ Examples of Filesystems

The filesystems provided by '''TclVfs''' are all examples.

 * webdav

 * ftp sites

 * http sites

 * zip archive

 * tar archive

 * metakit database

 * namespace/procedures as filesystem

 * widget fs

Some examples can be found on the Tcler's Wiki, see pages referring to
http://wiki.tcl.tk/11851

 * Encryption

 * Compression

 * Jails

 * Quotas

~ Reference Implementation

The package '''TclVfs'''[http://sourceforge.net/projects/tclvfs/] can
serve as the basis for a reference implementation. The final reference
implementation will be provided at SourceForge, as an entry in the Tcl
Patch Tracker. The exact url will be added here when it becomes
available.

~ Comments

Comments on [http://mini.net/tcl/12328] suggest it might be a good idea to modify the 'file attributes' callback to make it more efficient for vfs writers, especially across a network and when vfs's are stacked.  Currently one needs to make multiple calls to accomplish anything. 

  [[ Add comments on the document here ]]

~ Copyright

This document has been placed in the public domain.








|

|
|




|

|





|



|

|

|








|


|












|
|




|








|




|







|





|
















|






|


















|
|











|




|


|


|
|
|



|



|




|




|
|
|
|













|

|


















|









|

|





|

|

|

|


>
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
executing the driver functionality in the filesystem interpreter
instead. In the case of requests coming from a different thread the C
level part of the reflection will post specialized events to the
filesystem thread, essentially forwarding the invocations of the
driver.

When a thread or interpreter is deleted all filesystems mounted with
the **filesystem mount** command using this thread/interpreter as
their computing base will be automatically unmounted and deleted as
well. This pulls the rug out under the other thread\(s\) and/or
interpreter\(s\), this however cannot be avoided. Future accesses will
either fail because the virtual files are now missing, or will access
different files provided by a different filesystem now owning the
path.

# Interaction with Safe Interpreters

The command **filesystem** is unsafe and safe interpreters are not
allowed to use it. The reason behind this restriction: The ability of
mounting filesystems gives a safe interpreter the ability to inject
code into a trusted interpreter. The mechanism is as follows:

 * An application using a trusted master interpreter and safe slaves
   for plugins reads and evaluates a file **foo** directly in the
   trusted interpreter.

 * A malicious plugin loaded into one of the safe slaves knows about
   this file **foo**, and its actual location. It mounts a virtual
   filesystem using a driver which is part of its own code, over the
   directory **foo** is in.

 * When the trusted interpreter reads **foo**, it does not go to the
   native filesystem anymore, but the mounted filesystem. In other
   words the driver in the slave provides the contents, the code which
   is executed in the trusted environment. From here on the slave can
   do anything it wishes in the trusted environment.

 * Access to any other file in the directory can be passed through
   unchanged to the filesystem originally owning the path.

# The Channel Close Callback

The channel close callback is an optional callback which can be set up
by the Tcl layer when a file is opened. This is done in the **open**
method, by returning a 2-element list. The first element is the
channel handle as usual and the second element the command prefix of
the callback.

The command prefix is early-bound, i.e. the command will be resolved
when the callback is set up. The resolution happens in the current
context, and thus can be anywhere in the application. Because of this
it is strongly recommended to use a fully-qualified command name in
the callback.

The callback is executed in the current context of the operation which
caused the channel to close. It is executed just before the channel is
closed **by the generic filesystem layer**. The callback itself
**must not** call **close**. It will always be executed as is,
i.e. without additional arguments. Any required arguments have to be
made part of the prefix when it is set up.

The channel is still live enough at the time of the call to allow
**seek** and **read** operations. In addition all available data
will have been flushed into it already. This means, for example, that
the callback can seek to the beginning of the said channel, read its
contents and then store the gathered data elsewhere. In other words,
this callback is not only crucial to the cleanup of any resources
associated with an opened file, but also for the ability to implement
a filesystem which can be written to. This does assume that the
filesystem does not use a reflected channel to access the contents of
the virtual file. If a reflected channel is used however, the close
callback is not required, as the _finalize_ method of the channel
can be used for the same purpose.

Under normal circumstances return code and any errors thrown by the
callback itself are ignored. In that case errors have to be signaled
asynchronously, for example by calling _bgerror_.

Any result returned by the callback is ignored.

Errors thrown by the callback are reported through the registered
handler for internal errors, if there is any. They are ignored if no
such handler is present.

**Note** that it is possible that the channel we are working with
here is implemented through reflection.

The order in which the various callbacks are called during closing is
this:

 * The channel for the file is closed via _close_ by the VFS.

 * The channel close callback has been set up as a regular close
   handler, and is called now.

 * The close function of the channel driver is called, reflected into
   the Tcl level and cleans it up.

 * The close operation completes.

The important point here is that the channel close callback set up by
the filesystem is definitely called before the reflected channel
cleans up its Tcl layer, so the assertion above about the channel
being live enough to be read and saved from the filesystem Tcl layer
holds even if both filesystem and channel are reflected. It also holds
if reflected transformations are involved.

# Early versus Late Binding of the Handler Command

We have two principal methods for using the handler command. These are
called early and late binding.

Early binding means that the command implementation to use is
determined at the time of the creation of the channel, i.e. when
_chan create_ is executed, before any methods are called. Afterward
it cannot change. The result of the command resolution is stored
internally and used until the channel is destroyed. Renaming the
handler command has no effect. In other words, the system will
automatically call the command under the new name. The destruction of
the handler command is intercepted and causes the channel to close as
well.

Late binding means that the handler command is stored internally
essentially as a string, and this string is mapped to the
implementation to use for each and every call to a method of the
handler. Renaming the command, or destroying it means that the next
call of a handler method will fail, causing the higher level channel
command to fail as well. Depending on the method the error message may
not be able to explain the reason of that failure.

Another problem with this approach is that the context for the
resolution of the command name has to be specified explicitly to avoid
problems with relative names. Early binding resolves once, in the
context of the _chan create_. Late binding performs resolution
anywhere where channel commands like **puts**, **gets**, etc.  are
called, i.e. in a random context. To prevent problems with different
commands of the same name in several namespaces it becomes necessary
to force the usage of a specific fixed context for the resolution.

Note that moving a different command into place after renaming the
original handler allows the Tcl level to change the implementation
dynamically at runtime. This however is not really an advantage over
early binding as the early bound command can be written such that it
delegates to the actual implementation, and that can then be changed
dynamically as well.

# Limitations

For now this section documents the existing limitations of the
reflection.

The code of the package **TclVfs** has only a few limitations.

 * One subtlety one has to be aware of is that mixing
   case-\(in\)sensitive filesystems and application code may yield
   unexpected results.

	 > For example mounting a case-sensitive virtual filesystem into a
   case-insensitive system \(like the standard Windows or MacOS
   filesystems\) and then using this with code relying on
   case-insensitivity problems will appear when accessing the virtual
   filesystem.

	 > Note that application code relying on case-insensitivity will not
   under Unix either, i.e. is inherently non-portable, and should be
   fixed.

 * The C-API's for the methods **link** and **lstat** are currently
   not exposed to the Tcl level. This may be done in the future to
   allow virtual filesystems implemented in Tcl to support the reading
   and writing of links.

	 > **Note** - Exposure of links may require path normalization and
   native path generation, something the TclVfs implementation does
   not support. This limitation regarding any type of link, hard or or
   soft, is quite deeply entrenched in the TclVfs code.

 * The public C-API filesystem function **Tcl\_FSUtime** is
   Unix-centric, its main data argument is a _struct utimbuf \*_. This
   structure contains only a single value for both _atime_ and
   _ctime_. The method **utime** of the handler command was
   nevertheless defined to take separate values for access and
   creation times, in case that this changes in the future.

 * The Tcl core VFS layer was written very near to regular filesystems
   and has no way to transport regular Tcl error messages through it.
   This is the reason for the introduction of the internal error
   callback. This problem cannot be fixed within the 8.5 line as it
   requires more extensive changes to the public API. Note that when
   such changes are done the reflection API has to change as well, as
   it then allows the direct passing of errors. At that point the C
   layer of the reflection will have to support both this and the new
   version of the API.

# Examples of Filesystems

The filesystems provided by **TclVfs** are all examples.

 * webdav

 * ftp sites

 * http sites

 * zip archive

 * tar archive

 * metakit database

 * namespace/procedures as filesystem

 * widget fs

Some examples can be found on the Tcler's Wiki, see pages referring to
<http://wiki.tcl.tk/11851>

 * Encryption

 * Compression

 * Jails

 * Quotas

# Reference Implementation

The package **TclVfs**<http://sourceforge.net/projects/tclvfs/>  can
serve as the basis for a reference implementation. The final reference
implementation will be provided at SourceForge, as an entry in the Tcl
Patch Tracker. The exact url will be added here when it becomes
available.

# Comments

Comments on <http://mini.net/tcl/12328>  suggest it might be a good idea to modify the 'file attributes' callback to make it more efficient for vfs writers, especially across a network and when vfs's are stacked.  Currently one needs to make multiple calls to accomplish anything. 

  [ Add comments on the document here ]

# Copyright

This document has been placed in the public domain.

Name change from tip/229.tip to tip/229.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

TIP:		229
Title:		Scripted Control of Name Resolution in Namespaces
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Post-History:	
Version:	$Revision: 1.10 $
Author:		Donal K. Fellows <[email protected]>
Created:	03-Nov-2004


~ Abstract

This TIP proposes extensions to the '''namespace''' command to allow
scripts to control how individual namespaces map names to commands.

~ Rationale

Tcl has, for historic reasons, attracted many different styles of
object system, and a favoured mechanism for implementing objects is on
top of namespaces (which were introduced in Tcl 8.0 based on work done
previously in [[incr Tcl]]).  However, a common problem that these OO
systems face is the inability to make namespaces efficiently map names
of entities within classes etc. into the object instances.  This TIP
provides a simple mechanism for doing this.

No mechanism is provided for affecting the resolving of variable
names. Best practice is to ensure that variables not present in the
current namespace are imported explicitly through the '''upvar''' or
'''variable''' commands (depending on context) and the fact that there
is any possibility of non-local variable name resolution has been
behind a number of bugs in the core (e.g. Bug #981733).

~ Proposed Change

~~ Namespace Path Subcommand

The '''namespace''' command will gain a new subcommand, '''path''',
with the following syntax:

 > '''namespace path''' ?''list''?

This command sets and queries the current namespace's command name
resolution path. If ''list'' is present, '''namespace path''' sets the
path to the list of namespaces named in the list and returns the empty
string; all the namespaces must exist or an error is thrown. If no
''list'' argument is provided, '''namespace path''' doesn't change
anything and returns the current path.

~~ Updates to Other Commands

The '''info commands''' command shall be updated so that, when no
namespace is present in its pattern part, it shall return all
(matching) commands that are visible without namespace qualifiers at
this point. The '''info procs''' command will not be so modified.

~~ Name Path Behaviour

Only names without a leading namespace separator in them are resolved
using the namespace's path. When resolving command names, resolving
relative to the current namespace is always preferred (unless a
resolver is installed, of course), and resolution relative to the
global namespace is always done after resolving relative to everything
in the path (unless the global namespace is explicitly in the path,
when it happens earlier). This means that the old
behaviour is exactly what you get when the path is empty, and also
ensures that virtually all scripts continue to work when a path is
set; if it was possible to remove the global namespace from the actual
path (as opposed to the settable part), virtually all scripts would
break. If an extension installs a custom name resolver, that
completely overrides the command name resolution path mechanism (to
maximize backward-compatability; it is not anticipated that much code
will try to mix the two mechanisms in a namespace).

Note that each namespace's path is isolated from the path of every
other namespace, including the parent namespace. Systems using the
'''namespace path''' mechanism as part of an implementation of
inheritance will want to set up the path for each object namespace
explicitly (this value can be statically precomputed on a per-class
basis); indeed, where multiple inheritance is involved it will
probably be more efficient to compute the path than let Tcl guess.

The path is parsed completely at the time the '''namespace path'''
command is run, and the resulting list of namespaces is used
directly. If a namespace on some namespaces' path is deleted, it is
immediately excised from the path of every namespace that refers to
it.

~~ Examples

The following script returns "::foo":

|namespace eval ::foo {
|   proc boo {} {namespace current}
|   namespace eval bar {
|      namespace path ::foo
|      boo
|   }
|}



The following script return "::foo::bar":

|namespace eval ::foo {
|   proc boo {} {namespace current}
|   namespace eval bar {
|      proc boo {} {namespace current}
|   }

|   namesspace eval spong {
|      namespace path ::foo
|      bar::boo
|   }
|}



~ Implementation

A patch is available[http://sf.net/tracker/?func=detail&aid=1159942&group_id=10894&atid=310894].

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
>

|

|


|



|
|






|
|

|

|

|

|


|


|


|


|

|

|
|

|



|
|

|
|



|

|

|



|

|
|


|





|



|
|
|
|
|
<
<
|
>
>


|
|
|
|
<
>
|
|
|
<
<
|
>
>
|

|

|


>

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

# TIP 229: Scripted Control of Name Resolution in Namespaces
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	03-Nov-2004
-----

# Abstract

This TIP proposes extensions to the **namespace** command to allow
scripts to control how individual namespaces map names to commands.

# Rationale

Tcl has, for historic reasons, attracted many different styles of
object system, and a favoured mechanism for implementing objects is on
top of namespaces \(which were introduced in Tcl 8.0 based on work done
previously in [incr Tcl]\).  However, a common problem that these OO
systems face is the inability to make namespaces efficiently map names
of entities within classes etc. into the object instances.  This TIP
provides a simple mechanism for doing this.

No mechanism is provided for affecting the resolving of variable
names. Best practice is to ensure that variables not present in the
current namespace are imported explicitly through the **upvar** or
**variable** commands \(depending on context\) and the fact that there
is any possibility of non-local variable name resolution has been
behind a number of bugs in the core \(e.g. Bug \#981733\).

# Proposed Change

## Namespace Path Subcommand

The **namespace** command will gain a new subcommand, **path**,
with the following syntax:

 > **namespace path** ?_list_?

This command sets and queries the current namespace's command name
resolution path. If _list_ is present, **namespace path** sets the
path to the list of namespaces named in the list and returns the empty
string; all the namespaces must exist or an error is thrown. If no
_list_ argument is provided, **namespace path** doesn't change
anything and returns the current path.

## Updates to Other Commands

The **info commands** command shall be updated so that, when no
namespace is present in its pattern part, it shall return all
\(matching\) commands that are visible without namespace qualifiers at
this point. The **info procs** command will not be so modified.

## Name Path Behaviour

Only names without a leading namespace separator in them are resolved
using the namespace's path. When resolving command names, resolving
relative to the current namespace is always preferred \(unless a
resolver is installed, of course\), and resolution relative to the
global namespace is always done after resolving relative to everything
in the path \(unless the global namespace is explicitly in the path,
when it happens earlier\). This means that the old
behaviour is exactly what you get when the path is empty, and also
ensures that virtually all scripts continue to work when a path is
set; if it was possible to remove the global namespace from the actual
path \(as opposed to the settable part\), virtually all scripts would
break. If an extension installs a custom name resolver, that
completely overrides the command name resolution path mechanism \(to
maximize backward-compatability; it is not anticipated that much code
will try to mix the two mechanisms in a namespace\).

Note that each namespace's path is isolated from the path of every
other namespace, including the parent namespace. Systems using the
**namespace path** mechanism as part of an implementation of
inheritance will want to set up the path for each object namespace
explicitly \(this value can be statically precomputed on a per-class
basis\); indeed, where multiple inheritance is involved it will
probably be more efficient to compute the path than let Tcl guess.

The path is parsed completely at the time the **namespace path**
command is run, and the resulting list of namespaces is used
directly. If a namespace on some namespaces' path is deleted, it is
immediately excised from the path of every namespace that refers to
it.

## Examples

The following script returns "::foo":

	namespace eval ::foo {
	   proc boo {} {namespace current}
	   namespace eval bar {
	      namespace path ::foo
	      boo


	   }
	}

The following script return "::foo::bar":

	namespace eval ::foo {
	   proc boo {} {namespace current}
	   namespace eval bar {
	      proc boo {} {namespace current}

	   }
	   namesspace eval spong {
	      namespace path ::foo
	      bar::boo


	   }
	}

# Implementation

A patch is available<http://sf.net/tracker/?func=detail&aid=1159942&group_id=10894&atid=310894> .

# Copyright

This document has been placed in the public domain.

Name change from tip/23.tip to tip/23.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
TIP:            23
Title:          Tk Toolkit Functional Areas for Maintainer Assignments
Version:        $Revision: 1.30 $
Author:         Kevin Kenny <[email protected]>
Author:         Jim Ingham <[email protected]>
Author:         Don Porter <[email protected]>
Author:         Daniel A. Steffen <[email protected]>
Author:		Donal K. Fellows <[email protected]>
State:          Accepted
Type:           Process
Vote:           Done
Created:        22-Jan-2001
Post-History:   


~ Abstract

This document proposes a division of the Tk toolkit's source code into
functional areas so that each area may be assigned to one or more
maintainers.

~ Background

TCT procedures (see [0]) call for each ''maintainer'' to be
responsible for a portion of the Tk toolkit's source code.  Certain
portions of the Tk toolkit's source code are naturally associated with
certain other portions.  (For example, the implementation of a command
is intimately related to the documentation for that command.)
Establishing a ''natural'' division of the Tk toolkit's source code
into units needing maintainers is a useful preliminary effort toward a
public call for volunteer maintainers.

See [30] for the mapping of these functional areas to maintainers.

~ Rationale

[16] provides a convincing rationale for establishing a simple mapping
from source files to maintainers.  It also breaks out maintainers'
functional areas for the Tcl core.  This document attempts to develop
a similar mapping for the Tk toolkit.

Just as with [16], this document attempts to divide the Tk toolkit
into a set of the smallest sensible functional units.

One other factor, which was not addressed in [16], is that there is
considerably more platform dependent code in Tk than in Tcl, and it is
unreasonable to expect people to take ownership for pieces of code
that run on platforms they don't have access to.  However, we want to
make sure that the maintainer structure supports the cross-platform
nature of Tk.

To that end, in any area where there is both generic code, and
platform specific code, we propose that maintainers can sign up for
the generic code ''and'' code for one or more platforms.  By
overlapping the generic code, we ensure that the public interfaces to
Tk will stay consistent among the platforms, while not forcing
maintainers to presume expertise in code they can't even compile, much
less test or understand fully.

~ Functional Areas

The Tk toolkit shall be divided into the following functional
units, each to be assigned one or more maintainers.  Each area will also
be a Category in the SourceForge Tracker for Tk:

~~ Widgets

 1. '''Bindings''' -
     library/tk.tcl

 2. '''Appearance''' -
     generic/default.h,
     macosx/tkMacOSXDefault.h,
     unix/tkUnixDefault.h,
     win/tkWinDefault.h

 3. '''[[*button]] and [[label]]''' -
     doc/button.n,
     doc/checkbutton.n,
     doc/label.n,
     doc/radiobutton.n,
     generic/tkButton.c,
     generic/tkButton.h,
     library/button.tcl,
     macosx/tkMacOSXButton.c,
     unix/tkUnixButton.c,
     tests/butGeom.tcl,
     tests/butGeom2.tcl,
     tests/button.test,
     tests/unixButton.test,
     tests/winButton.test,
     win/rc/buttons.bmp,
     win/tkWinButton.c

 4. '''Canvas Basics''' -
     doc/CanvPsY.3,
     doc/CanvTxtInfo.3,
     doc/CanvTkwin.3,
     doc/CrtItemType.3,
     doc/GetDash.3,
     doc/canvas.n,
     generic/tkCanvUtil.c,
     generic/tkCanvas.c,
     generic/tkCanvas.h,
     tests/canvas.test

 5. '''Canvas Items''' -
     generic/tkCanvArc.c,
     generic/tkCanvBmap.c,
     generic/tkCanvImg.c,
     generic/tkCanvLine.c,
     generic/tkCanvPoly.c,
     generic/tkCanvText.c,
     generic/tkCanvWind.c,
     generic/tkRectOval.c,
     tests/arc.tcl,
     tests/canvImg.test,
     tests/canvRect.test,
     tests/canvText.test,
     tests/canvWind.test

 6. '''Canvas PostScript''' -
     generic/prolog.ps,
     generic/tkCanvPs.c,
     library/prolog.ps,
     tests/canvPs.test,
     tests/canvPsArc.tcl,
     tests/canvPsBmap.tcl,
     tests/canvPsGrph.tcl,
     tests/canvPsImg.tcl,
     tests/canvPsText.tcl

 7. '''[[entry]]''' -
     doc/entry.n,
     generic/tkEntry.c,
     library/entry.tcl,
     tests/entry.test

 8. '''[[frame]], [[toplevel]] and [[labelframe]]''' (see [18]) -
     doc/frame.n,
     doc/labelframe.n,
     doc/toplevel.n,
     generic/tkFrame.c,
     tests/frame.test

 9. '''[[listbox]]''' -
     doc/listbox.n,
     generic/tkListbox.c,
     library/listbox.tcl,
     tests/listbox.test

 10. '''Generic Menus''' -
     doc/menu.n,
     doc/menubutton.n,
     doc/popup.n,
     generic/tkMacWinMenu.c,
     generic/tkMenu.c,
     generic/tkMenu.h,
     generic/tkMenuDraw.c,
     generic/tkMenubutton.c,
     generic/tkMenubutton.h,
     library/menu.tcl,
     library/tearoff.tcl,
     tests/menu.test,
     tests/menuDraw.test,
     tests/menubut.test

 11. '''Aqua Menus''' -
     macosx/tkMacOSXMenu.c,
     macosx/tkMacOSXMenu.r,
     macosx/tkMacOSXMenubutton.c,
     macosx/tkMacOSXMenus.c

 12. '''Unix Menus''' -
     tests/unixMenu.test,
     unix/tkUnixMenu.c,
     unix/tkUnixMenubu.c

 13. '''Win Menus''' -
     tests/winMenu.test,
     win/tkWinMenu.c

 14. '''[[message]]''' -
     doc/message.n,
     generic/tkMessage.c,
     tests/message.test

 15. '''[[scale]]''' -
     doc/scale.n,
     generic/tkScale.c,
     generic/tkScale.h,
     library/scale.tcl,
     macosx/tkMacOSXScale.c,
     tests/scale.test,
     unix/tkUnixScale.c

 16. '''[[scrollbar]]''' -
     doc/scrollbar.n,
     generic/tkScrollbar.c,
     generic/tkScrollbar.h,
     library/scrlbar.tcl,
     macosx/tkMacOSXScrlbr.c,
     tests/scrollbar.test,
     unix/tkUnixScrlbr.c,
     win/tkWinScrlbr.c

 17. '''[[spinbox]]''' -
     doc/spinbox.n,
     library/spinbox.tcl,
     tests/spinbox.test

 18. '''[[text]]''' -
     doc/text.n,
     generic/tkText.c,
     generic/tkText.h,
     generic/tkTextBTree.c,
     generic/tkTextDisp.c,
     generic/tkTextImage.c,
     generic/tkTextIndex.c,
<
|
<
|
|
|
|
|
|
|
|
|
|
>

|





|

|


|
|
|



|

|

|




|


|








|





|





|

|


|





|

















|











|














|










|





|






|





|















|





|




|



|




|








|









|




|








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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217

# TIP 23: Tk Toolkit Functional Areas for Maintainer Assignments

	Author:         Kevin Kenny <[email protected]>
	Author:         Jim Ingham <[email protected]>
	Author:         Don Porter <[email protected]>
	Author:         Daniel A. Steffen <[email protected]>
	Author:		Donal K. Fellows <[email protected]>
	State:          Accepted
	Type:           Process
	Vote:           Done
	Created:        22-Jan-2001
	Post-History:   
-----

# Abstract

This document proposes a division of the Tk toolkit's source code into
functional areas so that each area may be assigned to one or more
maintainers.

# Background

TCT procedures \(see [[0]](0.md)\) call for each _maintainer_ to be
responsible for a portion of the Tk toolkit's source code.  Certain
portions of the Tk toolkit's source code are naturally associated with
certain other portions.  \(For example, the implementation of a command
is intimately related to the documentation for that command.\)
Establishing a _natural_ division of the Tk toolkit's source code
into units needing maintainers is a useful preliminary effort toward a
public call for volunteer maintainers.

See [[30]](30.md) for the mapping of these functional areas to maintainers.

# Rationale

[[16]](16.md) provides a convincing rationale for establishing a simple mapping
from source files to maintainers.  It also breaks out maintainers'
functional areas for the Tcl core.  This document attempts to develop
a similar mapping for the Tk toolkit.

Just as with [[16]](16.md), this document attempts to divide the Tk toolkit
into a set of the smallest sensible functional units.

One other factor, which was not addressed in [[16]](16.md), is that there is
considerably more platform dependent code in Tk than in Tcl, and it is
unreasonable to expect people to take ownership for pieces of code
that run on platforms they don't have access to.  However, we want to
make sure that the maintainer structure supports the cross-platform
nature of Tk.

To that end, in any area where there is both generic code, and
platform specific code, we propose that maintainers can sign up for
the generic code _and_ code for one or more platforms.  By
overlapping the generic code, we ensure that the public interfaces to
Tk will stay consistent among the platforms, while not forcing
maintainers to presume expertise in code they can't even compile, much
less test or understand fully.

# Functional Areas

The Tk toolkit shall be divided into the following functional
units, each to be assigned one or more maintainers.  Each area will also
be a Category in the SourceForge Tracker for Tk:

## Widgets

 1. **Bindings** -
     library/tk.tcl

 2. **Appearance** -
     generic/default.h,
     macosx/tkMacOSXDefault.h,
     unix/tkUnixDefault.h,
     win/tkWinDefault.h

 3. **[*button] and [label]** -
     doc/button.n,
     doc/checkbutton.n,
     doc/label.n,
     doc/radiobutton.n,
     generic/tkButton.c,
     generic/tkButton.h,
     library/button.tcl,
     macosx/tkMacOSXButton.c,
     unix/tkUnixButton.c,
     tests/butGeom.tcl,
     tests/butGeom2.tcl,
     tests/button.test,
     tests/unixButton.test,
     tests/winButton.test,
     win/rc/buttons.bmp,
     win/tkWinButton.c

 4. **Canvas Basics** -
     doc/CanvPsY.3,
     doc/CanvTxtInfo.3,
     doc/CanvTkwin.3,
     doc/CrtItemType.3,
     doc/GetDash.3,
     doc/canvas.n,
     generic/tkCanvUtil.c,
     generic/tkCanvas.c,
     generic/tkCanvas.h,
     tests/canvas.test

 5. **Canvas Items** -
     generic/tkCanvArc.c,
     generic/tkCanvBmap.c,
     generic/tkCanvImg.c,
     generic/tkCanvLine.c,
     generic/tkCanvPoly.c,
     generic/tkCanvText.c,
     generic/tkCanvWind.c,
     generic/tkRectOval.c,
     tests/arc.tcl,
     tests/canvImg.test,
     tests/canvRect.test,
     tests/canvText.test,
     tests/canvWind.test

 6. **Canvas PostScript** -
     generic/prolog.ps,
     generic/tkCanvPs.c,
     library/prolog.ps,
     tests/canvPs.test,
     tests/canvPsArc.tcl,
     tests/canvPsBmap.tcl,
     tests/canvPsGrph.tcl,
     tests/canvPsImg.tcl,
     tests/canvPsText.tcl

 7. **[entry]** -
     doc/entry.n,
     generic/tkEntry.c,
     library/entry.tcl,
     tests/entry.test

 8. **[frame], [toplevel] and [labelframe]** \(see [[18]](18.md)\) -
     doc/frame.n,
     doc/labelframe.n,
     doc/toplevel.n,
     generic/tkFrame.c,
     tests/frame.test

 9. **[listbox]** -
     doc/listbox.n,
     generic/tkListbox.c,
     library/listbox.tcl,
     tests/listbox.test

 10. **Generic Menus** -
     doc/menu.n,
     doc/menubutton.n,
     doc/popup.n,
     generic/tkMacWinMenu.c,
     generic/tkMenu.c,
     generic/tkMenu.h,
     generic/tkMenuDraw.c,
     generic/tkMenubutton.c,
     generic/tkMenubutton.h,
     library/menu.tcl,
     library/tearoff.tcl,
     tests/menu.test,
     tests/menuDraw.test,
     tests/menubut.test

 11. **Aqua Menus** -
     macosx/tkMacOSXMenu.c,
     macosx/tkMacOSXMenu.r,
     macosx/tkMacOSXMenubutton.c,
     macosx/tkMacOSXMenus.c

 12. **Unix Menus** -
     tests/unixMenu.test,
     unix/tkUnixMenu.c,
     unix/tkUnixMenubu.c

 13. **Win Menus** -
     tests/winMenu.test,
     win/tkWinMenu.c

 14. **[message]** -
     doc/message.n,
     generic/tkMessage.c,
     tests/message.test

 15. **[scale]** -
     doc/scale.n,
     generic/tkScale.c,
     generic/tkScale.h,
     library/scale.tcl,
     macosx/tkMacOSXScale.c,
     tests/scale.test,
     unix/tkUnixScale.c

 16. **[scrollbar]** -
     doc/scrollbar.n,
     generic/tkScrollbar.c,
     generic/tkScrollbar.h,
     library/scrlbar.tcl,
     macosx/tkMacOSXScrlbr.c,
     tests/scrollbar.test,
     unix/tkUnixScrlbr.c,
     win/tkWinScrlbr.c

 17. **[spinbox]** -
     doc/spinbox.n,
     library/spinbox.tcl,
     tests/spinbox.test

 18. **[text]** -
     doc/text.n,
     generic/tkText.c,
     generic/tkText.h,
     generic/tkTextBTree.c,
     generic/tkTextDisp.c,
     generic/tkTextImage.c,
     generic/tkTextIndex.c,
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
     tests/textDisp.test,
     tests/textImage.test,
     tests/textIndex.test,
     tests/textMark.test,
     tests/textTag.test,
     tests/textWind.test

 19. '''Menubars (obsolete)''' -
     doc/menubar.n,
     library/obsolete.tcl

 20. '''[[tk_optionMenu]]''' -
     doc/optionMenu.n,
     library/optMenu.tcl

 21. '''[[panedwindow]]''' (see [41]) -
     doc/panedwindow.n,
     generic/tkPanedWindow.c,
     library/panedwindow.tcl,
     tests/panedwindow.test

 22. '''Style Engine''' (see [48]) -
     generic/tkStyle.c

~~ Widget Options

 23. '''Option Parsing''' -
     doc/ConfigWidg.3,
     doc/SetOptions.3,
     generic/tkConfig.c,
     generic/tkOldConfig.c,
     macosx/tkMacOSXConfig.c,
     unix/tkUnixConfig.c,
     tests/config.test,
     win/tkWinConfig.c

 24. '''Relief''' -
     doc/3DBorder.3,
     doc/GetRelief.3,
     generic/tk3d.c,
     generic/tk3d.h,
     unix/tkUnix3d.c,
     tests/bevel.tcl,
     tests/border.test,
     win/tkWin3d.c

 25. '''Built-in Bitmaps''' -
     bitmaps/error.bmp,
     bitmaps/gray12.bmp,
     bitmaps/gray25.bmp,
     bitmaps/gray50.bmp,
     bitmaps/gray75.bmp,
     bitmaps/hourglass.bmp,
     bitmaps/info.bmp,
     bitmaps/questhead.bmp,
     bitmaps/question.bmp,
     bitmaps/warning.bmp,
     doc/GetBitmap.3,
     generic/tkBitmap.c,
     macosx/tkMacOSXBitmap.c,
     tests/bitmap.test

 26. '''Conversions From String''' -
     doc/GetAnchor.3,
     doc/GetCapStyl.3,
     doc/GetJoinStl.3,
     doc/GetJustify.3,
     doc/GetPixels.3,
     doc/GetUid.3,
     generic/tkGet.c,
     tests/get.test

 27. '''Objects''' - 
     generic/tkObj.c,
     tests/obj.test

 28. '''Utility Functions''' -
     doc/DrawFocHlt.3,
     doc/GetScroll.3,
     generic/tkUtil.c,
     tests/util.test

 29. '''Colormaps and Visuals''' -
     doc/GetClrmap.3,
     doc/GetVisual.3,
     generic/tkVisual.c,
     tests/visual.test

 30. '''Color Names''' -
     doc/GetColor.3,
     doc/colors.n,
     generic/tkColor.c,
     generic/tkColor.h,
     macosx/tkMacOSXColor.c,
     unix/tkUnixColor.c,
     tests/cmap.tcl,
     tests/color.test,
     win/tkWinColor.c,
     xlib/xcolors.c

 31. '''Cursor Names''' -
     doc/GetCursor.3,
     doc/cursors.n,
     generic/tkCursor.c,
     macosx/tkMacOSXCursor.c,
     macosx/tkMacOSXCursors.r,
     macosx/tkMacOSXXCursors.r,
     unix/tkUnixCursor.c,
     tests/cursor.test,
     win/rc/cursor*.cur,
     win/tkWinCursor.c,
     xlib/X11/cursorfont.h

 32. '''Key Symbols''' -
     doc/keysyms.n,
     macosx/tkMacOSXKeyboard.c,
     unix/tkUnixKey.c,
     win/tkWinKey.c,
     xlib/X11/keysym.h,
     xlib/X11/keysymdef.h

~~ Standard Dialogs

 33. '''Generic Dialog Support''' -
     library/comdlg.tcl

 34. '''[[tk_chooseColor]]''' -
     doc/chooseColor.n,
     library/clrpick.tcl,
     tests/clrpick.test

 35. '''[[tk_dialog]]''' -
     doc/dialog.n,
     library/dialog.tcl,
     macosx/tkMacOSXDialog.c,
     tests/dialog.test,
     tests/winDialog.test,
     unix/tkUnixDialog.c,
     win/tkWinDialog.c

 36. '''[[tk_chooseDirectory]]''' -
     doc/chooseDirectory.n,
     library/choosedir.tcl,
     tests/choosedir.test

 37. '''[[tk_get*File]]''' -
     doc/getOpenFile.n,
     generic/tkFileFilter.c,
     generic/tkFileFilter.h,
     library/tkfbox.tcl,
     library/xmfbox.tcl,
     tests/filebox.test,
     tests/xmfbox.test

 38. '''[[tk_messageBox]]''' -
     doc/messageBox.n,
     library/msgbox.tcl,
     tests/msgbox.test

~~ Images

 39. '''Image Basics''' -
     doc/CrtImgType.3,
     doc/DeleteImg.3,
     doc/GetImage.3,
     doc/ImgChanged.3,
     doc/NameOfImg.3,
     doc/image.n,
     generic/tkImage.c,
     generic/tkImgUtil.c,
     generic/tkStubImg.c,
     tests/image.test

 40. '''Bitmap Images''' -
     doc/bitmap.n,
     generic/tkImgBmap.c,
     tests/imgBmap.test

 41. '''Photo Images''' -
     doc/CrtPhImgFmt.3,
     doc/FindPhoto.3,
     doc/photo.n,
     generic/tkImgPhoto.c,
     tests/imgPhoto.test

 42. '''Photo Image|GIF''' -
     generic/tkImgGIF.c

 43. '''Photo Image|PPM''' -
     generic/tkImgPPM.c,
     tests/imgPPM.test

~~ Fonts

 44. '''Generic Fonts''' -
     doc/FontId.3,
     doc/GetFont.3,
     doc/MeasureChar.3,
     doc/TextLayout.3,
     doc/font.n,
     generic/tkFont.c,
     generic/tkFont.h,
     tests/font.test

 45. '''Aqua Fonts''' -
     macosx/tkMacOSXFont.c

 46. '''Unix Fonts''' -
     tests/unixFont.test,
     unix/tkUnixFont.c,
     unix/tkUnixRFont.c

 47. '''Win Fonts''' -
     tests/winFont.test,
     win/tkWinFont.c

~~ Geometry management

 48. '''Geometry Management''' -
     doc/GeomReq.3,
     doc/MaintGeom.3,
     doc/ManageGeom.3,
     generic/tkGeometry.c,
     tests/geometry.test

 49. '''[[grid]]''' -
     doc/grid.n,
     generic/tkGrid.c,
     tests/grid.test

 50. '''[[pack]]''' -
     doc/pack-old.n,
     doc/pack.n,
     generic/tkPack.c,
     tests/oldpack.test,
     tests/pack.test

 51. '''[[place]]''' -
     doc/place.n,
     generic/tkPlace.c,
     tests/place.test

~~ Selection and Clipboard

 52. '''[[clipboard]]''' -
     doc/Clipboard.3,
     doc/clipboard.n,
     generic/tkClipboard.c,
     macosx/tkMacOSXClipboard.c,
     tests/clipboard.test,
     tests/unixSelect.test,
     tests/winClipboard.test,
     unix/tkUnixSelect.c,
     win/tkWinClipboard.c

 53. '''[[selection]]''' -
     doc/ClrSelect.3,
     doc/CrtSelHdlr.3,
     doc/GetSelect.3,
     doc/OwnSelect.3,
     doc/selection.n,
     generic/tkSelect.c,
     generic/tkSelect.h,
     tests/select.test

~~ Other Tk commands

 54. '''[[console]]''' -
     doc/console.n,
     generic/tkConsole.c,
     library/console.tcl

 55. '''[[focus]]''' -
     doc/focus.n,
     generic/tkFocus.c,
     tests/focus.test

 56. '''[[grab]] and [[tk busy]]''' -
     doc/Grab.3,
     doc/busy.n
     doc/grab.n,
     generic/tkBusy.c,
     generic/tkBusy.h,
     generic/tkGrab.c,
     tests/busy.test,
     tests/grab.test

 57. '''[[option]]''' -
     doc/AddOption.3,
     doc/GetOption.3,
     doc/option.n,
     generic/tkOption.c,
     tests/option.file1,
     tests/option.file2,
     tests/option.test

 58. '''[[send]]''' -
     doc/SetAppName.3,
     doc/send.n,
     macosx/tkMacOSXSend.c,
     tests/send.test,
     tests/unixSend.test,
     tests/winSend.test,
     unix/tkUnixSend.c,
     win/tkWinSend.c

 59. '''[[tk_focus*]]''' -
     doc/focusNext.n,
     library/focus.tcl,
     tests/focusTcl.test

 60. '''[[tk_setPalette]]''' -
     doc/palette.n,
     library/palette.tcl

 61. '''Safe Tk''' -
     doc/loadTk.n,
     library/safetk.tcl,
     tests/safe.test

~~ Low-level Tk functions

 62. '''Geometry Functions''' -
     generic/tkTrig.c

 63. '''Tk_Win Functions''' -
     doc/ConfigWind.3,
     doc/CrtWindow.3,
     doc/IdToWindow.3,
     doc/MainWin.3,
     doc/MapWindow.3,
     doc/Name.3,
     doc/Restack.3,
     doc/SetClass.3,
     doc/SetClassProcs.3,
     doc/SetVisual.3,
     doc/StrictMotif.3,
     doc/Tk_Init.3,
     doc/WindowId.3,
     generic/tkWindow.c,
     tests/window.test

 64. '''Graphic Contexts''' -
     doc/GetGC.3,
     generic/tkGC.c

 65. '''Generic Window Operations''' -
     doc/CoordToWin.3,
     doc/FreeXId.3,
     doc/GetHINSTANCE.3,
     doc/GetHWND.3,
     doc/GetPixmap.3,
     doc/GetRootCrd.3,
     doc/GetVRoot.3,







|



|



|





|


|

|









|









|















|









|



|





|





|











|








|



|







|

|


|




|








|




|








|




|

|











|




|






|


|



|

|









|


|




|



|

|






|




|






|




|

|










|









|

|




|




|









|








|









|




|



|




|

|


|











|




|



|







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
     tests/textDisp.test,
     tests/textImage.test,
     tests/textIndex.test,
     tests/textMark.test,
     tests/textTag.test,
     tests/textWind.test

 19. **Menubars \(obsolete\)** -
     doc/menubar.n,
     library/obsolete.tcl

 20. **[tk_optionMenu]** -
     doc/optionMenu.n,
     library/optMenu.tcl

 21. **[panedwindow]** \(see [[41]](41.md)\) -
     doc/panedwindow.n,
     generic/tkPanedWindow.c,
     library/panedwindow.tcl,
     tests/panedwindow.test

 22. **Style Engine** \(see [[48]](48.md)\) -
     generic/tkStyle.c

## Widget Options

 23. **Option Parsing** -
     doc/ConfigWidg.3,
     doc/SetOptions.3,
     generic/tkConfig.c,
     generic/tkOldConfig.c,
     macosx/tkMacOSXConfig.c,
     unix/tkUnixConfig.c,
     tests/config.test,
     win/tkWinConfig.c

 24. **Relief** -
     doc/3DBorder.3,
     doc/GetRelief.3,
     generic/tk3d.c,
     generic/tk3d.h,
     unix/tkUnix3d.c,
     tests/bevel.tcl,
     tests/border.test,
     win/tkWin3d.c

 25. **Built-in Bitmaps** -
     bitmaps/error.bmp,
     bitmaps/gray12.bmp,
     bitmaps/gray25.bmp,
     bitmaps/gray50.bmp,
     bitmaps/gray75.bmp,
     bitmaps/hourglass.bmp,
     bitmaps/info.bmp,
     bitmaps/questhead.bmp,
     bitmaps/question.bmp,
     bitmaps/warning.bmp,
     doc/GetBitmap.3,
     generic/tkBitmap.c,
     macosx/tkMacOSXBitmap.c,
     tests/bitmap.test

 26. **Conversions From String** -
     doc/GetAnchor.3,
     doc/GetCapStyl.3,
     doc/GetJoinStl.3,
     doc/GetJustify.3,
     doc/GetPixels.3,
     doc/GetUid.3,
     generic/tkGet.c,
     tests/get.test

 27. **Objects** - 
     generic/tkObj.c,
     tests/obj.test

 28. **Utility Functions** -
     doc/DrawFocHlt.3,
     doc/GetScroll.3,
     generic/tkUtil.c,
     tests/util.test

 29. **Colormaps and Visuals** -
     doc/GetClrmap.3,
     doc/GetVisual.3,
     generic/tkVisual.c,
     tests/visual.test

 30. **Color Names** -
     doc/GetColor.3,
     doc/colors.n,
     generic/tkColor.c,
     generic/tkColor.h,
     macosx/tkMacOSXColor.c,
     unix/tkUnixColor.c,
     tests/cmap.tcl,
     tests/color.test,
     win/tkWinColor.c,
     xlib/xcolors.c

 31. **Cursor Names** -
     doc/GetCursor.3,
     doc/cursors.n,
     generic/tkCursor.c,
     macosx/tkMacOSXCursor.c,
     macosx/tkMacOSXCursors.r,
     macosx/tkMacOSXXCursors.r,
     unix/tkUnixCursor.c,
     tests/cursor.test,
     win/rc/cursor\*.cur,
     win/tkWinCursor.c,
     xlib/X11/cursorfont.h

 32. **Key Symbols** -
     doc/keysyms.n,
     macosx/tkMacOSXKeyboard.c,
     unix/tkUnixKey.c,
     win/tkWinKey.c,
     xlib/X11/keysym.h,
     xlib/X11/keysymdef.h

## Standard Dialogs

 33. **Generic Dialog Support** -
     library/comdlg.tcl

 34. **[tk_chooseColor]** -
     doc/chooseColor.n,
     library/clrpick.tcl,
     tests/clrpick.test

 35. **[tk_dialog]** -
     doc/dialog.n,
     library/dialog.tcl,
     macosx/tkMacOSXDialog.c,
     tests/dialog.test,
     tests/winDialog.test,
     unix/tkUnixDialog.c,
     win/tkWinDialog.c

 36. **[tk_chooseDirectory]** -
     doc/chooseDirectory.n,
     library/choosedir.tcl,
     tests/choosedir.test

 37. **[tk_get*File]** -
     doc/getOpenFile.n,
     generic/tkFileFilter.c,
     generic/tkFileFilter.h,
     library/tkfbox.tcl,
     library/xmfbox.tcl,
     tests/filebox.test,
     tests/xmfbox.test

 38. **[tk_messageBox]** -
     doc/messageBox.n,
     library/msgbox.tcl,
     tests/msgbox.test

## Images

 39. **Image Basics** -
     doc/CrtImgType.3,
     doc/DeleteImg.3,
     doc/GetImage.3,
     doc/ImgChanged.3,
     doc/NameOfImg.3,
     doc/image.n,
     generic/tkImage.c,
     generic/tkImgUtil.c,
     generic/tkStubImg.c,
     tests/image.test

 40. **Bitmap Images** -
     doc/bitmap.n,
     generic/tkImgBmap.c,
     tests/imgBmap.test

 41. **Photo Images** -
     doc/CrtPhImgFmt.3,
     doc/FindPhoto.3,
     doc/photo.n,
     generic/tkImgPhoto.c,
     tests/imgPhoto.test

 42. **Photo Image\|GIF** -
     generic/tkImgGIF.c

 43. **Photo Image\|PPM** -
     generic/tkImgPPM.c,
     tests/imgPPM.test

## Fonts

 44. **Generic Fonts** -
     doc/FontId.3,
     doc/GetFont.3,
     doc/MeasureChar.3,
     doc/TextLayout.3,
     doc/font.n,
     generic/tkFont.c,
     generic/tkFont.h,
     tests/font.test

 45. **Aqua Fonts** -
     macosx/tkMacOSXFont.c

 46. **Unix Fonts** -
     tests/unixFont.test,
     unix/tkUnixFont.c,
     unix/tkUnixRFont.c

 47. **Win Fonts** -
     tests/winFont.test,
     win/tkWinFont.c

## Geometry management

 48. **Geometry Management** -
     doc/GeomReq.3,
     doc/MaintGeom.3,
     doc/ManageGeom.3,
     generic/tkGeometry.c,
     tests/geometry.test

 49. **[grid]** -
     doc/grid.n,
     generic/tkGrid.c,
     tests/grid.test

 50. **[pack]** -
     doc/pack-old.n,
     doc/pack.n,
     generic/tkPack.c,
     tests/oldpack.test,
     tests/pack.test

 51. **[place]** -
     doc/place.n,
     generic/tkPlace.c,
     tests/place.test

## Selection and Clipboard

 52. **[clipboard]** -
     doc/Clipboard.3,
     doc/clipboard.n,
     generic/tkClipboard.c,
     macosx/tkMacOSXClipboard.c,
     tests/clipboard.test,
     tests/unixSelect.test,
     tests/winClipboard.test,
     unix/tkUnixSelect.c,
     win/tkWinClipboard.c

 53. **[selection]** -
     doc/ClrSelect.3,
     doc/CrtSelHdlr.3,
     doc/GetSelect.3,
     doc/OwnSelect.3,
     doc/selection.n,
     generic/tkSelect.c,
     generic/tkSelect.h,
     tests/select.test

## Other Tk commands

 54. **[console]** -
     doc/console.n,
     generic/tkConsole.c,
     library/console.tcl

 55. **[focus]** -
     doc/focus.n,
     generic/tkFocus.c,
     tests/focus.test

 56. **[grab] and [tk busy]** -
     doc/Grab.3,
     doc/busy.n
     doc/grab.n,
     generic/tkBusy.c,
     generic/tkBusy.h,
     generic/tkGrab.c,
     tests/busy.test,
     tests/grab.test

 57. **[option]** -
     doc/AddOption.3,
     doc/GetOption.3,
     doc/option.n,
     generic/tkOption.c,
     tests/option.file1,
     tests/option.file2,
     tests/option.test

 58. **[send]** -
     doc/SetAppName.3,
     doc/send.n,
     macosx/tkMacOSXSend.c,
     tests/send.test,
     tests/unixSend.test,
     tests/winSend.test,
     unix/tkUnixSend.c,
     win/tkWinSend.c

 59. **[tk_focus*]** -
     doc/focusNext.n,
     library/focus.tcl,
     tests/focusTcl.test

 60. **[tk_setPalette]** -
     doc/palette.n,
     library/palette.tcl

 61. **Safe Tk** -
     doc/loadTk.n,
     library/safetk.tcl,
     tests/safe.test

## Low-level Tk functions

 62. **Geometry Functions** -
     generic/tkTrig.c

 63. **Tk\_Win Functions** -
     doc/ConfigWind.3,
     doc/CrtWindow.3,
     doc/IdToWindow.3,
     doc/MainWin.3,
     doc/MapWindow.3,
     doc/Name.3,
     doc/Restack.3,
     doc/SetClass.3,
     doc/SetClassProcs.3,
     doc/SetVisual.3,
     doc/StrictMotif.3,
     doc/Tk\_Init.3,
     doc/WindowId.3,
     generic/tkWindow.c,
     tests/window.test

 64. **Graphic Contexts** -
     doc/GetGC.3,
     generic/tkGC.c

 65. **Generic Window Operations** -
     doc/CoordToWin.3,
     doc/FreeXId.3,
     doc/GetHINSTANCE.3,
     doc/GetHWND.3,
     doc/GetPixmap.3,
     doc/GetRootCrd.3,
     doc/GetVRoot.3,
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
     tests/id.test,
     tests/raise.test,
     tests/tk.test,
     tests/winfo.test,
     tests/wm.test,
     xlib/xgc.c

 66. '''Aqua Window Operations''' -
     macosx/tkMacOSXCarbonEvents.c
     macosx/tkMacOSXDebug.c
     macosx/tkMacOSXDebug.h
     macosx/tkMacOSXDraw.c,
     macosx/tkMacOSXEmbed.c,
     macosx/tkMacOSXEvent.c
     macosx/tkMacOSXEvent.h
     macosx/tkMacOSXHLEvents.c,
     macosx/tkMacOSXKeyEvent.c
     macosx/tkMacOSXMouseEvent.c
     macosx/tkMacOSXNotify.c
     macosx/tkMacOSXRegion.c,
     macosx/tkMacOSXSubwindows.c,
     macosx/tkMacOSXWindowEvent.c
     macosx/tkMacOSXWm.c,
     macosx/tkMacOSXWm.h,
     macosx/tkMacOSXXStubs.c

 67. '''Unix Window Operations''' -
     tests/unixEmbed.test,
     tests/unixWm.test,
     unix/tkUnix.c,
     unix/tkUnixDraw.c,
     unix/tkUnixEmbed.c,
     unix/tkUnixEvent.c,
     unix/tkUnixFocus.c,
     unix/tkUnixWm.c,
     unix/tkUnixXId.c

 68. '''Win Window Operations''' -
     tests/winWm.test,
     win/stubs.c,
     win/tkWinDraw.c,
     win/tkWinEmbed.c,
     win/tkWinImage.c,
     win/tkWinPixmap.c,
     win/tkWinPointer.c,
     win/tkWinRegion.c,
     win/tkWinWindow.c,
     win/tkWinWm.c,
     win/tkWinX.c

 69. '''Events''' -
     doc/BindTable.3,
     doc/event.n,
     generic/tkBind.c,
     tests/bind.test

 70. '''Event Loop''' -
     doc/CrtCmHdlr.3,
     doc/CrtGenHdlr.3,
     doc/EventHndlr.3,
     doc/HandleEvent.3,
     doc/MainLoop.3,
     doc/QWinEvent.3,
     doc/RestrictEv.3,
     generic/tkEvent.c,
     tests/event.test

 71. '''Error Handling''' -
     doc/CrtErrHdlr.3,
     doc/tkerror.n,
     generic/tkError.c,
     library/bgerror.tcl,
     tests/bgerror.test

 72. '''Atoms''' -
     doc/InternAtom.3,
     generic/tkAtom.c,
     xlib/X11/Xatom.h

~~ Shells

 73. '''Argv Parsing''' -
     doc/ParseArgv.3,
     generic/tkArgv.c

 74. '''Application Embedding''' -
     doc/Tk_Main.3,
     generic/tkInitScript.h,
     generic/tkMain.c,
     macosx/tkMacOSXInit.c,
     unix/tkUnixInit.c,
     win/tkWin32Dll.c,
     win/tkWinInit.c,
     tests/main.test

 75. '''wish''' -
     doc/wish.1,
     macosx/tkMacOSXAppInit.c,
     unix/tkAppInit.c,
     win/winMain.c

~~ Demonstrations

 76. '''Widget Tour''' -
     library/demos/arrow.tcl,
     library/demos/bind.tcl,
     library/demos/bitmap.tcl,
     library/demos/button.tcl,
     library/demos/check.tcl,
     library/demos/clrpick.tcl,
     library/demos/colors.tcl,







|


















|










|












|





|










|






|




|

|



|
|








|





|

|







599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
     tests/id.test,
     tests/raise.test,
     tests/tk.test,
     tests/winfo.test,
     tests/wm.test,
     xlib/xgc.c

 66. **Aqua Window Operations** -
     macosx/tkMacOSXCarbonEvents.c
     macosx/tkMacOSXDebug.c
     macosx/tkMacOSXDebug.h
     macosx/tkMacOSXDraw.c,
     macosx/tkMacOSXEmbed.c,
     macosx/tkMacOSXEvent.c
     macosx/tkMacOSXEvent.h
     macosx/tkMacOSXHLEvents.c,
     macosx/tkMacOSXKeyEvent.c
     macosx/tkMacOSXMouseEvent.c
     macosx/tkMacOSXNotify.c
     macosx/tkMacOSXRegion.c,
     macosx/tkMacOSXSubwindows.c,
     macosx/tkMacOSXWindowEvent.c
     macosx/tkMacOSXWm.c,
     macosx/tkMacOSXWm.h,
     macosx/tkMacOSXXStubs.c

 67. **Unix Window Operations** -
     tests/unixEmbed.test,
     tests/unixWm.test,
     unix/tkUnix.c,
     unix/tkUnixDraw.c,
     unix/tkUnixEmbed.c,
     unix/tkUnixEvent.c,
     unix/tkUnixFocus.c,
     unix/tkUnixWm.c,
     unix/tkUnixXId.c

 68. **Win Window Operations** -
     tests/winWm.test,
     win/stubs.c,
     win/tkWinDraw.c,
     win/tkWinEmbed.c,
     win/tkWinImage.c,
     win/tkWinPixmap.c,
     win/tkWinPointer.c,
     win/tkWinRegion.c,
     win/tkWinWindow.c,
     win/tkWinWm.c,
     win/tkWinX.c

 69. **Events** -
     doc/BindTable.3,
     doc/event.n,
     generic/tkBind.c,
     tests/bind.test

 70. **Event Loop** -
     doc/CrtCmHdlr.3,
     doc/CrtGenHdlr.3,
     doc/EventHndlr.3,
     doc/HandleEvent.3,
     doc/MainLoop.3,
     doc/QWinEvent.3,
     doc/RestrictEv.3,
     generic/tkEvent.c,
     tests/event.test

 71. **Error Handling** -
     doc/CrtErrHdlr.3,
     doc/tkerror.n,
     generic/tkError.c,
     library/bgerror.tcl,
     tests/bgerror.test

 72. **Atoms** -
     doc/InternAtom.3,
     generic/tkAtom.c,
     xlib/X11/Xatom.h

## Shells

 73. **Argv Parsing** -
     doc/ParseArgv.3,
     generic/tkArgv.c

 74. **Application Embedding** -
     doc/Tk\_Main.3,
     generic/tkInitScript.h,
     generic/tkMain.c,
     macosx/tkMacOSXInit.c,
     unix/tkUnixInit.c,
     win/tkWin32Dll.c,
     win/tkWinInit.c,
     tests/main.test

 75. **wish** -
     doc/wish.1,
     macosx/tkMacOSXAppInit.c,
     unix/tkAppInit.c,
     win/winMain.c

## Demonstrations

 76. **Widget Tour** -
     library/demos/arrow.tcl,
     library/demos/bind.tcl,
     library/demos/bitmap.tcl,
     library/demos/button.tcl,
     library/demos/check.tcl,
     library/demos/clrpick.tcl,
     library/demos/colors.tcl,
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
     library/demos/images/gray25.bmp,
     library/demos/images/letters.bmp,
     library/demos/images/noletter.bmp,
     library/demos/images/pattern.bmp,
     library/demos/images/tcllogo.gif,
     library/demos/images/teapot.ppm

 77. '''Square Demo''' -
     generic/tkSquare.c,
     library/demos/square

 78. '''Other Demos''' -
     library/demos/browse,
     library/demos/hello,
     library/demos/ixset,
     library/demos/rmt,
     library/demos/rolodex,
     library/demos/tcolor,
     library/demos/timer

~~ Localization

 79. '''L10N''' -
     library/msgs/cs.msg,
     library/msgs/de.msg,
     library/msgs/el.msg,
     library/msgs/en.msg,
     library/msgs/en_gb.msg,
     library/msgs/es.msg,
     library/msgs/fr.msg,
     library/msgs/it.msg,
     library/msgs/nl.msg,
     library/msgs/ru.msg

~~ Release Engineering

 80. '''Release Notes''' -
     README,
     */README,
     */*/README,
     changes,
     license.terms,
     doc/options.n,
     doc/tk4.0.ps,
     tests/bugs.tcl

 81. '''Portability''' -
     compat/limits.h,
     compat/stdlib.h,
     compat/unistd.h

 82. '''X11 Emulation''' -
     xlib/X11/X.h,
     xlib/X11/Xfuncproto.h,
     xlib/X11/Xlib.h,
     xlib/X11/Xutil.h,
     xlib/xbytes.h,
     xlib/xdraw.c,
     xlib/ximage.c,
     xlib/xutil.c

 83. '''Mac OS X Build''' -
     macosx/Makefile,
     macosx/buildTkConfig.tcl,
     macosx/tkAboutDlg.r,
     macosx/tkMacOSX.h,
     macosx/tkMacOSXAETE.r,
     macosx/Wish.pbproj/project.pbxproj

 84. '''Unix Build''' -
     unix/Makefile.in,
     unix/aclocal.m4,
     unix/configure.in,
     unix/install-sh,
     unix/tcl.m4,
     unix/tk.spec,
     unix/tkConfig.sh.in

 85. '''Win Build''' -
     win/Makefile.in,
     win/aclocal.m4,
     win/buildall.vc.bat,
     win/configure.in,
     win/makefile.vc,
     win/mkd.bat,
     win/nmakehlp.c,
     win/rc/tkc,
     win/rc/tk_base.rc,
     win/rc/wish.exe.manifest,
     win/rc/wish.rc,
     win/rmd.bat,
     win/rules.vc,
     win/tcl.m4,
     win/tkConfig.sh.in,
     win/tkWin.h

 86. '''Test Tools''' -
     generic/tkTest.c,
     macosx/tkMacOSXTest.c,
     win/tkWinTest.c,
     tests/all.tcl,
     tests/defs.tcl,
     tests/visual_bb.test

 87. '''Logos''' -
     library/images/logo.eps,
     library/images/logo100.gif,
     library/images/logo64.gif,
     library/images/logoLarge.gif,
     library/images/logoMed.gif,
     library/images/pwrdLogo.eps,
     library/images/pwrdLogo100.gif,
     library/images/pwrdLogo150.gif,
     library/images/pwrdLogo175.gif,
     library/images/pwrdLogo200.gif,
     library/images/pwrdLogo75.gif,
     library/images/tai-ku.gif,
     macosx/Wish.icns,
     win/lamp.bmp,
     win/rc/tk.ico,
     win/rc/wish.ico

~~ Themed Tk (Ttk)

 88. '''Themed Tk''' -
     doc/ttk_*,
     generic/ttk/*,
     library/ttk/*,
     tests/ttk/*,
     macosx/ttkMacOSXTheme.c,
     win/ttkWinMonitor.c,
     win/ttkWinTheme.c,
     win/ttkWinXPTheme.c

~ Shared Files

The following files are shared by all of Tk.  Any maintainer may
modify them as necessary to complete changes they are making to
their portion of Tk.  Some of the following files define Tk's
API and should be changed only with TCT approval.

   * ChangeLog,







|



|








|

|




|






|

|


|






|




|









|







|








|








|








|





|

|

















|

|
|
|
|
|





|







750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
     library/demos/images/gray25.bmp,
     library/demos/images/letters.bmp,
     library/demos/images/noletter.bmp,
     library/demos/images/pattern.bmp,
     library/demos/images/tcllogo.gif,
     library/demos/images/teapot.ppm

 77. **Square Demo** -
     generic/tkSquare.c,
     library/demos/square

 78. **Other Demos** -
     library/demos/browse,
     library/demos/hello,
     library/demos/ixset,
     library/demos/rmt,
     library/demos/rolodex,
     library/demos/tcolor,
     library/demos/timer

## Localization

 79. **L10N** -
     library/msgs/cs.msg,
     library/msgs/de.msg,
     library/msgs/el.msg,
     library/msgs/en.msg,
     library/msgs/en\_gb.msg,
     library/msgs/es.msg,
     library/msgs/fr.msg,
     library/msgs/it.msg,
     library/msgs/nl.msg,
     library/msgs/ru.msg

## Release Engineering

 80. **Release Notes** -
     README,
     */README,
     */\*/README,
     changes,
     license.terms,
     doc/options.n,
     doc/tk4.0.ps,
     tests/bugs.tcl

 81. **Portability** -
     compat/limits.h,
     compat/stdlib.h,
     compat/unistd.h

 82. **X11 Emulation** -
     xlib/X11/X.h,
     xlib/X11/Xfuncproto.h,
     xlib/X11/Xlib.h,
     xlib/X11/Xutil.h,
     xlib/xbytes.h,
     xlib/xdraw.c,
     xlib/ximage.c,
     xlib/xutil.c

 83. **Mac OS X Build** -
     macosx/Makefile,
     macosx/buildTkConfig.tcl,
     macosx/tkAboutDlg.r,
     macosx/tkMacOSX.h,
     macosx/tkMacOSXAETE.r,
     macosx/Wish.pbproj/project.pbxproj

 84. **Unix Build** -
     unix/Makefile.in,
     unix/aclocal.m4,
     unix/configure.in,
     unix/install-sh,
     unix/tcl.m4,
     unix/tk.spec,
     unix/tkConfig.sh.in

 85. **Win Build** -
     win/Makefile.in,
     win/aclocal.m4,
     win/buildall.vc.bat,
     win/configure.in,
     win/makefile.vc,
     win/mkd.bat,
     win/nmakehlp.c,
     win/rc/tkc,
     win/rc/tk\_base.rc,
     win/rc/wish.exe.manifest,
     win/rc/wish.rc,
     win/rmd.bat,
     win/rules.vc,
     win/tcl.m4,
     win/tkConfig.sh.in,
     win/tkWin.h

 86. **Test Tools** -
     generic/tkTest.c,
     macosx/tkMacOSXTest.c,
     win/tkWinTest.c,
     tests/all.tcl,
     tests/defs.tcl,
     tests/visual\_bb.test

 87. **Logos** -
     library/images/logo.eps,
     library/images/logo100.gif,
     library/images/logo64.gif,
     library/images/logoLarge.gif,
     library/images/logoMed.gif,
     library/images/pwrdLogo.eps,
     library/images/pwrdLogo100.gif,
     library/images/pwrdLogo150.gif,
     library/images/pwrdLogo175.gif,
     library/images/pwrdLogo200.gif,
     library/images/pwrdLogo75.gif,
     library/images/tai-ku.gif,
     macosx/Wish.icns,
     win/lamp.bmp,
     win/rc/tk.ico,
     win/rc/wish.ico

## Themed Tk \(Ttk\)

 88. **Themed Tk** -
     doc/ttk\_\*,
     generic/ttk/\*,
     library/ttk/\*,
     tests/ttk/\*,
     macosx/ttkMacOSXTheme.c,
     win/ttkWinMonitor.c,
     win/ttkWinTheme.c,
     win/ttkWinXPTheme.c

# Shared Files

The following files are shared by all of Tk.  Any maintainer may
modify them as necessary to complete changes they are making to
their portion of Tk.  Some of the following files define Tk's
API and should be changed only with TCT approval.

   * ChangeLog,
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963

     macosx/tkMacOSXInt.h,
     macosx/tkMacOSXPort.h,
     unix/tkUnixInt.h,
     unix/tkUnixPort.h,
     win/tkWinInt.h,
     win/tkWinPort.h

~ Generated Files

The following files are generated, so they don't need maintainers.

   * generic/ks_names.h,
     generic/tkDecls.h,
     generic/tkIntDecls.h,
     generic/tkIntPlatDecls.h,
     generic/tkIntXlibDecls.h,
     generic/tkPlatDecls.h,
     generic/tkStubInit.c,
     library/demos/tclIndex,
     library/tclIndex,
     unix/configure,
     unix/mkLinks,
     win/configure

~ Platform Dependencies

In addition to the division into functional areas, responsibility for
a given area can also be qualified by one or more ''platform''
specifiers.  Some areas, like '''Windows Configuration and Build
Tools''' are obviously platform specific, so the qualification is
unnecessary.  Others, like '''Canvas Items''', are wholly generic.  But
others, like '''Button''', '''Scale''' or '''Scrollbar''' contain code for
all platforms.

A maintainer can sign up for one of these latter areas, but specify
support for only one platform.  This means that that person will be
responsible for the generic code in this area, in conjunction with the
other platform maintainers in this area, and the platform specific
code in that area.

The point behind sharing the generic code among all the maintainers is
so that any changes to the Tk visible face of the widget be designed
in concert for all platforms.  Therefore, it is the responsibility of
a platform maintainer for one platform who is sponsering a new feature
for that area to work with the other platform maintainers to ensure
that the feature is implemented on all platforms.  One of the
strengths of Tk is its cross-platform nature, and one of the
maintainer's jobs is to ensure that this continues.

Procedurally, the maintainer will be listed as '''Button Widget -
Mac OS X''', etc.  A maintainer for a given area can sign up for one
or more platforms.  Due to the good design of the Tk's platform
dependencies, determining which files are generic, and which are
platform specific is trivial.  The generic ones are in the ''generic''
directory, the Mac ones in the ''macosx'' directory, etc.  Similarly, an
area which has NO files in the macosx, win, or unix directories is a
generic area, and no qualifiers are needed.

~ Copyright

This document has been placed in the public domain.








|



|












|


|
|
|
|
|

















|
|


|
|



|


>
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
     macosx/tkMacOSXInt.h,
     macosx/tkMacOSXPort.h,
     unix/tkUnixInt.h,
     unix/tkUnixPort.h,
     win/tkWinInt.h,
     win/tkWinPort.h

# Generated Files

The following files are generated, so they don't need maintainers.

   * generic/ks\_names.h,
     generic/tkDecls.h,
     generic/tkIntDecls.h,
     generic/tkIntPlatDecls.h,
     generic/tkIntXlibDecls.h,
     generic/tkPlatDecls.h,
     generic/tkStubInit.c,
     library/demos/tclIndex,
     library/tclIndex,
     unix/configure,
     unix/mkLinks,
     win/configure

# Platform Dependencies

In addition to the division into functional areas, responsibility for
a given area can also be qualified by one or more _platform_
specifiers.  Some areas, like **Windows Configuration and Build
Tools** are obviously platform specific, so the qualification is
unnecessary.  Others, like **Canvas Items**, are wholly generic.  But
others, like **Button**, **Scale** or **Scrollbar** contain code for
all platforms.

A maintainer can sign up for one of these latter areas, but specify
support for only one platform.  This means that that person will be
responsible for the generic code in this area, in conjunction with the
other platform maintainers in this area, and the platform specific
code in that area.

The point behind sharing the generic code among all the maintainers is
so that any changes to the Tk visible face of the widget be designed
in concert for all platforms.  Therefore, it is the responsibility of
a platform maintainer for one platform who is sponsering a new feature
for that area to work with the other platform maintainers to ensure
that the feature is implemented on all platforms.  One of the
strengths of Tk is its cross-platform nature, and one of the
maintainer's jobs is to ensure that this continues.

Procedurally, the maintainer will be listed as **Button Widget -
Mac OS X**, etc.  A maintainer for a given area can sign up for one
or more platforms.  Due to the good design of the Tk's platform
dependencies, determining which files are generic, and which are
platform specific is trivial.  The generic ones are in the _generic_
directory, the Mac ones in the _macosx_ directory, etc.  Similarly, an
area which has NO files in the macosx, win, or unix directories is a
generic area, and no qualifiers are needed.

# Copyright

This document has been placed in the public domain.

Name change from tip/230.tip to tip/230.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
TIP:            230
Title:          Tcl Channel Transformation Reflection API
Version:        $Revision: 1.17 $
Author:         Andreas Kupries <[email protected]>
Author:         Andreas Kupries <[email protected]>
Author:         Andreas Kupries <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        02-Nov-2004
Post-History:   
Tcl-Version:    8.6


~ Abstract

This document describes an API which reflects the Channel
Transformation API of the core I/O system up into the Tcl level, for
the implementation of channel transformations in Tcl.  It is built on
top of [208] ('Add a chan command') and also an independent companion
to [219] ('Tcl Channel Reflection API') and [228] ('Tcl Filesystem
Reflection API'). As the latter TIPs bring the ability of writing
channel drivers and filesystems in Tcl itself so this TIP provides the
facilities for the implementation of new channel transformations in
Tcl.  This document specifies version ''1'' of the transformation
reflection API.

~ Background and Motivation

The purpose of this and the other reflection TIPs is to provide all
the facilities required for the creation and usage of wrapped files
(i.e. virtual filesystems attached to executables and binary
libraries) within the core.

While it is possible to implement and place all the proposed
reflectivity in separate and external packages, this however means
that the core itself cannot make use of wrapping technology and
virtual filesystems to encapsulate and attach its own data and library
files to itself. Something which is desirable as it can make the
deployment and embedding of the core easier, due to having less files
<
|
<
|
|
|
|
|
|
|
|
|
>

|




|
|
|


|


|



|
|








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

# TIP 230: Tcl Channel Transformation Reflection API

	Author:         Andreas Kupries <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        02-Nov-2004
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

This document describes an API which reflects the Channel
Transformation API of the core I/O system up into the Tcl level, for
the implementation of channel transformations in Tcl.  It is built on
top of [[208]](208.md) \('Add a chan command'\) and also an independent companion
to [[219]](219.md) \('Tcl Channel Reflection API'\) and [[228]](228.md) \('Tcl Filesystem
Reflection API'\). As the latter TIPs bring the ability of writing
channel drivers and filesystems in Tcl itself so this TIP provides the
facilities for the implementation of new channel transformations in
Tcl.  This document specifies version _1_ of the transformation
reflection API.

# Background and Motivation

The purpose of this and the other reflection TIPs is to provide all
the facilities required for the creation and usage of wrapped files
\(i.e. virtual filesystems attached to executables and binary
libraries\) within the core.

While it is possible to implement and place all the proposed
reflectivity in separate and external packages, this however means
that the core itself cannot make use of wrapping technology and
virtual filesystems to encapsulate and attach its own data and library
files to itself. Something which is desirable as it can make the
deployment and embedding of the core easier, due to having less files
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600

of the special test commands for exercising the various internal of
the Tcl core during test. This TIP asks to make that mechanism
publicly available to script and package authors, with a bit of
cleanup regarding the Tcl level API. The roots of that mechanism can
be traced back to the Trf package which implemented channel
transformations first and provides a similar command.

~ Transform Management API Specification

The Tcl level API consists of two new subcommands added to the
ensemble command '''chan'''' specified by [208]. Both subcommands are
completely generic, i.e. they can be applied to any type of channel,
without restrictions.  There is no C API to specify. The Tcl core
already has a standard API for the creation of channel transformations
from the C level.

~~ The push Subcommand

 > '''chan push''' ''channel cmdprefix''

This subcommand creates a new script level transformation using the
command prefix ''cmdprefix'' as its handler and attaches it to the
specified channel. The new transformation is always added on top of
any other transformations which may be present.

The handle of the new transformation is returned as the result of the
command. This handle is the first argument given to all handler
methods, to allow the code to distinguish between the various
instances of the same transformation, if necessary.

Use the new '''chan pop''' command to remove the transformation. See
below.

The API this handler has to provide is specified below, in the section
"Command Handler API Specification".

We have chosen to use ''late-binding'' of the handler command. See
the section "Early- versus Late-Binding of the Handler Command" for
more detailed explanations.

The command invokes the handler method '''initialize''' to determine
the supported methods before it pushes the transformation. It will
throw an error if a read-only transformation is pushed on a write-only
channel, or vice versa. In general if the r/w-mode of transformation
and channel together cause the result to be neither readable nor
writable.

~~ The pop Subcommand

 > '''chan pop''' ''channel''

This subcommand removes the topmost transformation from the
''channel'', if there is any. This command is equivalent to the
builtin command ''close'' if the channel had no transformations added
to it.

Note: If the removal of the topmost transformation uncovers inactive
transformations (See section "Interaction with Threads and Other
Interpreters"), then these will be removed now as well.

~ Command Handler API Specification

The Tcl-level handler command for a reflected channel transformation
is an ensemble that has to support the following subcommands, as
listed below. Note that the term ''ensemble'' is used to generically
describe all command (prefixes) which are able to process
subcommands. This TIP is '''not''' tied to the recently introduced
'namespace ensemble's (though they may be used to implement such
handlers.)

~~ The initialize Subcommand

 > ''handler'' '''initialize''' ''handle mode''

This method is called first, and then never again (for the given
''handle''). Its responsibility is to initialize all parts of the
transformation at the Tcl level. The MODE is a list containing any of
'''read''' and '''write'''.

 * '''write''' contained in ''mode'' implies that the channel is writable.

 * '''read'''  contained in ''mode'' implies that the channel is readable.

The return value of the method has to be a list containing the
names of all methods which are supported by this handler. Any error
thrown by the method will prevent the creation of the
transformation. The thrown error will appear as error thrown by
'''chan push'''.

The current version is ''1''.

This method has no equivalent at the C level.

~~ The finalize Subcommand

 > ''handler'' '''finalize''' ''handle''

This method is called last for the given ''handle'', just before the
destruction of the C level data structures. It is now its
responsibility to clean up all parts of the transformation at the Tcl
level.

Any result returned by the method will be ignored. The same is true
for errors thrown by the method.

This method has no equivalent at the C level.

~~ The flush Subcommand

 > ''handler'' '''flush''' ''handle''

This method is called whenever data in the transformation 'write'
buffer has to be forced downward, i.e. towards the base channel. The
result returned by the method is taken as the ''binary'' data to write
to the transformation below the current transformation. This can be
the base channel as well.

In other words, when this method is called the transformation cannot
defer the actual transformation operation anymore and has to transform
all data waiting in its internal write buffers and return the result
of that action.

The method is optional. However if this method is supported then
'''write''' has to be supported as well. The reverse is not true.

~~ The write Subcommand

 > ''handler'' '''write''' ''handle buffer''

This method is optional. If it is not present it means that the
transformation does not support writing, and the channel it was pushed
on becomes non-writable as well.

It will be called whenever the user, or a transformation above this
transformation writes data downward. The ''buffer'' contains the
'''binary''' data which has been written to us. It is the
responsibility of this method to actually transform the data.

The result returned by the method is taken as the '''binary''' data to
write to the transformation below this transformation. This can be the
base channel as well. Note that the result is allowed to be empty, or
less than the data we got. The transformation is not required to
transform everything which was written to it right now. It is allowed
to store this data in internal buffers and to defer the actual
transformation until it has more data.

~~ The drain Subcommand

 > ''handler'' '''drain''' ''handle''

This method is called whenever data in the transformation input
(i.e. read) buffer has to be forced upward, i.e. towards the user,
i.e. the script. The result returned by the method is taken as the
'''binary''' data to push upward to the transformation above this
transformation. This can be the script as well.

In other words, when this method is called the transformation cannot
defer the actual transformation operation anymore and has to transform
all data waiting in its internal read buffers and return the result of
that action.

The method is optional. However if this method is supported then
'''read''' has to be supported as well. The reverse is not true.

~~ The read Subcommand

 > ''handler'' '''read''' ''handle buffer''

This method is optional. If it is not present it means that the
transformation does not support reading, and the channel it was pushed
on becomes non-readable as well.

It is called whenever the base channel, or a transformation below this
transformation pushes data upward. The ''buffer'' contains the
'''binary''' data which has been given to us from below. It is the
responsibility of this method to actually transform data. The result
returned by the method is taken as the '''binary''' data to push
further upward to the transformation above this transformation. This
can be the user, i.e. the script as well.

Note that the result is allowed to be empty, or even less than the
data we got. The transformation is not required to transform
everything given to it right now. It is allowed to store incoming data
in internal buffers and to defer the actual transformation until it
has more data.

~~ The limit? Subcommand

 > ''handler'' '''limit?''' ''handle''

This method is optional. If it is not present it means that the
transformation is allowed to read ahead as much as it likes.

This method is called during input processing and allows the Tcl level
part of the transformation to restrict the number of bytes read
from the downward transformation or base channel before its method
'''read''' is called with the resulting buffer.

The result of the method has to be an integer number not equal to
zero. A negative result signals that the transformation allows the I/O
system to read an unlimited number of bytes. A positive number on
the other hand is interpreted as the maximum number of bytes the
I/O system is allowed to read from the downward transformation or base
channel.

This method is necessary for transformations where the data is bounded
at the end in some way. In that case the transformation has to prevent
the system from reading beyond the boundary as otherwise data behind
it will be given to the transformation and then lost when the
transformation is removed. '''This is a limitation of the current I/O
core''' as it does not allow a transformation to push unused data back
into the I/O core when the transformation is removed from the channel.

Fixing this '''limitation''' requires a separate TIP, as either the
public API of the I/O core has to be extended, or the public structure
of channel drivers.

~~ The clear Subcommand

 > ''handler'' '''clear''' ''handle''

This method is called to clear any data stored in the internal input
buffers of the transformation. This happens only when the user seeks
the channel the transformation is attached to.

Any result returned by the method is ignored.

The method is optional. I.e. a transformation not having any internal
buffers to clear can leave out its implementation.

~ Hardwired Behavior of Reflected Transformations

Not all functions of the channel driver implementing the reflected
transformation are directly reflected into the Tcl level. Their
behavior is hardwired in the C level implementing the reflection and
specified now.

 BlockModeProc: Records the chosen blocking mode in the C-level data
   structures. This influences the low-level write and read behavior.
   However the Tcl level is shielded from this, so a handler method is
   not required.

 CloseProc: Invokes the methods '''drain''' and '''flush''' to clean
   up any buffers managed by the Tcl level of the transformation, and
   then '''finalize'''. '''drain''' is not called if a previous call
   to it has not been invalidated yet.

 InputProc: Tries to satisfies the incoming read request from the
   input result buffer first. If that is not enough it invokes the
   '''limit?'''  method to establish the current read limit, reads
   data from the downward transformation or base channel per the limit
   and feeds the data it got to the Tcl level of the transformation,
   via an invocation of the method '''read'''. The result of that call
   is added to the input result buffer and used to further satisfy the
   read request.

 > If the channel is blocking the system will iterate until the
   request is fulfilled completely or EOF has been signaled from
   below.

 > In non-blocking mode however the loop will stop if either the
   request was fulfilled completely, or if we would block. Note that
   reaching EOF in this situation causes a flush of the Tcl side input
   buffers via an invocation of the method '''drain'''. Otherwise the
   data stored in them would be lost when the transformation is
   removed or the channel closed completely.

 OutputProc: Simply forwards the written buffer to the method
   '''write''' for processing and then writes any returned result to
   the transformation or base channel below.

 SeekProc: Recognizes requests made by '''tell''' and passes them down
   without doing anything else. The result generated by the base
   channel is then passed back up unchanged.

 > Any other request causes it to flush all write buffers on the Tcl
   side via an invocation of the method '''flush''', and clear all
   input buffers on the Tcl side via an invocation of the method
   '''clear''' before passing the request down. Note that the calls
   mentioned above are not made if the channel is not writable, or not
   readable. Further note that the results of the '''flush''' are
   discarded, not written, as they would otherwise move the current
   location and throw off our expectations regarding where we are now
   and will end up after the seek.

 > This implements the most simple seek behavior as it was found in
   the very earliest incarnation of the transform reflection
   functionality, i.e. passing down any seek request unchanged until
   the base channel is reached. This also means that the internal
   state of transformations is not adjusted after a seek and may
   generate bogus results.

 > The reflection (actually any transformation) provided by the
   package ''Trf'' has much more complex seek behavior. This was left
   out for now to keep the scope of this TIP relatively focused. A
   follow-up TIP can be written for a deeper discussion of the
   interaction between seeking and any type of transformation, not
   only reflected ones.

 > See http://www.oche.de/~akupries/soft/trf/trf_seek.html for the
   description of the complex seeking model used by the transformation
   reflection in Trf.

 SetOptionProc, GetOptionProc, GetFileHandleProc: The calls are passed
   down without change, any results are passed back to the caller,
   again without any changes.

 > Transformations have no options which can be configured when they
   are attached to a channel, hence the pass-through and no handler
   method at the Tcl level.

 WatchProc: Remembers the interest mask provided by the caller and
   uses this to manage the internal timer used to generate fake file
   events when data is buffered.

 NotifyProc: Manages the internal timer. Will pass the
   incoming mask of triggered events upward without change.

~ Interaction with Threads and Other Interpreters

Adding a reflected transformation to a channel does not create any
restrictions on the sharing of the channel with other interpreters,
nor with moving the channel to different interpreters or threads.

Like for reflected channels (See [219] ('Tcl Channel Reflection
API')), the implementation ensures that the handler command is always
executed in the original interpreter and thread. The latter is done by
posting specialized events to the original thread, essentially
forwarding driver invocations to the correct thread.

When a thread or interpreter is deleted all transformations it owns are deleted as far as possible, and any remnants are marked as dead. The latter occurs only if the channel using the deleted transformation is outside of the deleted thread or interpreter. Such channels will throw errors when accessed, until the offending transformation is removed from them via '''chan pop''' (Multiple pop's will be necessary if the deleted transformation sits in the middle of a stack).

~ Interaction with Safe Interpreters

The new subcommands '''push''' and '''pop''' of '''chan''' are both
safe and therefore made accessible to safe interpreters.

While '''push'''ing a transformation arranges for the execution of
code this code is always executed within the safe interpreter, even if
the channel was moved (See previous section).

That the data flowing through the channel is modified by the
transformation is no problem either, because to attach the
transformation to the channel it has to have been given to the safe
interpreter in the beginning, in other words, the interpreter doing
this already trusted the safe interpreter in some way, and the fact
that we can now add a transformation does not change this.

Equivalent reasoning applies if the channel was created by the safe
interpreter and then shared/moved into the trusted interpreter. The
transformation has no effect on the trust already given to the safe
interpreter through the share/move operation.

The same holds for the subcommand '''pop'''. If the safe interpreter
can execute it on a channel it has the channel already in its
possession, either because it created the channel, or because the
channel was shared/moved into it.

~ Event processing

It is specified that reflected transformations do not support any type
of user-visible event handling.

The only event handling done is the invisible passing of current
interest from higher to lower layers, and the (again invisible)
behaviour needed to drive the flushing of transformation buffers to
higher layers. See the descriptions of ''WatchProc'' and
''NotifyProc'' in the section '''Hardwired Behavior of Reflected
Transformations'''.

This is different from the previous revisions of this TIP which
included language and definitions to support event processing by
transformations up to and including revision 1.11, i.e. allowing
transformations to register interest in events, and then process them.

The main example use case for this was that it would give a
transformation the ability to initialize itself with data coming from
the channel (like a key exchange) before switching to the plain
transformative behaviour. While working on the design of how to
support this on the Tcl script level I ran into lots of complicated
edge cases and convolutions.

Based on this I have now come to the belief that this has been a
misfeature from the beginning and that the use case this was based on
(see above) is an example of comingling concerns which should be
separate, i.e an example of what should not be done.

The transformation's concern is transforming data, nothing else. Any
parameters needed for this, like keys, seeds, etc. should come from
the outside, at the time it is pushed on the channel stack.
Initializations like key exchanges, cipher negotiations, etc. should
and are not be a concern of the transformation. They should and can be
done '''before''' the transformation is configured and pushed.

This last means that the removal of user-visible event handling
support is by no means a restriction on the type of things we can
do. Even so, should we find other use cases for event handling by
transformations we can always write another TIP within which we
specify how to extend reflected transformations with that feature.

~ Early- versus Late-Binding of the Handler Command

We have two principal methods for using the handler command. These are
called early- and late-binding.

'''Early-binding''' means that the command implementation to use is
determined at the time of the creation of the channel, i.e. when
''chan push'' is executed, before any methods are called. Afterward it
cannot change. The result of the command resolution is stored
internally and used until the channel is destroyed. Renaming the
handler command has no effect. In other words, the system will
automatically call the command under the new name. The destruction of
the handler command is intercepted and causes the channel to close as
well.

'''Late-binding''' means that the handler command is stored internally
essentially as a string, and this string is mapped to the
implementation to use for each and every call to a method of the
handler. Renaming the command, or destroying it means that the next
call of a handler method will fail, causing the higher level channel
command to fail as well. Depending on the method the error message may
not be able to explain the reason of that failure.

Another problem with the late-binding approach is that the context for
the resolution of the command name has to be specified explicitly to
avoid problems with relative names. Early-binding resolves once, in
the context of the ''chan create''. Late-binding performs resolution
anywhere where channel commands like ''puts'', ''gets'', etc. are
called, i.e. in a random context. To prevent problems with different
commands of the same name in several namespace it becomes necessary to
force the usage of a specific fixed context for the resolution.

Note that moving a different command into place after renaming the
original handler allows the Tcl level to change the implementation
dynamically at runtime. This however is not really an advantage over
early-binding as the early-bound command can be written such that it
delegates to the actual implementation, and that can then be changed
dynamically as well.

However, despite all this late binding is so far the method of choice for the implementation of callbacks, be they in Tcl, or Tk; and has been chosen for the reflection as well.

The context for all handler method invokations is the '''global scope'''.

~ Limitations

The method '''limit?''' is required to limit reading from below to
prevent reading over transformation specific boundaries. This is a
direct consequence of not being able to push unused data back into the
I/O core when a transformation is removed.

The reflection implements the very simple seek behavior found in the
earliest incarnation of this functionality, i.e. passing down any
seek request unchanged until the base channel is reached. This also
means that the internal state of transformations is not adjusted
after a seek and may generate bogus results. The reflection
(actually any transformation) provided by the package ''Trf'' has
much more complex seek behavior. This was left out for now to keep
the scope of this TIP relatively focused. A follow-up TIP can be
written for a deeper discussion of the interaction between seeking
and any type of transformation, not only reflected ones.

See http://www.oche.de/~akupries/soft/trf/trf_seek.html for the
description of the complex seeking model used by the transformation
reflection in Trf.

~ Miscellanea

The transform reflection API reserves the driver type "tclrtransform"
for itself, and uses it to detect its own transformations. Usage of
this driver type by other transformations is not allowed.

~ Examples

~~ Transformation Implementations

A simple way of implementing new transformations is to use any of the
various object systems for Tcl. Create a class for the transformation.
'''chan push''' the transformation in the constructor for new objects
and store the transformation handle. Make the new object the command
handler for the transformation. This automatically translates the sub
commands for the command handler into object methods. Implement the
various methods required. When the object is deleted deactivate the
transformation, and delete the object when the channel announces that
the transformation has been '''chan pop'''ped. This part is a bit
tricky, flags have to be used to break the potential cycle.

Another possibility is to implement the command handler as a regular
command, together with a creation command wrapping around ''chan
push'' and a backend which keeps track of all handles created by it
and their state, associated data, etc.

~~ Possible Transformations

 * Identity

 * Gathering statistics about the channel. The simplest would be to
   count bytes, for example.

 * Divert a copy of all data to a separate channel.
   In other words, spying on the channel.

 * Give a channel which normally cannot seek backward the ability to
   do so through buffering (a limited amount of) the data read from it.

 * Limit reading from a channel to a specific finite number of
   characters (This can be done via a suitable implementation of
   the method "limit?" in the transformation handler).

~ Reference Implementation

A variant implementation of this TIP is already present in the core,
as part of the special test commands for exercising the various
internal of the Tcl core during test.

The relevant files are

 * "tclIOGT.c" (base implementation) and

 * "tclTest.c" (command interface).

The command interface specified here is different from the current
interface.

| test transform channel -command command

versus

| chan push channel cmdprefix
| chan pop

The handler methods are different as well. This TIP consolidated a
number of methods, gave them better names and removed unnecessary
arguments. It also removed some limitations.

The actual reference implementation is provided at SourceForge
[http://sourceforge.net/support/tracker.php?aid=1163274].

~ Comments

[[ Add comments on the document here ]]

~ Copyright

This document has been placed in the public domain.








|


|





|

|


|








|





|



|






|

|


|
|



|
|

|



|
|
|
|
|

|

|

|
|

|

|

|





|

|



|

|

|









|

|



|









|

|

|






|
|


|







|

|


|

|








|

|

|






|
|

|









|

|







|












|
|


|



|

|










|











|

|




|


|










|




|


|




|

|

|











|
|





|


















|





|
|




|

|

|


|

|













|




|





|

|
|
|








|






|







|







|




|

|







|










|
|













|

|

|









|





|



|





|

|



|





|



|
|


|










|


|
|

|







|

|




|



|
|






|

|

|

|


>
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
of the special test commands for exercising the various internal of
the Tcl core during test. This TIP asks to make that mechanism
publicly available to script and package authors, with a bit of
cleanup regarding the Tcl level API. The roots of that mechanism can
be traced back to the Trf package which implemented channel
transformations first and provides a similar command.

# Transform Management API Specification

The Tcl level API consists of two new subcommands added to the
ensemble command **chan**' specified by [[208]](208.md). Both subcommands are
completely generic, i.e. they can be applied to any type of channel,
without restrictions.  There is no C API to specify. The Tcl core
already has a standard API for the creation of channel transformations
from the C level.

## The push Subcommand

 > **chan push** _channel cmdprefix_

This subcommand creates a new script level transformation using the
command prefix _cmdprefix_ as its handler and attaches it to the
specified channel. The new transformation is always added on top of
any other transformations which may be present.

The handle of the new transformation is returned as the result of the
command. This handle is the first argument given to all handler
methods, to allow the code to distinguish between the various
instances of the same transformation, if necessary.

Use the new **chan pop** command to remove the transformation. See
below.

The API this handler has to provide is specified below, in the section
"Command Handler API Specification".

We have chosen to use _late-binding_ of the handler command. See
the section "Early- versus Late-Binding of the Handler Command" for
more detailed explanations.

The command invokes the handler method **initialize** to determine
the supported methods before it pushes the transformation. It will
throw an error if a read-only transformation is pushed on a write-only
channel, or vice versa. In general if the r/w-mode of transformation
and channel together cause the result to be neither readable nor
writable.

## The pop Subcommand

 > **chan pop** _channel_

This subcommand removes the topmost transformation from the
_channel_, if there is any. This command is equivalent to the
builtin command _close_ if the channel had no transformations added
to it.

Note: If the removal of the topmost transformation uncovers inactive
transformations \(See section "Interaction with Threads and Other
Interpreters"\), then these will be removed now as well.

# Command Handler API Specification

The Tcl-level handler command for a reflected channel transformation
is an ensemble that has to support the following subcommands, as
listed below. Note that the term _ensemble_ is used to generically
describe all command \(prefixes\) which are able to process
subcommands. This TIP is **not** tied to the recently introduced
'namespace ensemble's \(though they may be used to implement such
handlers.\)

## The initialize Subcommand

 > _handler_ **initialize** _handle mode_

This method is called first, and then never again \(for the given
_handle_\). Its responsibility is to initialize all parts of the
transformation at the Tcl level. The MODE is a list containing any of
**read** and **write**.

 * **write** contained in _mode_ implies that the channel is writable.

 * **read**  contained in _mode_ implies that the channel is readable.

The return value of the method has to be a list containing the
names of all methods which are supported by this handler. Any error
thrown by the method will prevent the creation of the
transformation. The thrown error will appear as error thrown by
**chan push**.

The current version is _1_.

This method has no equivalent at the C level.

## The finalize Subcommand

 > _handler_ **finalize** _handle_

This method is called last for the given _handle_, just before the
destruction of the C level data structures. It is now its
responsibility to clean up all parts of the transformation at the Tcl
level.

Any result returned by the method will be ignored. The same is true
for errors thrown by the method.

This method has no equivalent at the C level.

## The flush Subcommand

 > _handler_ **flush** _handle_

This method is called whenever data in the transformation 'write'
buffer has to be forced downward, i.e. towards the base channel. The
result returned by the method is taken as the _binary_ data to write
to the transformation below the current transformation. This can be
the base channel as well.

In other words, when this method is called the transformation cannot
defer the actual transformation operation anymore and has to transform
all data waiting in its internal write buffers and return the result
of that action.

The method is optional. However if this method is supported then
**write** has to be supported as well. The reverse is not true.

## The write Subcommand

 > _handler_ **write** _handle buffer_

This method is optional. If it is not present it means that the
transformation does not support writing, and the channel it was pushed
on becomes non-writable as well.

It will be called whenever the user, or a transformation above this
transformation writes data downward. The _buffer_ contains the
**binary** data which has been written to us. It is the
responsibility of this method to actually transform the data.

The result returned by the method is taken as the **binary** data to
write to the transformation below this transformation. This can be the
base channel as well. Note that the result is allowed to be empty, or
less than the data we got. The transformation is not required to
transform everything which was written to it right now. It is allowed
to store this data in internal buffers and to defer the actual
transformation until it has more data.

## The drain Subcommand

 > _handler_ **drain** _handle_

This method is called whenever data in the transformation input
\(i.e. read\) buffer has to be forced upward, i.e. towards the user,
i.e. the script. The result returned by the method is taken as the
**binary** data to push upward to the transformation above this
transformation. This can be the script as well.

In other words, when this method is called the transformation cannot
defer the actual transformation operation anymore and has to transform
all data waiting in its internal read buffers and return the result of
that action.

The method is optional. However if this method is supported then
**read** has to be supported as well. The reverse is not true.

## The read Subcommand

 > _handler_ **read** _handle buffer_

This method is optional. If it is not present it means that the
transformation does not support reading, and the channel it was pushed
on becomes non-readable as well.

It is called whenever the base channel, or a transformation below this
transformation pushes data upward. The _buffer_ contains the
**binary** data which has been given to us from below. It is the
responsibility of this method to actually transform data. The result
returned by the method is taken as the **binary** data to push
further upward to the transformation above this transformation. This
can be the user, i.e. the script as well.

Note that the result is allowed to be empty, or even less than the
data we got. The transformation is not required to transform
everything given to it right now. It is allowed to store incoming data
in internal buffers and to defer the actual transformation until it
has more data.

## The limit? Subcommand

 > _handler_ **limit?** _handle_

This method is optional. If it is not present it means that the
transformation is allowed to read ahead as much as it likes.

This method is called during input processing and allows the Tcl level
part of the transformation to restrict the number of bytes read
from the downward transformation or base channel before its method
**read** is called with the resulting buffer.

The result of the method has to be an integer number not equal to
zero. A negative result signals that the transformation allows the I/O
system to read an unlimited number of bytes. A positive number on
the other hand is interpreted as the maximum number of bytes the
I/O system is allowed to read from the downward transformation or base
channel.

This method is necessary for transformations where the data is bounded
at the end in some way. In that case the transformation has to prevent
the system from reading beyond the boundary as otherwise data behind
it will be given to the transformation and then lost when the
transformation is removed. **This is a limitation of the current I/O
core** as it does not allow a transformation to push unused data back
into the I/O core when the transformation is removed from the channel.

Fixing this **limitation** requires a separate TIP, as either the
public API of the I/O core has to be extended, or the public structure
of channel drivers.

## The clear Subcommand

 > _handler_ **clear** _handle_

This method is called to clear any data stored in the internal input
buffers of the transformation. This happens only when the user seeks
the channel the transformation is attached to.

Any result returned by the method is ignored.

The method is optional. I.e. a transformation not having any internal
buffers to clear can leave out its implementation.

# Hardwired Behavior of Reflected Transformations

Not all functions of the channel driver implementing the reflected
transformation are directly reflected into the Tcl level. Their
behavior is hardwired in the C level implementing the reflection and
specified now.

 BlockModeProc: Records the chosen blocking mode in the C-level data
   structures. This influences the low-level write and read behavior.
   However the Tcl level is shielded from this, so a handler method is
   not required.

 CloseProc: Invokes the methods **drain** and **flush** to clean
   up any buffers managed by the Tcl level of the transformation, and
   then **finalize**. **drain** is not called if a previous call
   to it has not been invalidated yet.

 InputProc: Tries to satisfies the incoming read request from the
   input result buffer first. If that is not enough it invokes the
   **limit?**  method to establish the current read limit, reads
   data from the downward transformation or base channel per the limit
   and feeds the data it got to the Tcl level of the transformation,
   via an invocation of the method **read**. The result of that call
   is added to the input result buffer and used to further satisfy the
   read request.

 > If the channel is blocking the system will iterate until the
   request is fulfilled completely or EOF has been signaled from
   below.

 > In non-blocking mode however the loop will stop if either the
   request was fulfilled completely, or if we would block. Note that
   reaching EOF in this situation causes a flush of the Tcl side input
   buffers via an invocation of the method **drain**. Otherwise the
   data stored in them would be lost when the transformation is
   removed or the channel closed completely.

 OutputProc: Simply forwards the written buffer to the method
   **write** for processing and then writes any returned result to
   the transformation or base channel below.

 SeekProc: Recognizes requests made by **tell** and passes them down
   without doing anything else. The result generated by the base
   channel is then passed back up unchanged.

 > Any other request causes it to flush all write buffers on the Tcl
   side via an invocation of the method **flush**, and clear all
   input buffers on the Tcl side via an invocation of the method
   **clear** before passing the request down. Note that the calls
   mentioned above are not made if the channel is not writable, or not
   readable. Further note that the results of the **flush** are
   discarded, not written, as they would otherwise move the current
   location and throw off our expectations regarding where we are now
   and will end up after the seek.

 > This implements the most simple seek behavior as it was found in
   the very earliest incarnation of the transform reflection
   functionality, i.e. passing down any seek request unchanged until
   the base channel is reached. This also means that the internal
   state of transformations is not adjusted after a seek and may
   generate bogus results.

 > The reflection \(actually any transformation\) provided by the
   package _Trf_ has much more complex seek behavior. This was left
   out for now to keep the scope of this TIP relatively focused. A
   follow-up TIP can be written for a deeper discussion of the
   interaction between seeking and any type of transformation, not
   only reflected ones.

 > See <http://www.oche.de/~akupries/soft/trf/trf\_seek.html> for the
   description of the complex seeking model used by the transformation
   reflection in Trf.

 SetOptionProc, GetOptionProc, GetFileHandleProc: The calls are passed
   down without change, any results are passed back to the caller,
   again without any changes.

 > Transformations have no options which can be configured when they
   are attached to a channel, hence the pass-through and no handler
   method at the Tcl level.

 WatchProc: Remembers the interest mask provided by the caller and
   uses this to manage the internal timer used to generate fake file
   events when data is buffered.

 NotifyProc: Manages the internal timer. Will pass the
   incoming mask of triggered events upward without change.

# Interaction with Threads and Other Interpreters

Adding a reflected transformation to a channel does not create any
restrictions on the sharing of the channel with other interpreters,
nor with moving the channel to different interpreters or threads.

Like for reflected channels \(See [[219]](219.md) \('Tcl Channel Reflection
API'\)\), the implementation ensures that the handler command is always
executed in the original interpreter and thread. The latter is done by
posting specialized events to the original thread, essentially
forwarding driver invocations to the correct thread.

When a thread or interpreter is deleted all transformations it owns are deleted as far as possible, and any remnants are marked as dead. The latter occurs only if the channel using the deleted transformation is outside of the deleted thread or interpreter. Such channels will throw errors when accessed, until the offending transformation is removed from them via **chan pop** \(Multiple pop's will be necessary if the deleted transformation sits in the middle of a stack\).

# Interaction with Safe Interpreters

The new subcommands **push** and **pop** of **chan** are both
safe and therefore made accessible to safe interpreters.

While **push**ing a transformation arranges for the execution of
code this code is always executed within the safe interpreter, even if
the channel was moved \(See previous section\).

That the data flowing through the channel is modified by the
transformation is no problem either, because to attach the
transformation to the channel it has to have been given to the safe
interpreter in the beginning, in other words, the interpreter doing
this already trusted the safe interpreter in some way, and the fact
that we can now add a transformation does not change this.

Equivalent reasoning applies if the channel was created by the safe
interpreter and then shared/moved into the trusted interpreter. The
transformation has no effect on the trust already given to the safe
interpreter through the share/move operation.

The same holds for the subcommand **pop**. If the safe interpreter
can execute it on a channel it has the channel already in its
possession, either because it created the channel, or because the
channel was shared/moved into it.

# Event processing

It is specified that reflected transformations do not support any type
of user-visible event handling.

The only event handling done is the invisible passing of current
interest from higher to lower layers, and the \(again invisible\)
behaviour needed to drive the flushing of transformation buffers to
higher layers. See the descriptions of _WatchProc_ and
_NotifyProc_ in the section **Hardwired Behavior of Reflected
Transformations**.

This is different from the previous revisions of this TIP which
included language and definitions to support event processing by
transformations up to and including revision 1.11, i.e. allowing
transformations to register interest in events, and then process them.

The main example use case for this was that it would give a
transformation the ability to initialize itself with data coming from
the channel \(like a key exchange\) before switching to the plain
transformative behaviour. While working on the design of how to
support this on the Tcl script level I ran into lots of complicated
edge cases and convolutions.

Based on this I have now come to the belief that this has been a
misfeature from the beginning and that the use case this was based on
\(see above\) is an example of comingling concerns which should be
separate, i.e an example of what should not be done.

The transformation's concern is transforming data, nothing else. Any
parameters needed for this, like keys, seeds, etc. should come from
the outside, at the time it is pushed on the channel stack.
Initializations like key exchanges, cipher negotiations, etc. should
and are not be a concern of the transformation. They should and can be
done **before** the transformation is configured and pushed.

This last means that the removal of user-visible event handling
support is by no means a restriction on the type of things we can
do. Even so, should we find other use cases for event handling by
transformations we can always write another TIP within which we
specify how to extend reflected transformations with that feature.

# Early- versus Late-Binding of the Handler Command

We have two principal methods for using the handler command. These are
called early- and late-binding.

**Early-binding** means that the command implementation to use is
determined at the time of the creation of the channel, i.e. when
_chan push_ is executed, before any methods are called. Afterward it
cannot change. The result of the command resolution is stored
internally and used until the channel is destroyed. Renaming the
handler command has no effect. In other words, the system will
automatically call the command under the new name. The destruction of
the handler command is intercepted and causes the channel to close as
well.

**Late-binding** means that the handler command is stored internally
essentially as a string, and this string is mapped to the
implementation to use for each and every call to a method of the
handler. Renaming the command, or destroying it means that the next
call of a handler method will fail, causing the higher level channel
command to fail as well. Depending on the method the error message may
not be able to explain the reason of that failure.

Another problem with the late-binding approach is that the context for
the resolution of the command name has to be specified explicitly to
avoid problems with relative names. Early-binding resolves once, in
the context of the _chan create_. Late-binding performs resolution
anywhere where channel commands like _puts_, _gets_, etc. are
called, i.e. in a random context. To prevent problems with different
commands of the same name in several namespace it becomes necessary to
force the usage of a specific fixed context for the resolution.

Note that moving a different command into place after renaming the
original handler allows the Tcl level to change the implementation
dynamically at runtime. This however is not really an advantage over
early-binding as the early-bound command can be written such that it
delegates to the actual implementation, and that can then be changed
dynamically as well.

However, despite all this late binding is so far the method of choice for the implementation of callbacks, be they in Tcl, or Tk; and has been chosen for the reflection as well.

The context for all handler method invokations is the **global scope**.

# Limitations

The method **limit?** is required to limit reading from below to
prevent reading over transformation specific boundaries. This is a
direct consequence of not being able to push unused data back into the
I/O core when a transformation is removed.

The reflection implements the very simple seek behavior found in the
earliest incarnation of this functionality, i.e. passing down any
seek request unchanged until the base channel is reached. This also
means that the internal state of transformations is not adjusted
after a seek and may generate bogus results. The reflection
\(actually any transformation\) provided by the package _Trf_ has
much more complex seek behavior. This was left out for now to keep
the scope of this TIP relatively focused. A follow-up TIP can be
written for a deeper discussion of the interaction between seeking
and any type of transformation, not only reflected ones.

See <http://www.oche.de/~akupries/soft/trf/trf\_seek.html> for the
description of the complex seeking model used by the transformation
reflection in Trf.

# Miscellanea

The transform reflection API reserves the driver type "tclrtransform"
for itself, and uses it to detect its own transformations. Usage of
this driver type by other transformations is not allowed.

# Examples

## Transformation Implementations

A simple way of implementing new transformations is to use any of the
various object systems for Tcl. Create a class for the transformation.
**chan push** the transformation in the constructor for new objects
and store the transformation handle. Make the new object the command
handler for the transformation. This automatically translates the sub
commands for the command handler into object methods. Implement the
various methods required. When the object is deleted deactivate the
transformation, and delete the object when the channel announces that
the transformation has been **chan pop**ped. This part is a bit
tricky, flags have to be used to break the potential cycle.

Another possibility is to implement the command handler as a regular
command, together with a creation command wrapping around _chan
push_ and a backend which keeps track of all handles created by it
and their state, associated data, etc.

## Possible Transformations

 * Identity

 * Gathering statistics about the channel. The simplest would be to
   count bytes, for example.

 * Divert a copy of all data to a separate channel.
   In other words, spying on the channel.

 * Give a channel which normally cannot seek backward the ability to
   do so through buffering \(a limited amount of\) the data read from it.

 * Limit reading from a channel to a specific finite number of
   characters \(This can be done via a suitable implementation of
   the method "limit?" in the transformation handler\).

# Reference Implementation

A variant implementation of this TIP is already present in the core,
as part of the special test commands for exercising the various
internal of the Tcl core during test.

The relevant files are

 * "tclIOGT.c" \(base implementation\) and

 * "tclTest.c" \(command interface\).

The command interface specified here is different from the current
interface.

	 test transform channel -command command

versus

	 chan push channel cmdprefix
	 chan pop

The handler methods are different as well. This TIP consolidated a
number of methods, gave them better names and removed unnecessary
arguments. It also removed some limitations.

The actual reference implementation is provided at SourceForge
<http://sourceforge.net/support/tracker.php?aid=1163274> .

# Comments

[ Add comments on the document here ]

# Copyright

This document has been placed in the public domain.

Name change from tip/231.tip to tip/231.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

TIP:		231
Title:		Support for [wm attributes] on X11
Version:	$Revision: 1.7 $
Author:		Joe English <[email protected]>
State:		Final
Type:		Project
Created:	06-Nov-2004
Tcl-Version:	8.5
Vote:		Done
Post-History:	


~ Abstract

This TIP adds three UNIX/X11-specific attributes to the '''wm
attributes''' command to take advantage of features newer Unix window
manager control standards.

~ Specification

This TIP proposes to add support for the following window attributes
under X11 in the '''wm attributes''' command:

 * '''-fullscreen'''

 > This attribute has the same meaning as the equivalent option for
   Windows (see [223]) with one restriction (outlined below).

 * '''-topmost'''

 > This attribute has the same meaning as the equivalent option for
   Windows (see [95]) with one restriction (outlined below).

 * '''-zoomed'''

 > This attribute requests that the window be maximized; it is the
   same as [['''wm state''' ''win'' '''zoomed''']] on Windows, subject
   to the restriction outlined below.

~ Restrictions

Under X11, the '''-fullscreen''', '''-topmost''', and '''-zoomed'''
attributes require cooperation from the window manager.  If the window
manager does not support these attributes, setting them will have no
effect.  In particular, they are not supported by older window
managers like MWM and DTWM.

Under X11, the '''wm attributes''' command operates asynchronously:
[['''wm attributes''' ''-attribute'']] returns the current value of
the attribute, which will not be the same as the value most recently
set if the window manager has not yet processed the request or if it
does not support the attribute.

~ Reference Implementation

See patch #1062022 [http://sf.net/support/tracker.php?aid=1062022]
which is based on the freedesktop.org Extended Window Manager Hints
specification [http://www.freedesktop.org/Standards/wm-spec].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|


|


|

|

|
|

|

|
|

|

|
|


|

|





|
|




|

|

|

|


>

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

# TIP 231: Support for [wm attributes] on X11

	Author:		Joe English <[email protected]>
	State:		Final
	Type:		Project
	Created:	06-Nov-2004
	Tcl-Version:	8.5
	Vote:		Done
	Post-History:	
-----

# Abstract

This TIP adds three UNIX/X11-specific attributes to the **wm
attributes** command to take advantage of features newer Unix window
manager control standards.

# Specification

This TIP proposes to add support for the following window attributes
under X11 in the **wm attributes** command:

 * **-fullscreen**

	 > This attribute has the same meaning as the equivalent option for
   Windows \(see [[223]](223.md)\) with one restriction \(outlined below\).

 * **-topmost**

	 > This attribute has the same meaning as the equivalent option for
   Windows \(see [[95]](95.md)\) with one restriction \(outlined below\).

 * **-zoomed**

	 > This attribute requests that the window be maximized; it is the
   same as [**wm state** _win_ **zoomed**] on Windows, subject
   to the restriction outlined below.

# Restrictions

Under X11, the **-fullscreen**, **-topmost**, and **-zoomed**
attributes require cooperation from the window manager.  If the window
manager does not support these attributes, setting them will have no
effect.  In particular, they are not supported by older window
managers like MWM and DTWM.

Under X11, the **wm attributes** command operates asynchronously:
[**wm attributes** _-attribute_] returns the current value of
the attribute, which will not be the same as the value most recently
set if the window manager has not yet processed the request or if it
does not support the attribute.

# Reference Implementation

See patch \#1062022 <http://sf.net/support/tracker.php?aid=1062022> 
which is based on the freedesktop.org Extended Window Manager Hints
specification <http://www.freedesktop.org/Standards/wm-spec> .

# Copyright

This document has been placed in the public domain.

Name change from tip/232.tip to tip/232.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
136
137
138
139
140
141
142


143
144
145

146
147
148
149
150
151
152
153
154
155
156
157


158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

TIP:            232
Title:          Creating New Math Functions for the 'expr' Command
Version:        $Revision: 1.11 $
Author:         Arjen Markus <[email protected]>
Author:         Kevin Kenny <[email protected] >
State:          Final
Type:           Project
Vote:           Done
Created:        26-Nov-2004
Post-History:   
Keywords:       math,expr,Tcl
Tcl-Version:    8.5


~ Abstract

This TIP proposes to replace Tcl's math functions, ordinarily created
using the '''Tcl_CreateMathFunc()''' function, with ordinary Tcl
commands created in a known namespace, '''::tcl::mathfunc'''. This
change has two chief motivations: it allows programmers to define new
math functions at the Tcl level, and it encapsulates the
'''Tcl_Value''' API so that new math functions can work on data types
that are not described adequately as '''Tcl_Value''' objects.

~ Rationale

The two authors of this TIP, Kevin Kenny and Arjen Markus, have come at 
wanting the same change to Tcl from two distinct directions.

Arjen Markus has been the maintainer of several modules in Tcllib that
implement "special functions" such as the exponential integral, the
incomplete gamma function and the Bessel functions.  He has wanted to
have "scripted" math functions available to simplify his notation.  In
place of a complex expression like

|  set f [expr { $x*[J0 $x] + [J1 [expr {2.0*$x}]] }]

which is pretty unreadable (and prone to error because of the need
to brace the subexpressions), he would like a mechanism for defining
new mathematical functions so that he can write:

|  set f [expr { $x*J0($x) + J1(2.0*$x) }]

Donal Fellows has felt the need for such a construct, too, enough to
implement a "funcproc" extension that provides it.
[http://wiki.tcl.tk/541] 

Kevin Kenny has come at the desire for rework of the math function
mechanism from a different direction.  He has been investigating
Tcl Core support for arbitrary-precision integers [237], and discovered that
implementing math functions that accept them as arguments or return
them as results would require an incompatible change to the
'''Tcl_Value''' data type that is used to communicate with the math
functions.  When the last such change was made (in implementing
64-bit integers [72]), it required a source code change
to several popular extensions that
created new math functions ''min'' and ''max''.  Wishing the
incompatibility introduced by [237] to be the last of the type, he
decided to eliminate '''Tcl_Value''' and use the open-ended
'''Tcl_Obj''' data type in its place.  When he derived the type signature that
a math function would have if it accepted its parameters in an array
of '''Tcl_Obj''' pointers, he discovered that it was identical to the
'''Tcl_ObjCmdProc''' -- making him ask, "what if math functions really
''were'' commands?"

This TIP is the result of those two investigations, and proposes a unification
of math functions with Tcl commands.

~ Proposed Changes

This TIP proposes that:

 1. The [[expr]] command shall be modified so that an expression of the form:

|   f(arg1,arg2,...)

 >  shall generate code equivalent to that generated by

|   [tcl::mathfunc::f [expr { arg1 }] [expr { arg2 }] ...]

 >  so that math functions are interpreted as Tcl commands whose arguments
    are parsed as subexpressions.  The existing code in [[expr]] that checks
    for correct argument counts to the math functions at compile time shall
    be removed (the general consensus among Core maintainers is that
    compile-time checks of this sort are a bad idea anyway).

 >  Note that the call to ''tcl::mathfunc::f'' has no leading namespace
    delimiter.  A search for the function will try to resolve it first
    relative to the current namespace.

 1. The current math functions in Tcl shall be reimplemented as ordinary
    Tcl commands in the '''::tcl::mathfunc''' namespace; a Tcl interpreter
    will contain commands '''::tcl::mathfunc::abs''', 
    '''::tcl::mathfunc::acos''', etc.  

 1. The Tcl command [[info functions]] shall be deprecated in favor of
    searching for math functions using [[info commands]] in the appropriate
    namespace.

 1. The C functions '''Tcl_CreateMathFunc''', '''Tcl_GetMathFuncInfo''',
    and '''Tcl_ListMathFuncs''' shall be deprecated in favor of
    '''Tcl_CreateObjCommand''', '''Tcl_GetCommandInfo''' and
    [[info commands]].  (The last is provided only in Tcl at the
    present time; we do not export a C-level interface to enumerate
    commands in a namespace.)  The functions will continue to work
    for extensions that use them.  The '''Tcl_CreateMathFunc''' command
    will create a Tcl command in the '''::tcl::mathfunc''' namespace
    whose command procedure checks argument count and types and
    dispatches to the math function handler.  The '''Tcl_GetMathFuncInfo'''
    procedure will return ''TCL_OK'' or ''TCL_ERROR'' according to
    whether the given math function exists in '''::tcl::mathfunc'''
    and will return parameter information for (only) those functions
    defined using '''Tcl_CreateMathFunc'''.  Functions defined as
    ordinary Tcl commands shall return ''TCL_OK'' but have a parameter
    count of -1.  The '''Tcl_ListMathFuncs''' procedure will simply
    enumerate all the commands in the '''::tcl::mathfunc''' namespace.

 1. Several error messages change as a side effect of changing the
    math function implementation.  All of the new messages are more
    informative than the old ones (for instance, identifying which
    math function encountered a parameter error rather than a
    generic "too few/too many arguments to math function"), with the
    exception of the error message for an unknown function, which
    is replaced with "unknown command ::tcl::mathfunc::<the_command>"
    where <the_command> is the name of the missing function.

~ Discussion

The proposed change lifts several other restrictions in the way
math functions operate:

 1. There is no longer any restriction that new math functions must
    accept a fixed number of arguments, or, indeed, that their
    arguments and results must be numeric.  It will be possible to
    create variadic functions like:

|   proc ::tcl::mathfunc::min args {
|       set m Inf
|       foreach a $args {
|           if { $a < $m } {
|               set m $a
|           }
|       }


|       return $m
|   }


 1. It will be possible to compile Tcl code that refers to a math function
    that has not yet been defined.  That is:

|   proc foo { x } {
|       set have_f [llength [info commands ::tcl::mathfunc::f]]
|       if { $have_f } {
|           return [expr { f($x) }]
|       } else {
|           ... fallback ...
|       }
|   }



 >  will be a valid procedure. (In Tcl 8.4, the procedure will fail to
    compile if ''f'' is not known at compile time, something that
    runs contrary to the dynamic nature of Tcl.)

 1. Namespaces will be able to define their own math functions that
    are not visible outside those namespaces.  If a namespace defines
    a function '''[namespace current]]::tcl::mathfunc::f''', then calls to
    '''f''' in  expressions evaluated in that namespace will resolve
    to it in preference to '''::tcl::mathfunc::f'''.  Not only does
    this rule allow two extensions both to define functions '''f''' without
    collision, but it also allows an extension to override a builtin
    function such as '''sin'''.

Alas, all these improvements come at some cost of performance.  On
Kevin Kenny's machine, the command

| expr {sin(0.325)}

executes in roughly 520 nanoseconds before the change, and 870 nanoseconds
afterward.  Since the resolution of the function name is cached, name
lookup is not the problem; rather, the issue is that invoking the function
as a command needs to look for command traces; this whole mechanism costs
about 300-350 ns (and has been observed to do so in other contexts).  For
real-life expressions, the additional cost tends to vanish quickly into
statistical noise; variable access (with corresponding checks for traces)
and bytecode overhead quickly comes to dominate the performance for
all but the simplest expressions.

~ Safe Interpreters

It is not anticipated that exposing this functionality in a safe interpreter
will present any new problems for safety.  Any functionality that the
interpreter can access by defining or overriding math functions
is functionality that would have been available to it by calling
the functions as commands.

~ Impact on C-coded Extensions

Extensions coded in C that wish to create math functions accepting
parameters of type '''TCL_EITHER''' may find that they do not
get type coercion from parameters of new numeric types, such as
extended-precision integers.  The coding change to replace them
with Tcl commands is fairly easy and mechanical, at a level of
effort comparable to that needed for [72].  Moreover,
once it is completed, a math function will be using the
known '''Tcl_CreateObjCmd''' API, which has been stable since
Tcl 8.0 and is unlikely to change substantially in future releases.

The ''tbcload'' extension will need to implement a small amount
of bytecode translation to preserve compatibility with bytecode
compiled modules built against earlier versions of Tcl.  The reason
is that two bytecodes, '''INST_INVOKE_BUILTIN1''' and
'''INST_INVOKE_FUNC1''' have been eliminated from
'''Tcl_ExecuteByteCode''' since the compiler no longer emits them.
If this change for some reason should prove infeasible, we
can always put the bytecodes back into '''Tcl_ExecuteByteCode''',
but the authors of this TIP would prefer to avoid the code bloat.

~ Reference Implementation

A reference implementation is committed on the 'tcl-numerics-branch'
at SourceForge and may be retrieved with

| cvs -d:ext:[email protected]:/cvsroot/tcl checkout -rTIP232 tcl_numerics

~ Copyright

Copyright (c) 2005 by Kevin B. Kenny and Adriaan Markus.  All rights reserved.

This document may be distributed subject to the terms and conditions
set forth in the Open Publication License, version 1.0
[http://www.opencontent.org/openpub/].

<
|
<
|
|
|
|
|
|
|
|
|
>

|


|
|


|
|

|










|

|
|


|



|



|


|
|
|

|
|
|
|

|
|
|




|



|

|

|

|

|
|

|
|

|




|
|
|

|
|


|
|
|
|

|
|
|

|
|
|
|
|
|
|
|



|

|

|
|

|









|
|
|
|
|
<
<
>
>
|
<
|
>



|
|
|
|
|
|
<
<
|
>
>
|
|
|



|
|
|
|

|




|





|

|



|







|


|



|

|


|


|
|
|

|


|




|

|

|



|
>

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
136
137
138
139


140
141
142

143
144
145
146
147
148
149
150
151
152
153


154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

# TIP 232: Creating New Math Functions for the 'expr' Command

	Author:         Arjen Markus <[email protected]>
	Author:         Kevin Kenny <[email protected] >
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        26-Nov-2004
	Post-History:   
	Keywords:       math,expr,Tcl
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to replace Tcl's math functions, ordinarily created
using the **Tcl\_CreateMathFunc\(\)** function, with ordinary Tcl
commands created in a known namespace, **::tcl::mathfunc**. This
change has two chief motivations: it allows programmers to define new
math functions at the Tcl level, and it encapsulates the
**Tcl\_Value** API so that new math functions can work on data types
that are not described adequately as **Tcl\_Value** objects.

# Rationale

The two authors of this TIP, Kevin Kenny and Arjen Markus, have come at 
wanting the same change to Tcl from two distinct directions.

Arjen Markus has been the maintainer of several modules in Tcllib that
implement "special functions" such as the exponential integral, the
incomplete gamma function and the Bessel functions.  He has wanted to
have "scripted" math functions available to simplify his notation.  In
place of a complex expression like

	  set f [expr { $x*[J0 $x] + [J1 [expr {2.0*$x}]] }]

which is pretty unreadable \(and prone to error because of the need
to brace the subexpressions\), he would like a mechanism for defining
new mathematical functions so that he can write:

	  set f [expr { $x*J0($x) + J1(2.0*$x) }]

Donal Fellows has felt the need for such a construct, too, enough to
implement a "funcproc" extension that provides it.
<http://wiki.tcl.tk/541>  

Kevin Kenny has come at the desire for rework of the math function
mechanism from a different direction.  He has been investigating
Tcl Core support for arbitrary-precision integers [[237]](237.md), and discovered that
implementing math functions that accept them as arguments or return
them as results would require an incompatible change to the
**Tcl\_Value** data type that is used to communicate with the math
functions.  When the last such change was made \(in implementing
64-bit integers [[72]](72.md)\), it required a source code change
to several popular extensions that
created new math functions _min_ and _max_.  Wishing the
incompatibility introduced by [[237]](237.md) to be the last of the type, he
decided to eliminate **Tcl\_Value** and use the open-ended
**Tcl\_Obj** data type in its place.  When he derived the type signature that
a math function would have if it accepted its parameters in an array
of **Tcl\_Obj** pointers, he discovered that it was identical to the
**Tcl\_ObjCmdProc** -- making him ask, "what if math functions really
_were_ commands?"

This TIP is the result of those two investigations, and proposes a unification
of math functions with Tcl commands.

# Proposed Changes

This TIP proposes that:

 1. The [expr] command shall be modified so that an expression of the form:

		   f(arg1,arg2,...)

	 >  shall generate code equivalent to that generated by

		   [tcl::mathfunc::f [expr { arg1 }] [expr { arg2 }] ...]

	 >  so that math functions are interpreted as Tcl commands whose arguments
    are parsed as subexpressions.  The existing code in [expr] that checks
    for correct argument counts to the math functions at compile time shall
    be removed \(the general consensus among Core maintainers is that
    compile-time checks of this sort are a bad idea anyway\).

	 >  Note that the call to _tcl::mathfunc::f_ has no leading namespace
    delimiter.  A search for the function will try to resolve it first
    relative to the current namespace.

 1. The current math functions in Tcl shall be reimplemented as ordinary
    Tcl commands in the **::tcl::mathfunc** namespace; a Tcl interpreter
    will contain commands **::tcl::mathfunc::abs**, 
    **::tcl::mathfunc::acos**, etc.  

 1. The Tcl command [info functions] shall be deprecated in favor of
    searching for math functions using [info commands] in the appropriate
    namespace.

 1. The C functions **Tcl\_CreateMathFunc**, **Tcl\_GetMathFuncInfo**,
    and **Tcl\_ListMathFuncs** shall be deprecated in favor of
    **Tcl\_CreateObjCommand**, **Tcl\_GetCommandInfo** and
    [info commands].  \(The last is provided only in Tcl at the
    present time; we do not export a C-level interface to enumerate
    commands in a namespace.\)  The functions will continue to work
    for extensions that use them.  The **Tcl\_CreateMathFunc** command
    will create a Tcl command in the **::tcl::mathfunc** namespace
    whose command procedure checks argument count and types and
    dispatches to the math function handler.  The **Tcl\_GetMathFuncInfo**
    procedure will return _TCL\_OK_ or _TCL\_ERROR_ according to
    whether the given math function exists in **::tcl::mathfunc**
    and will return parameter information for \(only\) those functions
    defined using **Tcl\_CreateMathFunc**.  Functions defined as
    ordinary Tcl commands shall return _TCL\_OK_ but have a parameter
    count of -1.  The **Tcl\_ListMathFuncs** procedure will simply
    enumerate all the commands in the **::tcl::mathfunc** namespace.

 1. Several error messages change as a side effect of changing the
    math function implementation.  All of the new messages are more
    informative than the old ones \(for instance, identifying which
    math function encountered a parameter error rather than a
    generic "too few/too many arguments to math function"\), with the
    exception of the error message for an unknown function, which
    is replaced with "unknown command ::tcl::mathfunc::<the\_command>"
    where <the\_command> is the name of the missing function.

# Discussion

The proposed change lifts several other restrictions in the way
math functions operate:

 1. There is no longer any restriction that new math functions must
    accept a fixed number of arguments, or, indeed, that their
    arguments and results must be numeric.  It will be possible to
    create variadic functions like:

		   proc ::tcl::mathfunc::min args {
		       set m Inf
		       foreach a $args {
		           if { $a < $m } {
		               set m $a


		           }
		       }
		       return $m

		   }

 1. It will be possible to compile Tcl code that refers to a math function
    that has not yet been defined.  That is:

		   proc foo { x } {
		       set have_f [llength [info commands ::tcl::mathfunc::f]]
		       if { $have_f } {
		           return [expr { f($x) }]
		       } else {
		           ... fallback ...


		       }
		   }

	 >  will be a valid procedure. \(In Tcl 8.4, the procedure will fail to
    compile if _f_ is not known at compile time, something that
    runs contrary to the dynamic nature of Tcl.\)

 1. Namespaces will be able to define their own math functions that
    are not visible outside those namespaces.  If a namespace defines
    a function **[namespace current]::tcl::mathfunc::f**, then calls to
    **f** in  expressions evaluated in that namespace will resolve
    to it in preference to **::tcl::mathfunc::f**.  Not only does
    this rule allow two extensions both to define functions **f** without
    collision, but it also allows an extension to override a builtin
    function such as **sin**.

Alas, all these improvements come at some cost of performance.  On
Kevin Kenny's machine, the command

	 expr {sin(0.325)}

executes in roughly 520 nanoseconds before the change, and 870 nanoseconds
afterward.  Since the resolution of the function name is cached, name
lookup is not the problem; rather, the issue is that invoking the function
as a command needs to look for command traces; this whole mechanism costs
about 300-350 ns \(and has been observed to do so in other contexts\).  For
real-life expressions, the additional cost tends to vanish quickly into
statistical noise; variable access \(with corresponding checks for traces\)
and bytecode overhead quickly comes to dominate the performance for
all but the simplest expressions.

# Safe Interpreters

It is not anticipated that exposing this functionality in a safe interpreter
will present any new problems for safety.  Any functionality that the
interpreter can access by defining or overriding math functions
is functionality that would have been available to it by calling
the functions as commands.

# Impact on C-coded Extensions

Extensions coded in C that wish to create math functions accepting
parameters of type **TCL\_EITHER** may find that they do not
get type coercion from parameters of new numeric types, such as
extended-precision integers.  The coding change to replace them
with Tcl commands is fairly easy and mechanical, at a level of
effort comparable to that needed for [[72]](72.md).  Moreover,
once it is completed, a math function will be using the
known **Tcl\_CreateObjCmd** API, which has been stable since
Tcl 8.0 and is unlikely to change substantially in future releases.

The _tbcload_ extension will need to implement a small amount
of bytecode translation to preserve compatibility with bytecode
compiled modules built against earlier versions of Tcl.  The reason
is that two bytecodes, **INST\_INVOKE\_BUILTIN1** and
**INST\_INVOKE\_FUNC1** have been eliminated from
**Tcl\_ExecuteByteCode** since the compiler no longer emits them.
If this change for some reason should prove infeasible, we
can always put the bytecodes back into **Tcl\_ExecuteByteCode**,
but the authors of this TIP would prefer to avoid the code bloat.

# Reference Implementation

A reference implementation is committed on the 'tcl-numerics-branch'
at SourceForge and may be retrieved with

	 cvs -d:ext:[email protected]:/cvsroot/tcl checkout -rTIP232 tcl_numerics

# Copyright

Copyright \(c\) 2005 by Kevin B. Kenny and Adriaan Markus.  All rights reserved.

This document may be distributed subject to the terms and conditions
set forth in the Open Publication License, version 1.0
<http://www.opencontent.org/openpub/> .

Name change from tip/233.tip to tip/233.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

TIP:            233
Title:          Virtualization of Tcl's Sense of Time
Version:        $Revision: 1.6 $
Author:         Andreas Kupries <[email protected]>
Author:         Andreas Kupries <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        30-Nov-2004
Post-History:   
Tcl-Version:    8.5


~ Abstract

This document describes a number of changes to internal and public
APIs which allows external code to hook into the routines through
which the Tcl core computes time-dependent information, and to
override them. Through this the external code can manipulate Tcl's
sense of time.

~ Background and Motivation

The purpose of this change is to allow code embedding the Tcl core,
like simulators of all kind, to manipulate Tcl's sense of
time. Currently everything in the core dependent on time, like event
handling and all clock operations will always operate in real-time, as
the core gets the basic information directly from the operating
system. At least in simulators however it can make sense to have Tcl
run in the virtual time, and not real-time. This is currently not
possible, and this TIP proposes to change this, and how.

~ Specification

At the Tcl level nothing changes. All changes are at the C level,
extending and changing existing APIs.

Two new functions, '''Tcl_SetTimeProc''' and '''Tcl_QueryTimeProc''',
are added to the public API of the core. Their signatures are:

| void Tcl_SetTimeProc(Tcl_GetTimeProc *getProc,
|                      Tcl_ScaleTimeProc *scaleProc,
|                      ClientData clientData);
|
| void Tcl_QueryTimeProc(Tcl_GetTimeProc **getProc,
|                        Tcl_ScaleTimeProc **scaleProc,
|                        ClientData *clientData);
|
| typedef void (Tcl_GetTimeProc)   (Tcl_Time *timebuf, ClientData clientData);
| typedef void (Tcl_ScaleTimeProc) (Tcl_Time *timebuf, ClientData clientData);

The first function registers two related handler functions with the
core. The first handler function is a replacement for
'''Tcl_GetTime''', or rather the OS access made by
'''Tcl_GetTime'''. The other handler function is used by the Tcl
notifier to convert wait/block times from virtual into real time.

The second function returns the currently registered handler
functions. If no external handlers were set then this will return the
handlers accessing and processing the native time of the OS.

Any handler pair specified has to return data which is consistent
between them. In other words, setting one handler of the pair to
something assuming a 10-times slowdown, and the other handler of the
pair to something assuming a two-times slowdown is wrong and not
allowed.

The set handlers are allowed to run the delivered time backwards,
however this should be avoided. We have to allow it as the native time
can run backwards as the user can fiddle with the system time one way
or other. Note that the insertion of the hooks will not change the
behaviour of the Tcl core with regard to this situation, i.e. the
existing behaviour is retained.

The implementations of '''Tcl_GetTime''' and '''TclpGetClicks''' are
changed to check for the presence of a handler first, and will ask the
operating system for the current time if and only if no handler has
been registered. Both use the handler ''Tcl_GetTimeProc''.

The implementations of '''Tcl_Sleep''', '''Tcl_WaitForEvent''' and
'''NotifierThreadProc''' are changed to check for the presence of a
handler as well, and will invoke it with the current wait/block time
if it is present. The handler is not invoked if it is either not
present, or if no timeout was specified, or if the timeout is
zero. Both use the handler ''Tcl_ScaleTimeProc''.

~ Limitations

While the proposed changes are able to change Tcl's view of the
current time, and of time intervals, no effort was made to reduce the
execution speed of the interpreter itself, i,.e. of the bytecode
engine.

This means that from the point of view of the virtual time the
execution of bytecode has become faster. This can change the relative
timing of events. For example the window for a race condition is in
virtual time effectively reduced in size by the scaling factor between
virtual and real time, becoming less likely.

~ Reference Implementation

A reference implementation is provided at SourceForge
[http://sourceforge.net/support/tracker.php?aid=1073863].

~ Comments

[[ Add comments on the document here ]]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|







|










|




|


|
|
|
|
|
|
|
|
|
|



|
|



















|


|

|
|



|

|












|


|

|

|

|


>

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

# TIP 233: Virtualization of Tcl's Sense of Time

	Author:         Andreas Kupries <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        30-Nov-2004
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This document describes a number of changes to internal and public
APIs which allows external code to hook into the routines through
which the Tcl core computes time-dependent information, and to
override them. Through this the external code can manipulate Tcl's
sense of time.

# Background and Motivation

The purpose of this change is to allow code embedding the Tcl core,
like simulators of all kind, to manipulate Tcl's sense of
time. Currently everything in the core dependent on time, like event
handling and all clock operations will always operate in real-time, as
the core gets the basic information directly from the operating
system. At least in simulators however it can make sense to have Tcl
run in the virtual time, and not real-time. This is currently not
possible, and this TIP proposes to change this, and how.

# Specification

At the Tcl level nothing changes. All changes are at the C level,
extending and changing existing APIs.

Two new functions, **Tcl\_SetTimeProc** and **Tcl\_QueryTimeProc**,
are added to the public API of the core. Their signatures are:

	 void Tcl_SetTimeProc(Tcl_GetTimeProc *getProc,
	                      Tcl_ScaleTimeProc *scaleProc,
	                      ClientData clientData);
	
	 void Tcl_QueryTimeProc(Tcl_GetTimeProc **getProc,
	                        Tcl_ScaleTimeProc **scaleProc,
	                        ClientData *clientData);
	
	 typedef void (Tcl_GetTimeProc)   (Tcl_Time *timebuf, ClientData clientData);
	 typedef void (Tcl_ScaleTimeProc) (Tcl_Time *timebuf, ClientData clientData);

The first function registers two related handler functions with the
core. The first handler function is a replacement for
**Tcl\_GetTime**, or rather the OS access made by
**Tcl\_GetTime**. The other handler function is used by the Tcl
notifier to convert wait/block times from virtual into real time.

The second function returns the currently registered handler
functions. If no external handlers were set then this will return the
handlers accessing and processing the native time of the OS.

Any handler pair specified has to return data which is consistent
between them. In other words, setting one handler of the pair to
something assuming a 10-times slowdown, and the other handler of the
pair to something assuming a two-times slowdown is wrong and not
allowed.

The set handlers are allowed to run the delivered time backwards,
however this should be avoided. We have to allow it as the native time
can run backwards as the user can fiddle with the system time one way
or other. Note that the insertion of the hooks will not change the
behaviour of the Tcl core with regard to this situation, i.e. the
existing behaviour is retained.

The implementations of **Tcl\_GetTime** and **TclpGetClicks** are
changed to check for the presence of a handler first, and will ask the
operating system for the current time if and only if no handler has
been registered. Both use the handler _Tcl\_GetTimeProc_.

The implementations of **Tcl\_Sleep**, **Tcl\_WaitForEvent** and
**NotifierThreadProc** are changed to check for the presence of a
handler as well, and will invoke it with the current wait/block time
if it is present. The handler is not invoked if it is either not
present, or if no timeout was specified, or if the timeout is
zero. Both use the handler _Tcl\_ScaleTimeProc_.

# Limitations

While the proposed changes are able to change Tcl's view of the
current time, and of time intervals, no effort was made to reduce the
execution speed of the interpreter itself, i,.e. of the bytecode
engine.

This means that from the point of view of the virtual time the
execution of bytecode has become faster. This can change the relative
timing of events. For example the window for a race condition is in
virtual time effectively reduced in size by the scaling factor between
virtual and real time, becoming less likely.

# Reference Implementation

A reference implementation is provided at SourceForge
<http://sourceforge.net/support/tracker.php?aid=1073863> .

# Comments

[ Add comments on the document here ]

# Copyright

This document has been placed in the public domain.

Name change from tip/234.tip to tip/234.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490

TIP:            234
Title:          Add Support For Zlib Compression
Version:        $Revision: 1.21 $
Author:         Pascal Scheffers <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        08-Dec-2004
Post-History:   
Keywords:       Tcl,zip,gzip,deflate
Tcl-Version:    8.6


~ Abstract

This TIP proposes a new core package with commands to handle compression and
decompression using the Zlib compression library.

~ Rationale

The Zlib compression algorithm is a widely used method for compression of
files and streams. It is the algorithm used for .gz and (most) .zip files, as
well as one of the standard compression algorithms in the HTTP protocol
specifications.

Including support for Zlib compression in the core would enable the use of
compressed VFS files, fast pure Tcl implementations of gzip and zip utilities
and the use of compression in various network protocols.

A compressed VFS would be of great benefit to the new '''clock'''
implementation [173], which brings a long a large number of small files which
contain the timezone data. Although this would also require support for a VFS
file format in the core. One possible candidate would be the Tcl Read Only fs
(trofs), or perhaps a zip file VFS (only a tclvfs zip handler exists at the
time of writing). Such a compressed VFS is outside the scope of this TIP, but
would be much easier in the future based on top of it.

~~ History and Implementation Notes

The specification and implementation for the package and command originally
came from tclkit. This was wrapped in a TEA compliant package as a stand alone
package. The reference implementation is a full rewrite, retaining the public
API of the tclkit ''zlib'' command.

The gzip support and C Language API are not part of the original ''zlib''
extension. The streaming decompression is functionaly equivalent to tclkit
'''zlib sinflate''', but uses a different command names. Streaming compression
is new.

The package version for this release is 2.0 because the private API from the
original command has been removed. Alternatively, the package version can be
1.2 indicating new features were added and no existing public APIs were
changed.

~ Dependency Issues

The package utilizes zlib/libz from the gzip project
[http://www.gzip.org/zlib/]. The license of this project/library is compatible
with the Tcl license, and it also compiles on most, if not all, platforms
where Tcl compiles.

For ease of use, the core distribution shall include a copy of libz under
''tcl/contrib''. This copy will be built and used automatically when autoconf
cannot find zlib.h during the configure stage.

~ Streaming

For large files (where large is a relative value, of course), streaming
compression and decompression is required. This is implemented by using
temporary commands, which can be fed small amounts of data, yielding small
chunks of (de)compressed data.

~ Tcl API

~~ Block Compression and Decompression

There are three compressed formats supported by this command:

 * ''compress'' - the output contains raw deflate data, with no zlib/gzip
   headers or trailers and no checksum value.

 * ''deflate'' - the output contains data in zlib format, with zlib header and
   trailer using an Adler-32 checksum

 * ''gzip'' - the output contains data in gzip format, with empty gzip
   filename, no extra data, no comment, no modification time (set to zero), no
   header crc and the operating system will be set to 255 (unknown).

Data is treated as binary, meaning that all input and output is going to be
converted and treated as byte arrays in Tcl.

 > '''zlib compress''' ''data'' ?'''-level''' ''level''?

Returns raw deflated byte-array version of binary data ''data'', at an
optional compression ''level''. The compression level must be between 0 and 9:
1 gives best speed, 9 gives best compression, 0 gives no compression at all
(the input data is simply copied a block at a time).

 > '''zlib decompress''' ''compressedData'' 

Decompresses a raw deflated byte array as obtained from '''zlib compress'''.

 > '''zlib deflate''' ''data'' ?'''-level''' ''level''?

Returns zlib-compressed version of ''data'', at an optional compression
'''level'''. The compression level must be between 0 and 9: 1 gives best
speed, 9 gives best compression, 0 gives no compression at all (the input data
is simply copied a block at a time).

 > '''zlib inflate''' ''deflatedData'' 

Decompresses the zlib-compressed data as obtained from '''zlib deflate'''.

 > '''zlib gzip''' ''data'' ?'''-level''' ''level''? ?'''-header'''
   ''gzipHeaderDict''?

Returns gzip-compressed ''data'', at an optional compression ''level''. The
compression level must be between 0 and 9: 1 gives best speed, 9 gives best
compression, 0 gives no compression at all (the input data is simply copied a
block at a time).

When header dict is not given with the '''-header''' option, the gzip header
will have no file name, no extra data, no comment, no modification time (set
to zero), no header crc, and the operating system will be set to 255
(unknown).

The header dict may contain:

 * '''crc''' -
   integer: CRC-32 of the uncompressed data.

 * '''filename''' -
   string: original file name.

 * '''os''' -
   integer: Operating system/file system used (see RFC 1952
   [http://www.ietf.org/rfc/rfc1952.txt] for list of codes).

 * '''size''' -
   integer: uncompressed size modulo 2**32.

 * '''time''' -
   integer: unix mtime in seconds since 1970-1-1, suitable for use with
   '''clock format'''.

 * '''type''' -
   flag: '''binary''' for binary data, '''text''' for "probably text".

Other fields may be added in the future.

 > '''zlib gunzip''' ''gzipData'' ?'''-headerVar''' ''headerDictVarName''?

Decompresses the gzip data as obtained from '''zlib gzip''' or any gzip file.

The command returns the uncompressed data. The optional '''-headerVar'''
variable name will be filled with the available header fields. If a field does
not exist in the gzip header, it will not be present in the dict. For example,
the original filename, comment and crc are optional header fields and will be
not set in the dict if they do not exist.

Note that '''compress'''/'''decompress''', '''deflate'''/'''inflate''' and
'''gzip'''/'''gunzip''' must be used in pairs.

~~ Streaming Compression and Decompression

Streaming is handled in one of two ways. Either by '''push'''ing a
transformation onto a channel's transformation stack, or by a worker command
which is created by calling the '''zlib''' command's '''stream''' subcommand.

~~ Channel Transformations

 > '''zlib push'''
   '''deflate'''|'''inflate'''|'''compress'''|'''decompress'''|'''gzip'''|'''gunzip'''
   ''channel''
   ?''-level level''?
   ?''-limit count''?
   ?''-header gzipHeaderDict''?
   ?''-headerVar headerDictVarName''?

Pushes the requested transformation onto the channel stack. The compression
level must be between 0 and 9: 1 gives best speed, 9 gives best compression, 0
gives no compression at all (the input data is simply copied a block at a
time). The '''-limit''' option specifies the maximum number of bytes to read
from the channel. This is mainly intended to specify how much compressed
should be read from a non-seekable channel.

The '''-header''' and '''-headerVar''' are only used for '''gzip''' and
'''gunzip''' modes respectively. See the previous section for their
definition.

Additional '''chan''' commands are enabled after pushing a zlib
transformation:

 > '''chan adler32''' ''channelId''

Returns the Adler32 checksum for the data. Continuously updated during
compression, available only at the of decompression.

 > '''chan fullflush''' ''channelId''

Performs a fullflush on the compression output.

At the end of the data during compression, simply '''chan pop''' to finalize
compression and flush any remaining compressed data.

At the end of compressed data, the channel will return EOF until the
transformation is popped from the channel. If no '''-limit''' was specified,
the current access position of the channel is undefined.

When the base channel or transform returns EOF, compression will automatically
finalize. When EOF occurs during decompression but the compressed stream is not
yet at EOF, an error will be raised. 

~~ The zlib stream command

 > '''zlib stream'''
   '''deflate'''|'''inflate'''|'''compress'''|'''decompress'''|'''gzip'''|'''gunzip'''
   ?''-level level''?
   ?''-header gzipHeaderDict''?
   ?''-headerVar headerDictVarName''?

Returns a command name which will perform the requested operation in a
streaming fashion. The compression level value, ''level'', is only used when
compressing data.

The '''-header''' and '''-headerVar''' are only used for '''gzip''' and
'''gunzip''' modes respectively. See earlier in this TIP for their definition.

~~~ Stream Worker Command

The stream worker command is used to actually compress and decompress in
smaller chunks than the input and/or output.

 > ''stream'' '''put''' ?''-flush|-fullflush|-finalize''? ''data''

Adds data to be (de)compression. The flags '''-flush''', '''-fullflush''' and
'''-finalize''' are mutually exclusive and indicate the desired flushing of
the stream. '''-finalize''' is used to indicate the last block of data while
compressing. After '''-finalize''', no more data can be added to be
compressed. For decompression, after '''-finalize''' you can still add more
data for decompression.

 > ''stream'' '''flush'''

The next invoke of the stream's '''get''' subcommand will try to get the most
data from the stream. While compressing, calling [[''stream'' '''flush''']]
often will degrade the compression ratio as it forces all remaining input to
be output immediately.

 > ''stream'' '''fullflush'''

Like the '''flush''' subcommand, the next '''get''' subcommand invoked on the
stream will try to get the most data from the stream. Additionally, the
compressor will output extra data to enable recovery from this point in the
datastream.

 > ''stream'' '''finalize'''

For compression, this signals the end of the input data; no more data can be
added to the stream after the '''finalize''' subcommand is called. For
decompression, this functions the same as the '''flush''' subcommand.

 > ''stream'' '''get''' ?'''-count''' ''count''?

Gets (de)compressed data from the stream. The optional ''count'' parameter
specifies the maximum number of bytes to read from the stream. Especially for
decompression, it is strongly recommended to specify a ''count''.

 > ''stream'' '''eof'''

Returns 0 while the end of the compressed stream has not been reached. Returns
1 when the end of compressed stream was reached or the last data has been put
to the stream and '''-finalize''' was specified, or [[''stream''
'''finalize''']] has been called while compressing data.

When [[''stream'' '''eof''']] is returning true, and [[''stream'' '''get'''
?''count''?] returns an empty string, you will have obtained all data from the
stream.

 > ''stream'' '''checksum'''

Returns the Adler-32 or CRC-32 checksum of the uncompressed data. For
compressing streams, this value is updated on each '''$stream put'''. For
decompressing streams, the value will only match the adler32 of the
decompressed string after the last [[''stream'' '''get''']] returned an empty
string. Which type of checksum is computed (Adler-32 or CRC-32) depends on the
compression format of the stream.

 > ''stream'' '''close'''

Deletes the ''stream'' worker command and all storage associated with it.
Discards any remaining input and output. After this command, the ''stream''
command cannot be used anymore.

~~ Checksums

 > '''zlib crc32''' ''data'' ?'''-startValue''' ''startValue''?

Calculates a standard ''CRC-32'' checksum, with an optional start value for
incremental calculations.

 > '''zlib adler32''' ''data'' ?'''-startValue''' ''startValue''?

Calculates a quick ''Adler-32'' checksum, with an optional start value for
incremental calculations.

~ C API

~~ Synopsys

Tcl_Obj *
'''Tcl_ZlibDeflate'''(''interp, format, data, level, dictObj'')

Tcl_Obj *
'''Tcl_ZlibInflate'''(''interp, format, data, dictObj'')

unsigned int
'''Tcl_ZlibCRC32'''(''initValue, bytes, length'')

unsigned int
'''Tcl_ZlibAdler32'''(''initValue, bytes, length'')

int
'''Tcl_ZlibStreamInit'''(''interp, mode, format, level, dictObj, zshandlePtr'')

Tcl_Obj *
'''Tcl_ZlibStreamGetCommandName'''(''zshandle'')

int
'''Tcl_ZlibStreamEof'''(''zshandle'')

int
'''Tcl_ZlibStreamClose'''(''zshandle'')

int
'''Tcl_ZlibStreamAdler32'''(''zshandle'')

int
'''Tcl_ZlibStreamPut'''(''zshandle, dataObj, flush'')

int
'''Tcl_ZlibStreamGet'''(''zshandle, dataObj, count'')

~~ Arguments

 Tcl_Interp *interp (in): Optional interpreter to use for error reporting.

 int format (in): Compressed data format. For compression and decompression
   either '''TCL_ZLIB_FORMAT_RAW''', '''TCL_ZLIB_FORMAT_ZLIB''' or
   '''TCL_ZLIB_FORMAT_GZIP'''. A fourth value, '''TCL_ZLIB_FORMAT_AUTO''' is
   available for decompression, which can be used when decompressing either
   GZIP or ZLIB formatted data. Decompression of RAW data requires specifying
   the format as RAW.

 int mode (in): Compress or decompress mode. Either '''TCL_ZLIB_INFLATE''' or
   '''TCL_ZLIB_DEFLATE'''.

 Tcl_Obj *data (in): The input data for compression or decompression. Will be
   interpreted as a bytearray object.

 int level (in): The compression level. Must either be between 0 and 9 (1
   gives best speed, 9 gives best compression, 0 gives no compression at all
   with the input data is simply copied a block at a time) or -1 to get a
   default level that balances speed and compressed size. This parameter is
   ignored by decompressing streams.

 const char *bytes (in/out): On input, an array of bytes for calculation of
   checksums or compression/decompression. On output, an array of bytes to
   copy compressed or decompressed data into.

 int length (in): number of bytes to calculate the checksum on, or the size of
   ''bytes'' buffer to read from or write to.

 unsigned int initValue (in): start value value for the crc-32 or adler-32
   calculation.

 Tcl_Obj *dictPtr (in): A reference to a dict containing any additional
   options for the stream handler. This is used to pass options such as
   '''-limit''', '''-header''', etc. See the Tcl command documentation for a
   list of options supported for a particular format and mode. If NULL, will
   be treated as if it is an empty dict.

 Tcl_ZlibStream **zshandlePtr (out): Pointer to an integer to receive the
   handle to the stream. All subsequent ''Tcl_ZlibStream*''() calls require
   this handle.

 Tcl_ZlibStream *zshandle (in): Handle for the stream.

 Tcl_Obj *dataObj (in/out): A bytearray object to read the streamed data from
   ('''Tcl_ZlibStreamPut''') or write the streamed data to
   ('''Tcl_ZlibStreamGet''').

 int flush (in): Flush parameter. '''TCL_ZLIB_NO_FLUSH''',
   '''TCL_ZLIB_FLUSH''', '''TCL_ZLIB_FULLFLUSH''' or '''TCL_ZLIB_FINALIZE'''.

 int count (in): Maximum number of bytes to be written to the ''dataObj''
   Tcl_Obj. The special flag value -1 means get all bytes.

~~ Functions

 > '''Tcl_ZlibDeflate()'''

Depending on the ''type'' flag, this function returns a ''Tcl_Obj *'' with a
zero reference count containing the compressed data in either raw deflate
format, zlib format or gzip format. If an error happens during compression,
this function will return NULL and store a message in the Tcl interpreter.

 > '''Tcl_ZlibInflate()'''

This function returns a ''Tcl_Obj *'' with a zero reference count containing
the decompressed data. The ''buffersize'' argument may be used as a hint if
the decompressed size is know before decompression. If an error happens during
decompression, this function will return NULL and store a message in the Tcl
interpreter.

 > '''Tcl_ZlibCRC32()'''

This function returns the standard CRC-32 calculation. The ''startvalue''
should contain the previously returned value for streaming calculations, or
zero for the first block.

 > '''Tcl_ZlibAdler32()'''

This function returns a quick Adler-32 calculation. The ''startvalue'' should
contain the previously returned value for streaming calculations, or zero for
the first block.

 > '''Tcl_ZlibStreamInit()'''

This function initializes the internal state for compression or decompression
and creates the Tcl worker command for use at the script level. Returns TCL_OK
when initialization was succesful.

 > '''Tcl_ZlibStreamGetCommandName()'''

This function returns a ''Tcl_Obj *'' which contains the fully qualified
stream worker command name associated with this stream.

 > '''Tcl_ZlibStreamEof()'''

This function returns 0 or 1 depending on the state of the (de)compressor. For
decompression, eof is reached when the entire compressed stream has been
decompressed. For compression, eof is reached when the stream has been flushed
with '''TCL_ZLIB_FINALIZE'''.

 > '''Tcl_ZlibStreamClose()'''

This function frees up all memory associated with this stream, deletes the Tcl
worker command and discards all remaining input and output data.

 > '''Tcl_ZlibStreamAdler32()'''

This function returns the Adler-32 checksum of the uncompressed data up to this
point. For decompressing streams, the checksum will only match the checksum of
uncompressed data when ''Tcl_ZlibStreamGet'' returns an empty string.

 > '''Tcl_ZlibStreamPut()'''

This function is used to copy data to the stream from the given buffer. For
compression, the final block of data, which may be an empty string, must be
indicated with '''TCL_ZLIB_FINALIZE''' as the flush parameter. The number of
bytes read from the supplied buffer is returned (or -1 on error).

 > '''Tcl_ZlibStreamGet()'''

This function is used to copy the data from the stream to the given buffer.
The number of bytes written to the supplied buffer is returned (or -1 on
error).

~ Usage

Zlib support is to form part of Tcl's standard API: no special measures will
be needed for Tcl code or C-implemented extensions to make use of it.

~ Safe Interpreters

These commands only work on data already available to a safe interpreter and
are therefore safe make available in the safe interpreter.

~ Reference Implementation

An old version the reference implementation is available at the subversion
repository [http://svn.scheffers.net/zlib]. Alternatively, a recent snapshot
is available [http://svn.scheffers.net/zlib.tar.gz]. This reference
implementation includes a copy of zlib-1.2.1 [http://www.gzip.org].

The reference implementation currently implements a version 1.8 of this TIP.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|


|







|
|


|
|


|




|

|

|







|


|




|


|

|


|

|

|



|


|


|
|
|




|

|
|

|

|

|

|

|
|
|
|

|

|

|
|

|

|
|

|
|
|
|



|


|


|
|
|

|
|

|

|

|
|



|

|

|





|
|

|

|

|

|

|
|
|
|
|
|
|



|
|



|
|


|


|




|



|



|






|

|
|
|
|
|


|


|
|

|




|

|
|
|
|
|


|

|
|



|

|




|


|
|

|

|

|

|



|
|

|
|


|


|

|
|


|

|
|


|

|

|


|

|


|

|

|
|

|
|


|


|


|

|
|


|


|


|


|


|

|

|

|
|
|




|
|

|


|

|



|



|
|

|


|

|



|
|


|

|
|
|

|
|

|
|

|

|

|




|

|
|




|

|



|

|



|


|


|

|


|

|


|

|




|



|

|



|
|

|


|
|

|




|




|


|
|
|



|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490

# TIP 234: Add Support For Zlib Compression

	Author:         Pascal Scheffers <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        08-Dec-2004
	Post-History:   
	Keywords:       Tcl,zip,gzip,deflate
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes a new core package with commands to handle compression and
decompression using the Zlib compression library.

# Rationale

The Zlib compression algorithm is a widely used method for compression of
files and streams. It is the algorithm used for .gz and \(most\) .zip files, as
well as one of the standard compression algorithms in the HTTP protocol
specifications.

Including support for Zlib compression in the core would enable the use of
compressed VFS files, fast pure Tcl implementations of gzip and zip utilities
and the use of compression in various network protocols.

A compressed VFS would be of great benefit to the new **clock**
implementation [[173]](173.md), which brings a long a large number of small files which
contain the timezone data. Although this would also require support for a VFS
file format in the core. One possible candidate would be the Tcl Read Only fs
\(trofs\), or perhaps a zip file VFS \(only a tclvfs zip handler exists at the
time of writing\). Such a compressed VFS is outside the scope of this TIP, but
would be much easier in the future based on top of it.

## History and Implementation Notes

The specification and implementation for the package and command originally
came from tclkit. This was wrapped in a TEA compliant package as a stand alone
package. The reference implementation is a full rewrite, retaining the public
API of the tclkit _zlib_ command.

The gzip support and C Language API are not part of the original _zlib_
extension. The streaming decompression is functionaly equivalent to tclkit
**zlib sinflate**, but uses a different command names. Streaming compression
is new.

The package version for this release is 2.0 because the private API from the
original command has been removed. Alternatively, the package version can be
1.2 indicating new features were added and no existing public APIs were
changed.

# Dependency Issues

The package utilizes zlib/libz from the gzip project
<http://www.gzip.org/zlib/> . The license of this project/library is compatible
with the Tcl license, and it also compiles on most, if not all, platforms
where Tcl compiles.

For ease of use, the core distribution shall include a copy of libz under
_tcl/contrib_. This copy will be built and used automatically when autoconf
cannot find zlib.h during the configure stage.

# Streaming

For large files \(where large is a relative value, of course\), streaming
compression and decompression is required. This is implemented by using
temporary commands, which can be fed small amounts of data, yielding small
chunks of \(de\)compressed data.

# Tcl API

## Block Compression and Decompression

There are three compressed formats supported by this command:

 * _compress_ - the output contains raw deflate data, with no zlib/gzip
   headers or trailers and no checksum value.

 * _deflate_ - the output contains data in zlib format, with zlib header and
   trailer using an Adler-32 checksum

 * _gzip_ - the output contains data in gzip format, with empty gzip
   filename, no extra data, no comment, no modification time \(set to zero\), no
   header crc and the operating system will be set to 255 \(unknown\).

Data is treated as binary, meaning that all input and output is going to be
converted and treated as byte arrays in Tcl.

 > **zlib compress** _data_ ?**-level** _level_?

Returns raw deflated byte-array version of binary data _data_, at an
optional compression _level_. The compression level must be between 0 and 9:
1 gives best speed, 9 gives best compression, 0 gives no compression at all
\(the input data is simply copied a block at a time\).

 > **zlib decompress** _compressedData_ 

Decompresses a raw deflated byte array as obtained from **zlib compress**.

 > **zlib deflate** _data_ ?**-level** _level_?

Returns zlib-compressed version of _data_, at an optional compression
**level**. The compression level must be between 0 and 9: 1 gives best
speed, 9 gives best compression, 0 gives no compression at all \(the input data
is simply copied a block at a time\).

 > **zlib inflate** _deflatedData_ 

Decompresses the zlib-compressed data as obtained from **zlib deflate**.

 > **zlib gzip** _data_ ?**-level** _level_? ?**-header**
   _gzipHeaderDict_?

Returns gzip-compressed _data_, at an optional compression _level_. The
compression level must be between 0 and 9: 1 gives best speed, 9 gives best
compression, 0 gives no compression at all \(the input data is simply copied a
block at a time\).

When header dict is not given with the **-header** option, the gzip header
will have no file name, no extra data, no comment, no modification time \(set
to zero\), no header crc, and the operating system will be set to 255
\(unknown\).

The header dict may contain:

 * **crc** -
   integer: CRC-32 of the uncompressed data.

 * **filename** -
   string: original file name.

 * **os** -
   integer: Operating system/file system used \(see RFC 1952
   <http://www.ietf.org/rfc/rfc1952.txt>  for list of codes\).

 * **size** -
   integer: uncompressed size modulo 2\*\*32.

 * **time** -
   integer: unix mtime in seconds since 1970-1-1, suitable for use with
   **clock format**.

 * **type** -
   flag: **binary** for binary data, **text** for "probably text".

Other fields may be added in the future.

 > **zlib gunzip** _gzipData_ ?**-headerVar** _headerDictVarName_?

Decompresses the gzip data as obtained from **zlib gzip** or any gzip file.

The command returns the uncompressed data. The optional **-headerVar**
variable name will be filled with the available header fields. If a field does
not exist in the gzip header, it will not be present in the dict. For example,
the original filename, comment and crc are optional header fields and will be
not set in the dict if they do not exist.

Note that **compress**/**decompress**, **deflate**/**inflate** and
**gzip**/**gunzip** must be used in pairs.

## Streaming Compression and Decompression

Streaming is handled in one of two ways. Either by **push**ing a
transformation onto a channel's transformation stack, or by a worker command
which is created by calling the **zlib** command's **stream** subcommand.

## Channel Transformations

 > **zlib push**
   **deflate**\|**inflate**\|**compress**\|**decompress**\|**gzip**\|**gunzip**
   _channel_
   ?_-level level_?
   ?_-limit count_?
   ?_-header gzipHeaderDict_?
   ?_-headerVar headerDictVarName_?

Pushes the requested transformation onto the channel stack. The compression
level must be between 0 and 9: 1 gives best speed, 9 gives best compression, 0
gives no compression at all \(the input data is simply copied a block at a
time\). The **-limit** option specifies the maximum number of bytes to read
from the channel. This is mainly intended to specify how much compressed
should be read from a non-seekable channel.

The **-header** and **-headerVar** are only used for **gzip** and
**gunzip** modes respectively. See the previous section for their
definition.

Additional **chan** commands are enabled after pushing a zlib
transformation:

 > **chan adler32** _channelId_

Returns the Adler32 checksum for the data. Continuously updated during
compression, available only at the of decompression.

 > **chan fullflush** _channelId_

Performs a fullflush on the compression output.

At the end of the data during compression, simply **chan pop** to finalize
compression and flush any remaining compressed data.

At the end of compressed data, the channel will return EOF until the
transformation is popped from the channel. If no **-limit** was specified,
the current access position of the channel is undefined.

When the base channel or transform returns EOF, compression will automatically
finalize. When EOF occurs during decompression but the compressed stream is not
yet at EOF, an error will be raised. 

## The zlib stream command

 > **zlib stream**
   **deflate**\|**inflate**\|**compress**\|**decompress**\|**gzip**\|**gunzip**
   ?_-level level_?
   ?_-header gzipHeaderDict_?
   ?_-headerVar headerDictVarName_?

Returns a command name which will perform the requested operation in a
streaming fashion. The compression level value, _level_, is only used when
compressing data.

The **-header** and **-headerVar** are only used for **gzip** and
**gunzip** modes respectively. See earlier in this TIP for their definition.

### Stream Worker Command

The stream worker command is used to actually compress and decompress in
smaller chunks than the input and/or output.

 > _stream_ **put** ?_-flush\|-fullflush\|-finalize_? _data_

Adds data to be \(de\)compression. The flags **-flush**, **-fullflush** and
**-finalize** are mutually exclusive and indicate the desired flushing of
the stream. **-finalize** is used to indicate the last block of data while
compressing. After **-finalize**, no more data can be added to be
compressed. For decompression, after **-finalize** you can still add more
data for decompression.

 > _stream_ **flush**

The next invoke of the stream's **get** subcommand will try to get the most
data from the stream. While compressing, calling [_stream_ **flush**]
often will degrade the compression ratio as it forces all remaining input to
be output immediately.

 > _stream_ **fullflush**

Like the **flush** subcommand, the next **get** subcommand invoked on the
stream will try to get the most data from the stream. Additionally, the
compressor will output extra data to enable recovery from this point in the
datastream.

 > _stream_ **finalize**

For compression, this signals the end of the input data; no more data can be
added to the stream after the **finalize** subcommand is called. For
decompression, this functions the same as the **flush** subcommand.

 > _stream_ **get** ?**-count** _count_?

Gets \(de\)compressed data from the stream. The optional _count_ parameter
specifies the maximum number of bytes to read from the stream. Especially for
decompression, it is strongly recommended to specify a _count_.

 > _stream_ **eof**

Returns 0 while the end of the compressed stream has not been reached. Returns
1 when the end of compressed stream was reached or the last data has been put
to the stream and **-finalize** was specified, or [_stream_
**finalize**] has been called while compressing data.

When [_stream_ **eof**] is returning true, and [_stream_ **get**
?_count_?] returns an empty string, you will have obtained all data from the
stream.

 > _stream_ **checksum**

Returns the Adler-32 or CRC-32 checksum of the uncompressed data. For
compressing streams, this value is updated on each **$stream put**. For
decompressing streams, the value will only match the adler32 of the
decompressed string after the last [_stream_ **get**] returned an empty
string. Which type of checksum is computed \(Adler-32 or CRC-32\) depends on the
compression format of the stream.

 > _stream_ **close**

Deletes the _stream_ worker command and all storage associated with it.
Discards any remaining input and output. After this command, the _stream_
command cannot be used anymore.

## Checksums

 > **zlib crc32** _data_ ?**-startValue** _startValue_?

Calculates a standard _CRC-32_ checksum, with an optional start value for
incremental calculations.

 > **zlib adler32** _data_ ?**-startValue** _startValue_?

Calculates a quick _Adler-32_ checksum, with an optional start value for
incremental calculations.

# C API

## Synopsys

Tcl\_Obj \*
**Tcl\_ZlibDeflate**\(_interp, format, data, level, dictObj_\)

Tcl\_Obj \*
**Tcl\_ZlibInflate**\(_interp, format, data, dictObj_\)

unsigned int
**Tcl\_ZlibCRC32**\(_initValue, bytes, length_\)

unsigned int
**Tcl\_ZlibAdler32**\(_initValue, bytes, length_\)

int
**Tcl\_ZlibStreamInit**\(_interp, mode, format, level, dictObj, zshandlePtr_\)

Tcl\_Obj \*
**Tcl\_ZlibStreamGetCommandName**\(_zshandle_\)

int
**Tcl\_ZlibStreamEof**\(_zshandle_\)

int
**Tcl\_ZlibStreamClose**\(_zshandle_\)

int
**Tcl\_ZlibStreamAdler32**\(_zshandle_\)

int
**Tcl\_ZlibStreamPut**\(_zshandle, dataObj, flush_\)

int
**Tcl\_ZlibStreamGet**\(_zshandle, dataObj, count_\)

## Arguments

 Tcl\_Interp \*interp \(in\): Optional interpreter to use for error reporting.

 int format \(in\): Compressed data format. For compression and decompression
   either **TCL\_ZLIB\_FORMAT\_RAW**, **TCL\_ZLIB\_FORMAT\_ZLIB** or
   **TCL\_ZLIB\_FORMAT\_GZIP**. A fourth value, **TCL\_ZLIB\_FORMAT\_AUTO** is
   available for decompression, which can be used when decompressing either
   GZIP or ZLIB formatted data. Decompression of RAW data requires specifying
   the format as RAW.

 int mode \(in\): Compress or decompress mode. Either **TCL\_ZLIB\_INFLATE** or
   **TCL\_ZLIB\_DEFLATE**.

 Tcl\_Obj \*data \(in\): The input data for compression or decompression. Will be
   interpreted as a bytearray object.

 int level \(in\): The compression level. Must either be between 0 and 9 \(1
   gives best speed, 9 gives best compression, 0 gives no compression at all
   with the input data is simply copied a block at a time\) or -1 to get a
   default level that balances speed and compressed size. This parameter is
   ignored by decompressing streams.

 const char \*bytes \(in/out\): On input, an array of bytes for calculation of
   checksums or compression/decompression. On output, an array of bytes to
   copy compressed or decompressed data into.

 int length \(in\): number of bytes to calculate the checksum on, or the size of
   _bytes_ buffer to read from or write to.

 unsigned int initValue \(in\): start value value for the crc-32 or adler-32
   calculation.

 Tcl\_Obj \*dictPtr \(in\): A reference to a dict containing any additional
   options for the stream handler. This is used to pass options such as
   **-limit**, **-header**, etc. See the Tcl command documentation for a
   list of options supported for a particular format and mode. If NULL, will
   be treated as if it is an empty dict.

 Tcl\_ZlibStream \*\*zshandlePtr \(out\): Pointer to an integer to receive the
   handle to the stream. All subsequent _Tcl\_ZlibStream\*_\(\) calls require
   this handle.

 Tcl\_ZlibStream \*zshandle \(in\): Handle for the stream.

 Tcl\_Obj \*dataObj \(in/out\): A bytearray object to read the streamed data from
   \(**Tcl\_ZlibStreamPut**\) or write the streamed data to
   \(**Tcl\_ZlibStreamGet**\).

 int flush \(in\): Flush parameter. **TCL\_ZLIB\_NO\_FLUSH**,
   **TCL\_ZLIB\_FLUSH**, **TCL\_ZLIB\_FULLFLUSH** or **TCL\_ZLIB\_FINALIZE**.

 int count \(in\): Maximum number of bytes to be written to the _dataObj_
   Tcl\_Obj. The special flag value -1 means get all bytes.

## Functions

 > **Tcl\_ZlibDeflate\(\)**

Depending on the _type_ flag, this function returns a _Tcl\_Obj \*_ with a
zero reference count containing the compressed data in either raw deflate
format, zlib format or gzip format. If an error happens during compression,
this function will return NULL and store a message in the Tcl interpreter.

 > **Tcl\_ZlibInflate\(\)**

This function returns a _Tcl\_Obj \*_ with a zero reference count containing
the decompressed data. The _buffersize_ argument may be used as a hint if
the decompressed size is know before decompression. If an error happens during
decompression, this function will return NULL and store a message in the Tcl
interpreter.

 > **Tcl\_ZlibCRC32\(\)**

This function returns the standard CRC-32 calculation. The _startvalue_
should contain the previously returned value for streaming calculations, or
zero for the first block.

 > **Tcl\_ZlibAdler32\(\)**

This function returns a quick Adler-32 calculation. The _startvalue_ should
contain the previously returned value for streaming calculations, or zero for
the first block.

 > **Tcl\_ZlibStreamInit\(\)**

This function initializes the internal state for compression or decompression
and creates the Tcl worker command for use at the script level. Returns TCL\_OK
when initialization was succesful.

 > **Tcl\_ZlibStreamGetCommandName\(\)**

This function returns a _Tcl\_Obj \*_ which contains the fully qualified
stream worker command name associated with this stream.

 > **Tcl\_ZlibStreamEof\(\)**

This function returns 0 or 1 depending on the state of the \(de\)compressor. For
decompression, eof is reached when the entire compressed stream has been
decompressed. For compression, eof is reached when the stream has been flushed
with **TCL\_ZLIB\_FINALIZE**.

 > **Tcl\_ZlibStreamClose\(\)**

This function frees up all memory associated with this stream, deletes the Tcl
worker command and discards all remaining input and output data.

 > **Tcl\_ZlibStreamAdler32\(\)**

This function returns the Adler-32 checksum of the uncompressed data up to this
point. For decompressing streams, the checksum will only match the checksum of
uncompressed data when _Tcl\_ZlibStreamGet_ returns an empty string.

 > **Tcl\_ZlibStreamPut\(\)**

This function is used to copy data to the stream from the given buffer. For
compression, the final block of data, which may be an empty string, must be
indicated with **TCL\_ZLIB\_FINALIZE** as the flush parameter. The number of
bytes read from the supplied buffer is returned \(or -1 on error\).

 > **Tcl\_ZlibStreamGet\(\)**

This function is used to copy the data from the stream to the given buffer.
The number of bytes written to the supplied buffer is returned \(or -1 on
error\).

# Usage

Zlib support is to form part of Tcl's standard API: no special measures will
be needed for Tcl code or C-implemented extensions to make use of it.

# Safe Interpreters

These commands only work on data already available to a safe interpreter and
are therefore safe make available in the safe interpreter.

# Reference Implementation

An old version the reference implementation is available at the subversion
repository <http://svn.scheffers.net/zlib> . Alternatively, a recent snapshot
is available <http://svn.scheffers.net/zlib.tar.gz> . This reference
implementation includes a copy of zlib-1.2.1 <http://www.gzip.org> .

The reference implementation currently implements a version 1.8 of this TIP.

# Copyright

This document has been placed in the public domain.

Name change from tip/235.tip to tip/235.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

TIP:            235
Title:          Exposing a C API for Ensembles
Version:        $Revision: 1.9 $
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        10-Dec-2004
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP exposes a C API for the ensembles of [112].

~ Rationale

As the Tcl core moves to make more use of ensembles, it becomes more
necessary for there to be an API available to allow control over those
ensembles from the C level so that it is not necessary for such
manipulation to be done through the evaluation of Tcl scripts
(e.g. because this interferes with the interpreter's command count and
that may be limited in that particular interpreter). Given such an
API, it should be exposed to code outside the Tcl core if at all
possible.

~ Proposed Change

This TIP proposes exposing the following functions:

 Tcl_CreateEnsemble: Create an ensemble linked to a particular
   namespace and return the command token for the namespace command.
   The ''flags'' argument specifies the initial version of the set of
   flags controllable through Tcl_SetEnsembleFlags (see below).

 > > Tcl_Command '''Tcl_CreateEnsemble'''(Tcl_Interp *''interp'', const char *''name'', Tcl_Namespace *''namespacePtr'', int ''flags'')

 Tcl_FindEnsemble: Return a command token for an ensemble, or NULL if
   the name does not refer to an ensemble. The ''flags'' argument
   controls whether failure to find an ensemble is an error and should
   be either 0 or TCL_LEAVE_ERR_MSG.

 > > Tcl_Command '''Tcl_FindEnsemble'''(Tcl_Interp *''interp'', Tcl_Obj *''cmdNameObj'', int ''flags'')

 Tcl_IsEnsemble: Test whether a command token refers to an ensemble.

 > > int '''Tcl_IsEnsemble'''(Tcl_Command ''command'')

 Tcl_GetEnsembleSubcommandList, Tcl_SetEnsembleSubcommandList: Read
   and write the (fixed) list of subcommands of the ensemble.
   Equivalent to manipulating the '''-subcommands''' option.

 > > int '''Tcl_GetEnsembleSubcommandList'''(Tcl_Interp *''interp'', Tcl_Command ''command'', Tcl_Obj **''subcmdListObjPtr'')

 > > int '''Tcl_SetEnsembleSubcommandList'''(Tcl_Interp *''interp'', Tcl_Command ''command'', Tcl_Obj *''subcmdListObj'')

 Tcl_GetEnsembleMappingDict, Tcl_SetEnsembleMappingDict: Read and
   write the dictionary that maps subcommands to prefixes of
   implementation commands. Equivalent to manipulating the '''-map'''
   option.

 > > int '''Tcl_GetEnsembleMappingDict'''(Tcl_Interp *''interp'', Tcl_Command ''command'', Tcl_Obj **''mapDictObjPtr'')

 > > int '''Tcl_SetEnsembleMappingDict'''(Tcl_Interp *''interp'', Tcl_Command ''command'', Tcl_Obj *''mapDictObj'')

 Tcl_GetEnsembleUnknownHandler, Tcl_SetEnsembleUnknownHandler: Read
   and write the command prefix list that is used to implement the
   unknown-subcommand handler. Equivalent to manipulating the
   '''-unknown''' option.

 > > int '''Tcl_GetEnsembleUnknownHandler'''(Tcl_Interp *''interp'', Tcl_Command ''command'', Tcl_Obj **''handlerListObjPtr'')

 > > int '''Tcl_SetEnsembleUnknownHandler'''(Tcl_Interp *''interp'', Tcl_Command ''command'', Tcl_Obj *''handlerListObj'')

 Tcl_GetEnsembleFlags, Tcl_SetEnsembleFlags: Read and write the flags
   for the ensemble. Currently there is only one settable flag bit,
   TCL_ENSEMBLE_PREFIX, which is present exactly when '''-prefix'''
   option is true.

 > > int '''Tcl_GetEnsembleFlags'''(Tcl_Interp *''interp'', Tcl_Command ''command'', int *''flagsPtr'')

 > > int '''Tcl_SetEnsembleFlags'''(Tcl_Interp *''interp'', Tcl_Command ''command'', int ''flags'')

 Tcl_GetEnsembleNamespace: Reads the namespace associated with the
   ensemble; this value may not be altered.

 > > int '''Tcl_GetEnsembleNamespace'''(Tcl_Interp *''interp'', Tcl_Command ''command'', Tcl_Namespace **''namespacePtrPtr'')

~~ Notes

The handle for an ensemble is a normal Tcl_Command handle, and any
operation valid on such a command (e.g. deleting it or finding its name) 
is valid. Ensembles are just a special subclass of commands. This allows
the ensemble API to be considerably sparser than it would otherwise have
to be.

~ Reference Implementation

The API is already in the core, but with internal naming and not
exposed to anyone. Exposure is just renaming a few functions and
putting them in the stubs table. No new types are exposed. All this
means that a reference implementation is truly trivial.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|

|





|
|



|



|

|
|

|

|
|

|

|

|

|

|
|
|

|

|

|

|


|

|

|


|

|

|

|

|


|

|

|


|

|

|
|




|






|


>

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

# TIP 235: Exposing a C API for Ensembles

	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        10-Dec-2004
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP exposes a C API for the ensembles of [[112]](112.md).

# Rationale

As the Tcl core moves to make more use of ensembles, it becomes more
necessary for there to be an API available to allow control over those
ensembles from the C level so that it is not necessary for such
manipulation to be done through the evaluation of Tcl scripts
\(e.g. because this interferes with the interpreter's command count and
that may be limited in that particular interpreter\). Given such an
API, it should be exposed to code outside the Tcl core if at all
possible.

# Proposed Change

This TIP proposes exposing the following functions:

 Tcl\_CreateEnsemble: Create an ensemble linked to a particular
   namespace and return the command token for the namespace command.
   The _flags_ argument specifies the initial version of the set of
   flags controllable through Tcl\_SetEnsembleFlags \(see below\).

 > > Tcl\_Command **Tcl\_CreateEnsemble**\(Tcl\_Interp \*_interp_, const char \*_name_, Tcl\_Namespace \*_namespacePtr_, int _flags_\)

 Tcl\_FindEnsemble: Return a command token for an ensemble, or NULL if
   the name does not refer to an ensemble. The _flags_ argument
   controls whether failure to find an ensemble is an error and should
   be either 0 or TCL\_LEAVE\_ERR\_MSG.

 > > Tcl\_Command **Tcl\_FindEnsemble**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_cmdNameObj_, int _flags_\)

 Tcl\_IsEnsemble: Test whether a command token refers to an ensemble.

 > > int **Tcl\_IsEnsemble**\(Tcl\_Command _command_\)

 Tcl\_GetEnsembleSubcommandList, Tcl\_SetEnsembleSubcommandList: Read
   and write the \(fixed\) list of subcommands of the ensemble.
   Equivalent to manipulating the **-subcommands** option.

 > > int **Tcl\_GetEnsembleSubcommandList**\(Tcl\_Interp \*_interp_, Tcl\_Command _command_, Tcl\_Obj \*\*_subcmdListObjPtr_\)

 > > int **Tcl\_SetEnsembleSubcommandList**\(Tcl\_Interp \*_interp_, Tcl\_Command _command_, Tcl\_Obj \*_subcmdListObj_\)

 Tcl\_GetEnsembleMappingDict, Tcl\_SetEnsembleMappingDict: Read and
   write the dictionary that maps subcommands to prefixes of
   implementation commands. Equivalent to manipulating the **-map**
   option.

 > > int **Tcl\_GetEnsembleMappingDict**\(Tcl\_Interp \*_interp_, Tcl\_Command _command_, Tcl\_Obj \*\*_mapDictObjPtr_\)

 > > int **Tcl\_SetEnsembleMappingDict**\(Tcl\_Interp \*_interp_, Tcl\_Command _command_, Tcl\_Obj \*_mapDictObj_\)

 Tcl\_GetEnsembleUnknownHandler, Tcl\_SetEnsembleUnknownHandler: Read
   and write the command prefix list that is used to implement the
   unknown-subcommand handler. Equivalent to manipulating the
   **-unknown** option.

 > > int **Tcl\_GetEnsembleUnknownHandler**\(Tcl\_Interp \*_interp_, Tcl\_Command _command_, Tcl\_Obj \*\*_handlerListObjPtr_\)

 > > int **Tcl\_SetEnsembleUnknownHandler**\(Tcl\_Interp \*_interp_, Tcl\_Command _command_, Tcl\_Obj \*_handlerListObj_\)

 Tcl\_GetEnsembleFlags, Tcl\_SetEnsembleFlags: Read and write the flags
   for the ensemble. Currently there is only one settable flag bit,
   TCL\_ENSEMBLE\_PREFIX, which is present exactly when **-prefix**
   option is true.

 > > int **Tcl\_GetEnsembleFlags**\(Tcl\_Interp \*_interp_, Tcl\_Command _command_, int \*_flagsPtr_\)

 > > int **Tcl\_SetEnsembleFlags**\(Tcl\_Interp \*_interp_, Tcl\_Command _command_, int _flags_\)

 Tcl\_GetEnsembleNamespace: Reads the namespace associated with the
   ensemble; this value may not be altered.

 > > int **Tcl\_GetEnsembleNamespace**\(Tcl\_Interp \*_interp_, Tcl\_Command _command_, Tcl\_Namespace \*\*_namespacePtrPtr_\)

## Notes

The handle for an ensemble is a normal Tcl\_Command handle, and any
operation valid on such a command \(e.g. deleting it or finding its name\) 
is valid. Ensembles are just a special subclass of commands. This allows
the ensemble API to be considerably sparser than it would otherwise have
to be.

# Reference Implementation

The API is already in the core, but with internal naming and not
exposed to anyone. Exposure is just renaming a few functions and
putting them in the stubs table. No new types are exposed. All this
means that a reference implementation is truly trivial.

# Copyright

This document has been placed in the public domain.

Name change from tip/236.tip to tip/236.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

TIP:            236
Title:          Absolute Positioning of Canvas Items
Version:        $Revision: 1.10 $
Author:         Neil McKay <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        25-Dec-2004
Post-History:   
Keywords:       Tk,anchor,place
Tcl-Version:    8.6


~ Abstract

This TIP proposes adding a canvas widget command to set the absolute position
of canvas items.

~Rationale

There are many situations where it is desirable to move a group of canvas
items to a given position. Currently, this is done by getting the items' first
coordinate, calculating the offset required to move the items to the desired
position, and using the canvas '''move''' command to translate the items to
where we want them. This is tedious and inefficient.

~The 'moveto' Canvas Command

This TIP proposes adding a subcommand called '''moveto''' to the canvas widget
command. It is analogous to the canvas '''move''' command, except that it
accepts an absolute position instead of a relative displacement. For instance,
the command

|	.c moveto stuff 100 200

will displace all items tagged with ''stuff'' so that the first coordinate of
the first (bottom-most) tagged item lies at the point (100,200).

The result of the command will be the empty string.

~~Formal Syntax

 > ''canvas'' '''moveto''' ''tagOrId'' ''x'' ''y''

Argument description:

 canvas: The canvas instance's command.

 tagOrId: A specifier that selects one or more items. If no items are
 selected, the command does nothing.

 x, y: The absolute coordinates of the target location. If either coordinate
 is given as an empty string, then that coordinate will remain unchanged.

~Patches

A patch (against tcl8.5a3) that implements the '''moveto''' canvas subcommand
is available [http://www.eecs.umich.edu/~mckay/canvmoveto.patch.gz].

~Copyright

This document is in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|




|


|

|
|



|

|
|



|

|











|

|
|

|


>

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

# TIP 236: Absolute Positioning of Canvas Items

	Author:         Neil McKay <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        25-Dec-2004
	Post-History:   
	Keywords:       Tk,anchor,place
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes adding a canvas widget command to set the absolute position
of canvas items.

# Rationale

There are many situations where it is desirable to move a group of canvas
items to a given position. Currently, this is done by getting the items' first
coordinate, calculating the offset required to move the items to the desired
position, and using the canvas **move** command to translate the items to
where we want them. This is tedious and inefficient.

# The 'moveto' Canvas Command

This TIP proposes adding a subcommand called **moveto** to the canvas widget
command. It is analogous to the canvas **move** command, except that it
accepts an absolute position instead of a relative displacement. For instance,
the command

		.c moveto stuff 100 200

will displace all items tagged with _stuff_ so that the first coordinate of
the first \(bottom-most\) tagged item lies at the point \(100,200\).

The result of the command will be the empty string.

## Formal Syntax

 > _canvas_ **moveto** _tagOrId_ _x_ _y_

Argument description:

 canvas: The canvas instance's command.

 tagOrId: A specifier that selects one or more items. If no items are
 selected, the command does nothing.

 x, y: The absolute coordinates of the target location. If either coordinate
 is given as an empty string, then that coordinate will remain unchanged.

# Patches

A patch \(against tcl8.5a3\) that implements the **moveto** canvas subcommand
is available <http://www.eecs.umich.edu/~mckay/canvmoveto.patch.gz> .

# Copyright

This document is in the public domain.

Name change from tip/237.tip to tip/237.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498

TIP:            237
Title:          Arbitrary-Precision Integers for Tcl
Version:        $Revision: 1.19 $
Author:         Kevin B. Kenny <[email protected]>
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        14-Jan-2005
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP adds the capability to perform computations on integer values
of arbitrary precision.

~ Rationale

There have been a number of issues in Tcl 8.4 dealing with the limited
range of native integers and wide values. The original ideas of [72],
while they have given at least the basics of 64-bit integer support,
have also introduced some subtle violations of the doctrine that
"everything is a string." Some of these have been insidious bugs -
[http://sf.net/tracker/?func=detail&aid=868489&group_id=10894&atid=110894]
and
[http://sf.net/tracker/?func=detail&aid=1006626&group_id=10894&atid=110894]
are illustrative - while others are perhaps not "bugs" in the
strictest sense, but are still surprising behaviour.

For instance, it is possible for a script to tell integers from wide
integers even when their string representations are equal, by
performing any arithmetic operation that overflows:

|    % set x 2147483647    % set x [expr { wide(2146483647) }]
|    2147483647            2147483647
|    % incr x              % incr x
|    -2147483648           2147483648

With things as they stand,
[http://sf.net/tracker/?func=detail&aid=1006626&group_id=10894&atid=110894]
is nearly unfixable. It causes misconversion of large floating point
numbers that look like integers:

|    % set x -9223372036854775809
|    -9223372036854775809
|    % expr {double($x)}
|    9.22337203685e+018
|    % scan $x %g
|    -9.22337203685e+018

The reason here is that the string of digits is first converted to a
64-bit unsigned integer ('''Tcl_WideUInt'''). The '-' sign causes the
unsigned integer to be interpreted as a signed integer, and the sign
reversed. Since interpreting the unsigned integer as signed yields an
overflow, the result is positive rather than negative and gives the
odd behaviour shown above.

Of course, even if the implementation of 64-bit arithmetic were bug
free, there would be uses for arithmetic of higher precision. One
example is that several Tcl users have attempted pure-Tcl
implementations of RSA and Diffie-Hellman cryptographic algorithms.
These algorithms depend on arithmetic of high precision; implementing
them efficiently in today's Tcl requires a C extension because the
high-precision algorithms implemented in Tcl are simply too slow to be
acceptable.

Finally, studying the references for accurate conversion of floating
point numbers [132] reveals that input and output conversions both
require arbitrary-precision arithmetic in their implementation. The
reference implementation supplied with that TIP, alas, is code that is
poorly commented and difficult to integrate into Tcl's build system.
Reimplementing it according to Tcl's engineering practices means
implementing a large part of an arbitrary-precision arithmetic
library.

~ Proposal

This TIP proposes augmenting Tcl with code for processing integers of
arbitrary precision. Specifically:

 1. The ''libtommath'' library [http://math.libtomcrypt.com/] shall be
    added in a subdirectory of the Tcl source tree, parallel to
    ''generic/'', ''compat/'', etc. This library implements arithmetic
    on integers of arbitrary precision. For the rationale behind this
    library, and some of the precise integration details, see "Choice
    of Libary" below.

 2. New functions, ''Tcl_NewBignumObj'', ''Tcl_SetBignumObj'',
    ''Tcl_GetBignumFromObj'' and ''Tcl_GetBignumAndClearObj'' shall be
    added to the Tcl library. They shall be specified as follows:

 > Tcl_NewBignumObj: Creates an object containing an integer of
      arbitrary precision. The ''value'' argument gives the integer in
      the format native to ''libtommath''. ''Upon return, the value
      argument is cleared, because its digit array has had its
      ownership transferred to the Tcl library.''

 > > Tcl_Obj *'''Tcl_NewBignumObj'''(mp_int *''value'')

 > Tcl_SetBignumObj: Changes the value of an object to an integer of
      arbitrary precision. The ''value'' argument gives the integer in
      the format native to ''libtommath''. As with other
      '''Tcl_SetFooObj''' routines, the '''Tcl_Obj''' having its value
      set must be unshared (copy on write). As with
      '''Tcl_NewBignumObj''', the ''value'' argument is cleared on
      return and the digit list is owned by Tcl thereafter.

 > > void '''Tcl_SetBignumObj'''(Tcl_Obj *''objPtr'', mp_int *''value'')

 > Tcl_GetBignumFromObj: Interprets an object as a large integer, and
    constructs a copy of that large integer in the ''value'' argument.
    Returns ''TCL_OK'' if successful. On failure, stores an error
    message in the result of ''interp'' and returns ''TCL_ERROR''.

 > > int '''Tcl_GetBignumFromObj'''(Tcl_Interp *''interp'', Tcl_Obj*''objPtr'', mp_int *''value'')

 > Tcl_GetBignumAndClearObj: Interprets an object as a large integer,
      and stores the large integer in the ''value'' argument. Returns
      ''TCL_OK'' if successful. On failure, stores an error message in
      the result of ''interp'' and returns ''TCL_ERROR''. Calls
      '''Tcl_Panic''' if the object is shared. The object is reset to
      the empty state prior to return from this call.

 > > int '''Tcl_GetBignumAndClearObj'''(Tcl_Interp *''interp'', Tcl_Obj*''objPtr'', mp_int *''value'')

 >  The memory management of these routines deserves some
    explanation. For performance, it is desirable that copying bignums
    be avoided as far as possible. For this reason, the digit array
    stored in the ''mp_int'' object will be stored by pointer in the
    Tcl internal representation. This will result in memory problems
    unless the ''mp_int'' appears to be destroyed after it has been
    placed in a Tcl object, since further calls to the ''libtommath''
    functions may reallocate the array.

 >  Similarly, when retrieving a large integer from an object, if the
    object retains an internal representation with the ''mp_int'', the
    ''mp_int'' must be copied. Code that intends to overwrite or
    destroy an unshared object immediately can avoid the copy by using
    the call that clears the object; this call returns the original
    ''mp_int'' without needing to do any memory management.

 3. The ''internalRep'' union in the ''Tcl_Obj'' structure shall be
    augmented with a ''ptrAndLongRep'' field. This field shall be a
    structure comprising a pointer and a long integer. The pointer
    will designate an array of digits (the ''dp'' member of an
    ''mp_int'' structure in ''libtommath''). The long integer will be
    an encoding comprising:

 > * one bit representing the sign of the number

 > * fifteen bits giving the size of allocated memory in the digit
     array.

 > * fifteen bits giving the size of used memory in the digit array.

 >  The reason for this tight encoding is that the size of a
    ''Tcl_Obj'' shall not change, and yet an ''mp_int'' structure can
    be stored in the internal representation. This encoding will allow
    packing and unpacking the object with a few Boolean operations and
    shifts rather than needing to use a pointer internal
    representation and dynamically allocated memory to store the
    ''mp_int''. This packed representation is adequate to represent
    integers of (2**15 - 1) ''mp_digit''s (or 917,476 bits, since
    libtommath does its arithmetic in base 2**28). Since cryptographic
    algorithms, floating point conversions, and most number theoretic
    work will not exceed this length, the packed representation should
    cover nearly all values used in practice.

 >  When an ''mp_int'' value too large for that tight packing is to be
    stored as the internal rep of a ''Tcl_Obj'', a copy of the
    ''mp_int'' value will be allocated from the heap, and a pointer to
    the copy stored in the pointer field. A value of '''-1''' in the
    long integer field will indicate this unpacked storage option.

 4. A new ''tclBignumType'' (with type name '''bignum''') shall be
    added to the internal set of object types; it will have the
    ''ptrAndLongRep'' internal representation, and the usual four
    conversion routines.

 5. The ''wideIntRep'' field in the ''internalRep'' union shall remain
    (lest there be extensions that use it), but all code in the Tcl
    library that deals with it shall be removed. The routines,
    ''Tcl_GetWideIntFromObj'', ''Tcl_SetWideIntObj'', and
    ''Tcl_NewWideIntObj'' shall remain as part of the API, but will
    create objects with either ''int'' or ''bignum'' internal
    representations.

 6. The '''expr''' command shall be reworked so that all integer
    arithmetic is performed ''as if'' all integers are of arbitrary
    precision. In practice, numbers between LONG_MIN and LONG_MAX
    shall be stored in native long integers. The operators shall
    perform type promotions as needed. The command shall avoid (as far
    as practicable) performing arbitrary-precision arithmetic when
    native long ints are presented. Specifically:

 > * Mixed mode arithmetic with floating point numbers shall work as
     it does today; the argument that is not a floating point number
     shall be converted. Note that it will be possible for conversion
     to overflow the floating-point arithmetic range; in this case,
     the value shall be replaced with ''Inf''.

 > For arithmetic involving only integers:

 > * The unary '-' operator shall promote LONG_MIN to a mp_int; this is
     the only input that can cause it to overflow.

 > * The unary '+' and '!' operators require no promotion; '+' does
     nothing but verify that its argument is numeric, and '!' simply
     tests whether its argument is zero.

 > * The binary '**' operator (and the ''pow'' function) shall promote
     to an arbitrary precision integer conservatively: when computing
     'a**b', it will precompute 'ceil(log2(a)*b)', and promote if this
     logarithm exceeds LONG_BITS-1. The result shall be demoted to an
     integer if it fits.

 > * The binary '*' operator, if either argument is an
     arbitary-precision integer, shall promote the other to an
     arbitrary-precision integer. If both are native integers, and
     ''Tcl_WideInt'' is at least twice the width of a native ''long'',
     then the product will be computed in a ''Tcl_WideInt'', and the
     result will be either demoted to a ''long'' (if it fits) or
     promoted to an ''mp_int''.

 > > In the case where ''Tcl_WideInt'' is not at least twice the width
     of ''long'', the product will be computed to arbitrary precision
     and then demoted if it fits in a ''long''. ''This case is the
     only identified place where arbitrary-precision arithmetic will
     be used on native integers.''

 > * The binary '/' operator, if either argument is an
     arbitrary-precision integer, shall promote the other. If the
     quotient fits in a ''long'', it shall be demoted.

 > * The binary '%' operator, in computing ''a%b'', shall do the
     following:

 > > * If ''a'' and ''b'' are both native long integers, the result is
       also a native long integer.

 > > * If ''a'' is a native long integer but ''b'' is an
       arbitrary-precision integer, then ''a<b'', and ''a%b'' can be
       computed without division.

 > > * If ''b'' is a native ''long'', the division will be carried out
       using the arbitrary precision library, but the result will
       always be a native ''long.''

 > > * If ''a'' and ''b'' are both arbitrary-precision integers, the
       result will be computed to arbitrary precision, but demoted if
       it fits in a ''long''.

 > * The binary ''+'' and ''-'' operators, if either operand is an
     arbitrary-precision integer, shall promote the other operand to
     an arbitrary-precision integer, compute the result to arbitrary
     precision, and demote the result to ''long'' if it fits. If both
     operands are native ''long'', and ''Tcl_WideInt'' is larger than
     a native ''long'', then the result will be computed to
     ''Tcl_WideInt'' precision, and demoted to ''long'' if it fits.

 > > In the case where ''Tcl_WideInt'' is only as wide as ''long'',
     the operators shall test for overflow when adding numbers of like
     sign or subtracting numbers of opposite sign. If the sign of the
     result of one of these operations differs from the sign of the
     first operand, overflow has occurred; the result is promoted to
     an arbitrary precision integer and the sign is restored.

 > * The ''<<'' operator shall fail if its second operand is an
     arbitrary-precision integer and the first is nonzero (because
     this case must exceed the allowable number of digits). It returns
     an arbitrary-precision integer if its first argument is an
     arbitrary-precision integer, or if the shift will overflow. The
     overflow check for ''long'' values (''a<<b'') is

 > > * if ''b''>LONG_BITS-1, overflow.

 > > * if ''a''>0, and (a & -(1<<(LONG_BITS-1-b))), overflow.

 > > * if ''a''<0, and (~a & -(1<<LONG_BITS-1-b))), overflow.

 > * The '>>' operator ''a>>b'', shall return 0 (''a>=0'') or -1
     (''a<0'') if ''b'' is an arbitrary-precision integer (it would
     have shifted away all significant bits). Otherwise, the shift
     shall be performed to the precision of ''a'', and if ''a'' was an
     arbitrary-precision integer, the result shall be demoted to a
     ''long'' if it fits.

 > * The six comparison operators <, <=, ==, !=, >=, and >, can work
     knowing only the signs of the operands wben native ''long''
     values are compared with arbitrary-precision integers.
     Arbitrary-precision comparison is needed only when comparing
     arbitrary-precision integers of like sign. In any case, the
     result is a native ''long''.

 > * The ''eq'', ''ne'', ''in'', and ''ni'' operators work only on
     string representations and will not change.

 > * The ''&&'' and ''||'' and ''?:'' operators only test their
     operands for zero and will not change.

 > * The ~ operator shall follow the algebraic identity:

 > > ~a == -a - 1

 > > This identity holds if ''a'' is represented in any word size
     large enough to hold it without overflowing. It therefore
     generalizes to integers of arbitary precision; essentially,
     negative numbers are thought of as "twos-complement numbers with
     an infinite number of 1 bits at the most significant end."

 > * The base case of the ''&'' (''a&b'') operator shall be defined in
     the obvious way if ''a'' and ''b'' are both positive;
     corresponding bits of their binary representation will be ANDed
     together. For negative operands, the algebraic identity above,
     together with De Morgan's laws, can reduce the operation to the
     base case:

 > > * if a>=0, b<0, a&b == a & ~( ~b ) == a & ( - b - 1 )

 > > * if a<0, b>=0, symmetric with the above.

 > > * if a<0, b<0, a & b = ~( ~a | ~b ) = -( ( -a - 1 ) | ( -b - 1 ) ) - 1

 > * The base case of the ''|'' (''a|b'') operator shall be defined in
     the obvious way if ''a'' and ''b'' are both positive:
     corresponding bits of their binary representation will be ORed
     together. For negative operands, the algebraic identity above,
     together with De Morgan's laws, can reduce the operation to the
     base case:

 > > * if a>=0, b<0, a|b == ~( ~a & ~b ) == -( ~a & ( -b - 1 )) - 1

 > > * if a<0, b>=0, symmetric with the above.

 > > * if a<0, b<0, a|b == ~( ~a & ~b ) == -( ( -a - 1 ) & ( -b - 1 ) ) - 1

 > * The base case of the ''^'' (''a^b'') operator shall be defined in
     the obvious way if ''a'' and ''b'' are both positive:
     corresponding bits of their binary representation will be
     EXCLUSIVE ORed together. For negative operands, the algebraic
     identity above, together with the contrapositive law, can reduce
     the operation to the base case:

 > > * if a>=0, b<0, a^b == ~( a ^ ~b ) == -( a ^ ( -b - 1 ) ) - 1

 > > * if a<0, b>=0, symmetric with the above.

 > > * if a<0, b<0, a^b == ~a ^ ~b == ( -a - 1 ) ^ ( -b - 1 )

 > * The abs(), ceil(), double(), floor(), int(), round(), sqrt(), and
     wide() math functions shall all be modified to accept
     arbitrary-precision integers as parameters. All these functions
     will continue to return the same "type" as they do now (integer
     vs. floating point), but the domain and/or range will be extended
     to permit arbitrarily large integers as appropriate.

 > * A new function, ''entier($x)'' will be introduced; the function
     coerces ''$x'' to an integer of appropriate size. ''entier()'' is
     distinguished from ''int()'' in that ''int()'' results in an
     integer limited to the size of the native long integer always,
     while ''entier()'' results in whatever size of integer is needed
     to hold the full value.

 7. The '''incr''' and '''dict incr''' commands shall work on
    arbitary-precision values. Specifically, [[incr a $n]] will behave
    like [[set a [[expr { $a + $n }]]]] with the constraint that
    ''$a'' and ''$b'' must both be integers.

 8. The '''format''' and '''scan''' commands will acquire ''%lld'',
    ''%lli'', ''%llo'', ''%llx'' and ''%llX'' specifiers that format
    their arguments as arbitrary-precision decimal, (decimal/any
    format), octal, and hexadecimal integers, respectively. The format
    specifier ''%llu'' is invalid and will cause an error. The
    ''%llo'' and ''%llx'' specifiers, unlike their native-integer
    counterparts, will format ''signed'' numbers; the result of
    [[format %#llx -12345]] will not be 0xffffcfc7, but rather
    -0x3039. (If an application requires hexadecimal numbers in two's
    complement notation, it can get them by forcing a number to be
    positive:

|     set x -12345
|     set x64bit [expr { $x & ((1<<64) - 1) }]
|     format %#llx $x64bit

 >  will yield '0xffffffffffffcfc7'.

 9. User defined math functions will be able to gain access to a
    ''bignumValue'' only if they are created using the techniques
    described in [232]. The Tcl command that implements the user
    defined math function will be able to receive a '''bignum'''
    Tcl_Obj value just as it can receive any other Tcl_ObjType. The
    legacy ''Tcl_Value'' structure, will '''not''' be updated to add a
    bignum-valued field.

 10. The number parser detailed in [249] will be adopted into the
    Tcl internals.  See [249] for details on the implications.

~ Integration Details

The ''libtommath'' source code shall be extracted from the
distributions available at [http://math.libtomcrypt.com/] and brought
into the CVS repository as a ''vendor branch'' (see
[https://www.cvshome.org/docs/manual/cvs-1.11.18/cvs_13.html#SEC103]
for a discussion of managing vendor branches. It appears that all the
necessary modifications to integrate this source code with Tcl can be
made in the single file, ''tommath.h''; it is likely that the
''tools/'' directory in the Tcl source tree will contain a Tcl script
to make the modifications automatically when importing a new version.
CVS can maintain local modifications effectively, should we find it
necessary to patch the other sources.

The chief modification is that all the external symbols in the library
will have TclBN prepended to their names, so that they will not give
linking conflicts if an extension uses a 'tommath' library not
supplied with Tcl - or uses any other library compatible with the
Berkeley ''mp'' API.

~ Choice of Library

The ''libtommath'' code is chosen from among a fairly large set of
possible third-party bignum codes. Among the ones considered were:

 GMP: The Gnu GMP library is probably the fastest and most complete of
  the codes available. Alas, it is licensed under LGPL, which would
  require all distributors who prepare binary Tcl distributions to
  include the GMP source code. I chose to avoid any legal
  entanglements, and avoided GMP for this reason.

 The original Berkeley mp library: This library is atrociously slow,
  and was avoided for that reason.

 Gnu Calc: GPL licensed. A non-starter for that reason.

 mpexpr: This Tcl extension has been available for many years and is
  released under the BSD license. (It was the basis for Gnu Calc but
  predates the fork, and hence is not GPL-contaminated.) It would
  certainly be a possibility, but the code is not terribly well
  documented, is slow by today's standards, and still uses
  string-based Tcl API's. It would be a considerable amount of work to
  bring it into conformance with today's Tcl core engineering
  practices.

 OpenSSL: The OpenSSL library includes a fast and well-documented
  bignum library (developed so that OpenSSL can do RSA cryptography).
  Alas, the code is licensed under the original BSD license agreement,
  and has several parties added to the dreaded Advertising Clause.
  The Advertising Clause would present serious difficulties for our
  distributors, and so OpenSSL is not suitable. (The OpenSSL
  developers are not amenable to removing the Advertising Clause from
  the license.)

Several libraries implemented in C++ were dismissed out of hand,
because of the deployment issues associated with C++ runtime libraries
and static constructors.

The ''libtommath'' code is released to the Public Domain. Its author,
Tom St. Denis, explicitly and irrevocably authorizes its use for any
purpose, without fee, and without attribution. So license
incompatibilities aren't going to be an issue. The documentation is
wonderful (Tom has written a book of several hundred pages
[http://book.libtomcrypt.com/draft/tommath.pdf] describing the
algorithms used), and the code is lucid.

The chief disadvantage to ''libtommath'' is that it is a one-person
effort, and hence has the risk of becoming orphaned. I consider this
risk to be of acceptable severity, because of the quality of the code.
The Tcl maintainers could take it on quite readily.

~ Additional Possibilities

The Tcl library will actually use only about one-third of
''libtommath'' to implement the ''expr'' command. In particular, the
library functions for squaring, fast modular reduction, modular
exponentiation, greatest common divisor, least common multiple, Jacobi
symbol, modular inverse, primality testing and the solution of linear
Diophantine equations are not needed, and shall not be include in the
Tcl library to save memory footprint.

Nevertheless, these operations would be extremely useful in an
extension, so that programs that don't live with tight memory
constraints can do things like fast Diffie-Hellman or RSA
cryptography. We should probably consider a 'bignum' package to be
bundled with the core distribution that would add appropriate math
functions wrapping these operations.

~ Reference Implementation

A feature complete implementation is present on the CVS branch called
'kennykb-numerics-branch'.

~ Copyright

Copyright � 2005 by Kevin B. Kenny. All rights reserved.

This document may be distributed subject to the terms and conditions
set forth in the Open Publication License, version 1.0
[http://www.opencontent.org/openpub/].

<
|
<
|
|
|
|
|
|
|
|
>

|




|


|



|

|







|
|
|
|


|



|
|
|
|
|
|


|















|







|




|

|




|
|


|
|
|

|

|

|
|
|
|
|
|


|

|
|
|
|

|

|
|
|
|
|


|

|


|

|
|


|
|
|


|

|
|

|
|


|

|


|

|
|




|
|
|




|
|
|
|


|

|


|
|

|
|
|


|
|
|

|
|


|



|

|

|


|



|

|
|


|


|
|
|
|

|
|
|

|

|

|

|


|


|
|


|

|

|

|

|


|
|
|
|

|






|
|
|


|

|

|

|

|
|
|
|

|

|
|



|

|


|


|

|

|





|
|





|

|

|

|
|





|

|

|

|
|





|

|

|

|
|

|
|


|
|
|

|


|
|
|
|

|
|
|
|
|
|
|
|
|



|
|
|

|


|
|
|
|
|


|
|

|

|
|
|
|


|
|








|

|

|














|
|







|



|

|

|
|


|



|
|
|

|




|


|













|




|

|



|
>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498

# TIP 237: Arbitrary-Precision Integers for Tcl

	Author:         Kevin B. Kenny <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        14-Jan-2005
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP adds the capability to perform computations on integer values
of arbitrary precision.

# Rationale

There have been a number of issues in Tcl 8.4 dealing with the limited
range of native integers and wide values. The original ideas of [[72]](72.md),
while they have given at least the basics of 64-bit integer support,
have also introduced some subtle violations of the doctrine that
"everything is a string." Some of these have been insidious bugs -
<http://sf.net/tracker/?func=detail&aid=868489&group_id=10894&atid=110894> 
and
<http://sf.net/tracker/?func=detail&aid=1006626&group_id=10894&atid=110894> 
are illustrative - while others are perhaps not "bugs" in the
strictest sense, but are still surprising behaviour.

For instance, it is possible for a script to tell integers from wide
integers even when their string representations are equal, by
performing any arithmetic operation that overflows:

	    % set x 2147483647    % set x [expr { wide(2146483647) }]
	    2147483647            2147483647
	    % incr x              % incr x
	    -2147483648           2147483648

With things as they stand,
<http://sf.net/tracker/?func=detail&aid=1006626&group_id=10894&atid=110894> 
is nearly unfixable. It causes misconversion of large floating point
numbers that look like integers:

	    % set x -9223372036854775809
	    -9223372036854775809
	    % expr {double($x)}
	    9.22337203685e+018
	    % scan $x %g
	    -9.22337203685e+018

The reason here is that the string of digits is first converted to a
64-bit unsigned integer \(**Tcl\_WideUInt**\). The '-' sign causes the
unsigned integer to be interpreted as a signed integer, and the sign
reversed. Since interpreting the unsigned integer as signed yields an
overflow, the result is positive rather than negative and gives the
odd behaviour shown above.

Of course, even if the implementation of 64-bit arithmetic were bug
free, there would be uses for arithmetic of higher precision. One
example is that several Tcl users have attempted pure-Tcl
implementations of RSA and Diffie-Hellman cryptographic algorithms.
These algorithms depend on arithmetic of high precision; implementing
them efficiently in today's Tcl requires a C extension because the
high-precision algorithms implemented in Tcl are simply too slow to be
acceptable.

Finally, studying the references for accurate conversion of floating
point numbers [[132]](132.md) reveals that input and output conversions both
require arbitrary-precision arithmetic in their implementation. The
reference implementation supplied with that TIP, alas, is code that is
poorly commented and difficult to integrate into Tcl's build system.
Reimplementing it according to Tcl's engineering practices means
implementing a large part of an arbitrary-precision arithmetic
library.

# Proposal

This TIP proposes augmenting Tcl with code for processing integers of
arbitrary precision. Specifically:

 1. The _libtommath_ library <http://math.libtomcrypt.com/>  shall be
    added in a subdirectory of the Tcl source tree, parallel to
    _generic/_, _compat/_, etc. This library implements arithmetic
    on integers of arbitrary precision. For the rationale behind this
    library, and some of the precise integration details, see "Choice
    of Libary" below.

 2. New functions, _Tcl\_NewBignumObj_, _Tcl\_SetBignumObj_,
    _Tcl\_GetBignumFromObj_ and _Tcl\_GetBignumAndClearObj_ shall be
    added to the Tcl library. They shall be specified as follows:

	 > Tcl\_NewBignumObj: Creates an object containing an integer of
      arbitrary precision. The _value_ argument gives the integer in
      the format native to _libtommath_. _Upon return, the value
      argument is cleared, because its digit array has had its
      ownership transferred to the Tcl library._

	 > > Tcl\_Obj \***Tcl\_NewBignumObj**\(mp\_int \*_value_\)

	 > Tcl\_SetBignumObj: Changes the value of an object to an integer of
      arbitrary precision. The _value_ argument gives the integer in
      the format native to _libtommath_. As with other
      **Tcl\_SetFooObj** routines, the **Tcl\_Obj** having its value
      set must be unshared \(copy on write\). As with
      **Tcl\_NewBignumObj**, the _value_ argument is cleared on
      return and the digit list is owned by Tcl thereafter.

	 > > void **Tcl\_SetBignumObj**\(Tcl\_Obj \*_objPtr_, mp\_int \*_value_\)

	 > Tcl\_GetBignumFromObj: Interprets an object as a large integer, and
    constructs a copy of that large integer in the _value_ argument.
    Returns _TCL\_OK_ if successful. On failure, stores an error
    message in the result of _interp_ and returns _TCL\_ERROR_.

	 > > int **Tcl\_GetBignumFromObj**\(Tcl\_Interp \*_interp_, Tcl\_Obj\*_objPtr_, mp\_int \*_value_\)

	 > Tcl\_GetBignumAndClearObj: Interprets an object as a large integer,
      and stores the large integer in the _value_ argument. Returns
      _TCL\_OK_ if successful. On failure, stores an error message in
      the result of _interp_ and returns _TCL\_ERROR_. Calls
      **Tcl\_Panic** if the object is shared. The object is reset to
      the empty state prior to return from this call.

	 > > int **Tcl\_GetBignumAndClearObj**\(Tcl\_Interp \*_interp_, Tcl\_Obj\*_objPtr_, mp\_int \*_value_\)

	 >  The memory management of these routines deserves some
    explanation. For performance, it is desirable that copying bignums
    be avoided as far as possible. For this reason, the digit array
    stored in the _mp\_int_ object will be stored by pointer in the
    Tcl internal representation. This will result in memory problems
    unless the _mp\_int_ appears to be destroyed after it has been
    placed in a Tcl object, since further calls to the _libtommath_
    functions may reallocate the array.

	 >  Similarly, when retrieving a large integer from an object, if the
    object retains an internal representation with the _mp\_int_, the
    _mp\_int_ must be copied. Code that intends to overwrite or
    destroy an unshared object immediately can avoid the copy by using
    the call that clears the object; this call returns the original
    _mp\_int_ without needing to do any memory management.

 3. The _internalRep_ union in the _Tcl\_Obj_ structure shall be
    augmented with a _ptrAndLongRep_ field. This field shall be a
    structure comprising a pointer and a long integer. The pointer
    will designate an array of digits \(the _dp_ member of an
    _mp\_int_ structure in _libtommath_\). The long integer will be
    an encoding comprising:

	 > \* one bit representing the sign of the number

	 > \* fifteen bits giving the size of allocated memory in the digit
     array.

	 > \* fifteen bits giving the size of used memory in the digit array.

	 >  The reason for this tight encoding is that the size of a
    _Tcl\_Obj_ shall not change, and yet an _mp\_int_ structure can
    be stored in the internal representation. This encoding will allow
    packing and unpacking the object with a few Boolean operations and
    shifts rather than needing to use a pointer internal
    representation and dynamically allocated memory to store the
    _mp\_int_. This packed representation is adequate to represent
    integers of \(2\*\*15 - 1\) _mp\_digit_s \(or 917,476 bits, since
    libtommath does its arithmetic in base 2\*\*28\). Since cryptographic
    algorithms, floating point conversions, and most number theoretic
    work will not exceed this length, the packed representation should
    cover nearly all values used in practice.

	 >  When an _mp\_int_ value too large for that tight packing is to be
    stored as the internal rep of a _Tcl\_Obj_, a copy of the
    _mp\_int_ value will be allocated from the heap, and a pointer to
    the copy stored in the pointer field. A value of **-1** in the
    long integer field will indicate this unpacked storage option.

 4. A new _tclBignumType_ \(with type name **bignum**\) shall be
    added to the internal set of object types; it will have the
    _ptrAndLongRep_ internal representation, and the usual four
    conversion routines.

 5. The _wideIntRep_ field in the _internalRep_ union shall remain
    \(lest there be extensions that use it\), but all code in the Tcl
    library that deals with it shall be removed. The routines,
    _Tcl\_GetWideIntFromObj_, _Tcl\_SetWideIntObj_, and
    _Tcl\_NewWideIntObj_ shall remain as part of the API, but will
    create objects with either _int_ or _bignum_ internal
    representations.

 6. The **expr** command shall be reworked so that all integer
    arithmetic is performed _as if_ all integers are of arbitrary
    precision. In practice, numbers between LONG\_MIN and LONG\_MAX
    shall be stored in native long integers. The operators shall
    perform type promotions as needed. The command shall avoid \(as far
    as practicable\) performing arbitrary-precision arithmetic when
    native long ints are presented. Specifically:

	 > \* Mixed mode arithmetic with floating point numbers shall work as
     it does today; the argument that is not a floating point number
     shall be converted. Note that it will be possible for conversion
     to overflow the floating-point arithmetic range; in this case,
     the value shall be replaced with _Inf_.

	 > For arithmetic involving only integers:

	 > \* The unary '-' operator shall promote LONG\_MIN to a mp\_int; this is
     the only input that can cause it to overflow.

	 > \* The unary '\+' and '!' operators require no promotion; '\+' does
     nothing but verify that its argument is numeric, and '!' simply
     tests whether its argument is zero.

	 > \* The binary '\*\*' operator \(and the _pow_ function\) shall promote
     to an arbitrary precision integer conservatively: when computing
     'a\*\*b', it will precompute 'ceil\(log2\(a\)\*b\)', and promote if this
     logarithm exceeds LONG\_BITS-1. The result shall be demoted to an
     integer if it fits.

	 > \* The binary '\*' operator, if either argument is an
     arbitary-precision integer, shall promote the other to an
     arbitrary-precision integer. If both are native integers, and
     _Tcl\_WideInt_ is at least twice the width of a native _long_,
     then the product will be computed in a _Tcl\_WideInt_, and the
     result will be either demoted to a _long_ \(if it fits\) or
     promoted to an _mp\_int_.

	 > > In the case where _Tcl\_WideInt_ is not at least twice the width
     of _long_, the product will be computed to arbitrary precision
     and then demoted if it fits in a _long_. _This case is the
     only identified place where arbitrary-precision arithmetic will
     be used on native integers._

	 > \* The binary '/' operator, if either argument is an
     arbitrary-precision integer, shall promote the other. If the
     quotient fits in a _long_, it shall be demoted.

	 > \* The binary '%' operator, in computing _a%b_, shall do the
     following:

	 > > \* If _a_ and _b_ are both native long integers, the result is
       also a native long integer.

	 > > \* If _a_ is a native long integer but _b_ is an
       arbitrary-precision integer, then _a<b_, and _a%b_ can be
       computed without division.

	 > > \* If _b_ is a native _long_, the division will be carried out
       using the arbitrary precision library, but the result will
       always be a native _long._

	 > > \* If _a_ and _b_ are both arbitrary-precision integers, the
       result will be computed to arbitrary precision, but demoted if
       it fits in a _long_.

	 > \* The binary _\+_ and _-_ operators, if either operand is an
     arbitrary-precision integer, shall promote the other operand to
     an arbitrary-precision integer, compute the result to arbitrary
     precision, and demote the result to _long_ if it fits. If both
     operands are native _long_, and _Tcl\_WideInt_ is larger than
     a native _long_, then the result will be computed to
     _Tcl\_WideInt_ precision, and demoted to _long_ if it fits.

	 > > In the case where _Tcl\_WideInt_ is only as wide as _long_,
     the operators shall test for overflow when adding numbers of like
     sign or subtracting numbers of opposite sign. If the sign of the
     result of one of these operations differs from the sign of the
     first operand, overflow has occurred; the result is promoted to
     an arbitrary precision integer and the sign is restored.

	 > \* The _<<_ operator shall fail if its second operand is an
     arbitrary-precision integer and the first is nonzero \(because
     this case must exceed the allowable number of digits\). It returns
     an arbitrary-precision integer if its first argument is an
     arbitrary-precision integer, or if the shift will overflow. The
     overflow check for _long_ values \(_a<<b_\) is

	 > > \* if _b_>LONG\_BITS-1, overflow.

	 > > \* if _a_>0, and \(a & -\(1<<\(LONG\_BITS-1-b\)\)\), overflow.

	 > > \* if _a_<0, and \(~a & -\(1<<LONG\_BITS-1-b\)\)\), overflow.

	 > \* The '>>' operator _a>>b_, shall return 0 \(_a>=0_\) or -1
     \(_a<0_\) if _b_ is an arbitrary-precision integer \(it would
     have shifted away all significant bits\). Otherwise, the shift
     shall be performed to the precision of _a_, and if _a_ was an
     arbitrary-precision integer, the result shall be demoted to a
     _long_ if it fits.

	 > \* The six comparison operators <, <=, ==, !=, >=, and >, can work
     knowing only the signs of the operands wben native _long_
     values are compared with arbitrary-precision integers.
     Arbitrary-precision comparison is needed only when comparing
     arbitrary-precision integers of like sign. In any case, the
     result is a native _long_.

	 > \* The _eq_, _ne_, _in_, and _ni_ operators work only on
     string representations and will not change.

	 > \* The _&&_ and _\|\|_ and _?:_ operators only test their
     operands for zero and will not change.

	 > \* The ~ operator shall follow the algebraic identity:

	 > > ~a == -a - 1

	 > > This identity holds if _a_ is represented in any word size
     large enough to hold it without overflowing. It therefore
     generalizes to integers of arbitary precision; essentially,
     negative numbers are thought of as "twos-complement numbers with
     an infinite number of 1 bits at the most significant end."

	 > \* The base case of the _&_ \(_a&b_\) operator shall be defined in
     the obvious way if _a_ and _b_ are both positive;
     corresponding bits of their binary representation will be ANDed
     together. For negative operands, the algebraic identity above,
     together with De Morgan's laws, can reduce the operation to the
     base case:

	 > > \* if a>=0, b<0, a&b == a & ~\( ~b \) == a & \( - b - 1 \)

	 > > \* if a<0, b>=0, symmetric with the above.

	 > > \* if a<0, b<0, a & b = ~\( ~a \| ~b \) = -\( \( -a - 1 \) \| \( -b - 1 \) \) - 1

	 > \* The base case of the _\|_ \(_a\|b_\) operator shall be defined in
     the obvious way if _a_ and _b_ are both positive:
     corresponding bits of their binary representation will be ORed
     together. For negative operands, the algebraic identity above,
     together with De Morgan's laws, can reduce the operation to the
     base case:

	 > > \* if a>=0, b<0, a\|b == ~\( ~a & ~b \) == -\( ~a & \( -b - 1 \)\) - 1

	 > > \* if a<0, b>=0, symmetric with the above.

	 > > \* if a<0, b<0, a\|b == ~\( ~a & ~b \) == -\( \( -a - 1 \) & \( -b - 1 \) \) - 1

	 > \* The base case of the _^_ \(_a^b_\) operator shall be defined in
     the obvious way if _a_ and _b_ are both positive:
     corresponding bits of their binary representation will be
     EXCLUSIVE ORed together. For negative operands, the algebraic
     identity above, together with the contrapositive law, can reduce
     the operation to the base case:

	 > > \* if a>=0, b<0, a^b == ~\( a ^ ~b \) == -\( a ^ \( -b - 1 \) \) - 1

	 > > \* if a<0, b>=0, symmetric with the above.

	 > > \* if a<0, b<0, a^b == ~a ^ ~b == \( -a - 1 \) ^ \( -b - 1 \)

	 > \* The abs\(\), ceil\(\), double\(\), floor\(\), int\(\), round\(\), sqrt\(\), and
     wide\(\) math functions shall all be modified to accept
     arbitrary-precision integers as parameters. All these functions
     will continue to return the same "type" as they do now \(integer
     vs. floating point\), but the domain and/or range will be extended
     to permit arbitrarily large integers as appropriate.

	 > \* A new function, _entier\($x\)_ will be introduced; the function
     coerces _$x_ to an integer of appropriate size. _entier\(\)_ is
     distinguished from _int\(\)_ in that _int\(\)_ results in an
     integer limited to the size of the native long integer always,
     while _entier\(\)_ results in whatever size of integer is needed
     to hold the full value.

 7. The **incr** and **dict incr** commands shall work on
    arbitary-precision values. Specifically, [incr a $n] will behave
    like [set a [expr { $a + $n }]] with the constraint that
    _$a_ and _$b_ must both be integers.

 8. The **format** and **scan** commands will acquire _%lld_,
    _%lli_, _%llo_, _%llx_ and _%llX_ specifiers that format
    their arguments as arbitrary-precision decimal, \(decimal/any
    format\), octal, and hexadecimal integers, respectively. The format
    specifier _%llu_ is invalid and will cause an error. The
    _%llo_ and _%llx_ specifiers, unlike their native-integer
    counterparts, will format _signed_ numbers; the result of
    [format %#llx -12345] will not be 0xffffcfc7, but rather
    -0x3039. \(If an application requires hexadecimal numbers in two's
    complement notation, it can get them by forcing a number to be
    positive:

		     set x -12345
		     set x64bit [expr { $x & ((1<<64) - 1) }]
		     format %#llx $x64bit

	 >  will yield '0xffffffffffffcfc7'.

 9. User defined math functions will be able to gain access to a
    _bignumValue_ only if they are created using the techniques
    described in [[232]](232.md). The Tcl command that implements the user
    defined math function will be able to receive a **bignum**
    Tcl\_Obj value just as it can receive any other Tcl\_ObjType. The
    legacy _Tcl\_Value_ structure, will **not** be updated to add a
    bignum-valued field.

 10. The number parser detailed in [[249]](249.md) will be adopted into the
    Tcl internals.  See [[249]](249.md) for details on the implications.

# Integration Details

The _libtommath_ source code shall be extracted from the
distributions available at <http://math.libtomcrypt.com/>  and brought
into the CVS repository as a _vendor branch_ \(see
<https://www.cvshome.org/docs/manual/cvs-1.11.18/cvs_13.html#SEC103> 
for a discussion of managing vendor branches. It appears that all the
necessary modifications to integrate this source code with Tcl can be
made in the single file, _tommath.h_; it is likely that the
_tools/_ directory in the Tcl source tree will contain a Tcl script
to make the modifications automatically when importing a new version.
CVS can maintain local modifications effectively, should we find it
necessary to patch the other sources.

The chief modification is that all the external symbols in the library
will have TclBN prepended to their names, so that they will not give
linking conflicts if an extension uses a 'tommath' library not
supplied with Tcl - or uses any other library compatible with the
Berkeley _mp_ API.

# Choice of Library

The _libtommath_ code is chosen from among a fairly large set of
possible third-party bignum codes. Among the ones considered were:

 GMP: The Gnu GMP library is probably the fastest and most complete of
  the codes available. Alas, it is licensed under LGPL, which would
  require all distributors who prepare binary Tcl distributions to
  include the GMP source code. I chose to avoid any legal
  entanglements, and avoided GMP for this reason.

 The original Berkeley mp library: This library is atrociously slow,
  and was avoided for that reason.

 Gnu Calc: GPL licensed. A non-starter for that reason.

 mpexpr: This Tcl extension has been available for many years and is
  released under the BSD license. \(It was the basis for Gnu Calc but
  predates the fork, and hence is not GPL-contaminated.\) It would
  certainly be a possibility, but the code is not terribly well
  documented, is slow by today's standards, and still uses
  string-based Tcl API's. It would be a considerable amount of work to
  bring it into conformance with today's Tcl core engineering
  practices.

 OpenSSL: The OpenSSL library includes a fast and well-documented
  bignum library \(developed so that OpenSSL can do RSA cryptography\).
  Alas, the code is licensed under the original BSD license agreement,
  and has several parties added to the dreaded Advertising Clause.
  The Advertising Clause would present serious difficulties for our
  distributors, and so OpenSSL is not suitable. \(The OpenSSL
  developers are not amenable to removing the Advertising Clause from
  the license.\)

Several libraries implemented in C\+\+ were dismissed out of hand,
because of the deployment issues associated with C\+\+ runtime libraries
and static constructors.

The _libtommath_ code is released to the Public Domain. Its author,
Tom St. Denis, explicitly and irrevocably authorizes its use for any
purpose, without fee, and without attribution. So license
incompatibilities aren't going to be an issue. The documentation is
wonderful \(Tom has written a book of several hundred pages
<http://book.libtomcrypt.com/draft/tommath.pdf>  describing the
algorithms used\), and the code is lucid.

The chief disadvantage to _libtommath_ is that it is a one-person
effort, and hence has the risk of becoming orphaned. I consider this
risk to be of acceptable severity, because of the quality of the code.
The Tcl maintainers could take it on quite readily.

# Additional Possibilities

The Tcl library will actually use only about one-third of
_libtommath_ to implement the _expr_ command. In particular, the
library functions for squaring, fast modular reduction, modular
exponentiation, greatest common divisor, least common multiple, Jacobi
symbol, modular inverse, primality testing and the solution of linear
Diophantine equations are not needed, and shall not be include in the
Tcl library to save memory footprint.

Nevertheless, these operations would be extremely useful in an
extension, so that programs that don't live with tight memory
constraints can do things like fast Diffie-Hellman or RSA
cryptography. We should probably consider a 'bignum' package to be
bundled with the core distribution that would add appropriate math
functions wrapping these operations.

# Reference Implementation

A feature complete implementation is present on the CVS branch called
'kennykb-numerics-branch'.

# Copyright

Copyright © 2005 by Kevin B. Kenny. All rights reserved.

This document may be distributed subject to the terms and conditions
set forth in the Open Publication License, version 1.0
<http://www.opencontent.org/openpub/> .

Name change from tip/238.tip to tip/238.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

TIP:		238
Title:		Fire Event when Widget Created
Version:	$Revision: 1.7 $
Author:		Gerald W. Lester <[email protected]>
State:		Draft
Type:		Project
Vote:		Pending
Tcl-Version:	8.7
Created:	25-Jan-2005
Post-History:   
Keywords:	Tk


~ Abstract

This TIP arranged for a new virtual event to be fired every time a widget is
created. This allows class bindings to automatically discover new widget
instances and act on their creation.

~ Rationale

It would be useful if it was possible to set an event on class bindings to
allow custom code to be run when a widget of a particular class is created.

Note that the standard X11 <Create> event is not quite suitable, because that
is delivered to the X11 parent of the widget, which is not Tk in the case of
toplevel windows.

~ Proposal

It is proposed that the virtual event <<Create>> be sent to every widget upon
the creation of its actual underlying window (i.e. as part of
'''Tk_MakeWindowExist'''). Note that this is the earliest at which an event
can actually be delivered to the widget; before that, doing '''event
generate''' to the widget just creates an event that gets discarded.

~~ Example

|% bind Toplevel <<Create>> {
|    puts stdout {New toplevel called {%W} was created!}
|}

|% toplevel .foo
|New toplevel called {.foo} was created!

~~ Proposed C API Changes

No changes would be requried, this change is for the Tcl layer API.

~ Reference Implementation

A reference implementation does ''not'' yet exist.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|








|


|
|
|
|

|

|
|
<
>
|
|

|



|

|

|


>

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

# TIP 238: Fire Event when Widget Created

	Author:		Gerald W. Lester <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		Pending
	Tcl-Version:	8.7
	Created:	25-Jan-2005
	Post-History:   
	Keywords:	Tk
-----

# Abstract

This TIP arranged for a new virtual event to be fired every time a widget is
created. This allows class bindings to automatically discover new widget
instances and act on their creation.

# Rationale

It would be useful if it was possible to set an event on class bindings to
allow custom code to be run when a widget of a particular class is created.

Note that the standard X11 <Create> event is not quite suitable, because that
is delivered to the X11 parent of the widget, which is not Tk in the case of
toplevel windows.

# Proposal

It is proposed that the virtual event <<Create>> be sent to every widget upon
the creation of its actual underlying window \(i.e. as part of
**Tk\_MakeWindowExist**\). Note that this is the earliest at which an event
can actually be delivered to the widget; before that, doing **event
generate** to the widget just creates an event that gets discarded.

## Example

	% bind Toplevel <<Create>> {
	    puts stdout {New toplevel called {%W} was created!}

	}
	% toplevel .foo
	New toplevel called {.foo} was created!

## Proposed C API Changes

No changes would be requried, this change is for the Tcl layer API.

# Reference Implementation

A reference implementation does _not_ yet exist.

# Copyright

This document has been placed in the public domain.

Name change from tip/239.tip to tip/239.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

TIP:            239
Title:          Enhance the 'load' Command
Version:        $Revision: 1.12 $
Author:         Jeff Hobbs <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        26-Jan-2005
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes enhancing the Tcl '''load''' command with the
ability to load arbitrary libraries and functions.

~ Rationale

The current Tcl '''load''' command limits itself operating within the
context of loading Tcl extension libraries and nothing else, even
though all the code is there for general library loading.  With the
introduction of the VFS and more extensions having prerequisite
library dependencies, the ability to load arbitrary libraries would
ease development of StarKits with these extensions.  It will also
provide a general mechanism to assist other developers get around the
difficult process of cross-platform library loading.

~ Specification

Current specification:

 > '''load''' ''fileName'' ?''packageName'' ?''interp''??

Recommended specification:

 > '''load''' ?'''-function''' ''funcName''?
   ?'''-interp''' ''interp''?
   ?'''-package''' ''packageName''?
   ?'''-keeplibrary'''?
   ?'''--'''?
   ''fileName||libref''

 > returns library pointer reference value

The '''-interp''' option takes the place of the optional final
''interp'' argument.

The '''-package''' option replaces the optional ''packageName'' argument.  The user specifies just the partial function name without the "_Init" or "_SafeInit", as before.  The function is called with the Tcl interpreter to initialize as the sole argument.  If this option is not specified, the name is inferred from the filename.  If '''-function''' is specified, the Init call is not made.

The '''-function''' option takes a C function name to find the symbol
of (via dlsym(), GetProcAddress(), or related function).  If
'''-function''' is specified, '''-call''' and '''-interp''' are
ignored and the return value is the pointer location to the function,
or 0 if it is not found.  When this is used, the library is not closed
upon success, it remains open until a call to '''unload''' is made.

The '''-keeplibrary''' option set a flag to indicate the library should not be unloaded by Tcl.  This is needed in cases where the library may register functions (eg, via C's '''atexit''') that are needed beyond the lifetime of Tcl finalization.  This should only be used when necessary.

An error is thrown if the library cannot be loaded, otherwise a library pointer reference value is returned (unless '''-function''' is used).

'''load''' could take a library pointer reference as an argument for repeated '''-function''' requests.

I will also recommend obsoleting the existing '''unload''' call to use
this new functional spec style.  Current spec, to be unsupported (it's
new in 8.5):

 > '''unload''' ?''switches''? ''fileName'' ?''packageName'' ?''interp''??

New specification:

 > '''unload''' ?'''-interp''' ''interp''? ?'''-package'''
   ''packageName''? ?'''-keeplibrary'''? ?'''--'''?
   ''fileName||libref''

I removed the ''-nocomplain'' option.  The user should simply '''catch''' the command if they wish to suppress the types of errors that unload would throw.

I think that C functions should be made available as well for
cross-platform access to the load functionality, but that is not
specified in this TIP.  This would need to account for users that may
configure Tcl with --disable-load (does anybody need that anymore?).

~ Discussion

Not all platforms may support library loading to a degree required for this TIP functionality.  In that case, an error message will be thrown.

The use of '''--''' as a option end switch was debated as unnecessary since there is only one fixed argument.  JH likes the use of it for the completeness it gives the use of switches.

The '''load''' command will determine the use of the new form by checking if more than one argument is given and the first argument starts with a '''-'''.  This should not affect any existing extensions, as dynamic library filenames beginning with '''-''' are rare.

Here is a reference to Perl's dynamic library loading functionality:

http://aspn.activestate.com/ASPN/Perl/Products/ActivePerl/5.8/lib/DynaLoader.html

~ Examples

For a package in a starkit, tls example with shared OpenSSL library
shipped in package:

| # $dir set by package mechanism
| if {[package provide starkit] ne ""} {
|     load -call {} $dir/libopenssl.so
| }

| load $dir/libtls1.5.so

This would handle the extracting of dependent libraries in starkits automatically (and their subsequent disposal).

Another example would be Oratcl 4.3's use of dynamic Oracle library
callouts, which it has to do by hand due to the lack of this
functionality in the core.

~ Reference Implementation

[[To be uploaded to SourceForge and URL added to this TIP.]]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|


|

|








|



|



|
|
|
|
|
|



|
|

|

|
|
|


|

|

|

|

|
|
|

|



|
|
|

|




|

|



|

|



|

|




|
|
|
<
>
|

|





|

|

|


>

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

# TIP 239: Enhance the 'load' Command

	Author:         Jeff Hobbs <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        26-Jan-2005
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes enhancing the Tcl **load** command with the
ability to load arbitrary libraries and functions.

# Rationale

The current Tcl **load** command limits itself operating within the
context of loading Tcl extension libraries and nothing else, even
though all the code is there for general library loading.  With the
introduction of the VFS and more extensions having prerequisite
library dependencies, the ability to load arbitrary libraries would
ease development of StarKits with these extensions.  It will also
provide a general mechanism to assist other developers get around the
difficult process of cross-platform library loading.

# Specification

Current specification:

 > **load** _fileName_ ?_packageName_ ?_interp_??

Recommended specification:

 > **load** ?**-function** _funcName_?
   ?**-interp** _interp_?
   ?**-package** _packageName_?
   ?**-keeplibrary**?
   ?**--**?
   _fileName\|\|libref_

 > returns library pointer reference value

The **-interp** option takes the place of the optional final
_interp_ argument.

The **-package** option replaces the optional _packageName_ argument.  The user specifies just the partial function name without the "\_Init" or "\_SafeInit", as before.  The function is called with the Tcl interpreter to initialize as the sole argument.  If this option is not specified, the name is inferred from the filename.  If **-function** is specified, the Init call is not made.

The **-function** option takes a C function name to find the symbol
of \(via dlsym\(\), GetProcAddress\(\), or related function\).  If
**-function** is specified, **-call** and **-interp** are
ignored and the return value is the pointer location to the function,
or 0 if it is not found.  When this is used, the library is not closed
upon success, it remains open until a call to **unload** is made.

The **-keeplibrary** option set a flag to indicate the library should not be unloaded by Tcl.  This is needed in cases where the library may register functions \(eg, via C's **atexit**\) that are needed beyond the lifetime of Tcl finalization.  This should only be used when necessary.

An error is thrown if the library cannot be loaded, otherwise a library pointer reference value is returned \(unless **-function** is used\).

**load** could take a library pointer reference as an argument for repeated **-function** requests.

I will also recommend obsoleting the existing **unload** call to use
this new functional spec style.  Current spec, to be unsupported \(it's
new in 8.5\):

 > **unload** ?_switches_? _fileName_ ?_packageName_ ?_interp_??

New specification:

 > **unload** ?**-interp** _interp_? ?**-package**
   _packageName_? ?**-keeplibrary**? ?**--**?
   _fileName\|\|libref_

I removed the _-nocomplain_ option.  The user should simply **catch** the command if they wish to suppress the types of errors that unload would throw.

I think that C functions should be made available as well for
cross-platform access to the load functionality, but that is not
specified in this TIP.  This would need to account for users that may
configure Tcl with --disable-load \(does anybody need that anymore?\).

# Discussion

Not all platforms may support library loading to a degree required for this TIP functionality.  In that case, an error message will be thrown.

The use of **--** as a option end switch was debated as unnecessary since there is only one fixed argument.  JH likes the use of it for the completeness it gives the use of switches.

The **load** command will determine the use of the new form by checking if more than one argument is given and the first argument starts with a **-**.  This should not affect any existing extensions, as dynamic library filenames beginning with **-** are rare.

Here is a reference to Perl's dynamic library loading functionality:

<http://aspn.activestate.com/ASPN/Perl/Products/ActivePerl/5.8/lib/DynaLoader.html>

# Examples

For a package in a starkit, tls example with shared OpenSSL library
shipped in package:

	 # $dir set by package mechanism
	 if {[package provide starkit] ne ""} {
	     load -call {} $dir/libopenssl.so

	 }
	 load $dir/libtls1.5.so

This would handle the extracting of dependent libraries in starkits automatically \(and their subsequent disposal\).

Another example would be Oratcl 4.3's use of dynamic Oracle library
callouts, which it has to do by hand due to the lack of this
functionality in the core.

# Reference Implementation

[To be uploaded to SourceForge and URL added to this TIP.]

# Copyright

This document has been placed in the public domain.

Name change from tip/24.tip to tip/24.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

TIP:            24
Title:          Tcl Maintainer Assignments
Version:        $Revision: 1.56 $
Author:         Don Porter <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         Kevin B. Kenny <[email protected]>
Author:         Jeff Hobbs <[email protected]>
Author:         Pavel Goran <[email protected]>
Author:         Daniel A. Steffen <[email protected]>
Author:         miguel sofer <[email protected]>
State:          Draft
Type:           Informative
Vote:           Pending
Created:        29-Jan-2001
Post-History:   


~ Abstract

This document keeps a record of who maintains each functional area
of Tcl ([16]).

~ Assignments

Listed below are Tcl's functional units, in the same order as
in [16].  See [16] for the precise definition of what code belongs to
what area.  The area names are changed to match the Categories in Tcl's
SourceForge Bug Manager [http://sourceforge.net/bugs/?group_id=10894].

Note that an area can have more than one maintainer.  When the
maintenance of the entire area requires several types of
expertise, it is desirable to have more than one maintainer.

In several of the areas below, there are maintainers who have
volunteered to provide special expertise (for example, assistance
with programming and testing for the Mac platform) to assist
in maintaining an area, but who have not taken on the whole area.
These maintainers are indicated by a parenthesized designation
of their expertise.

For each of Tcl's functional units, the following maintainers are
assigned:

   1. ''Notifier'' - Kevin Kenny <[email protected]> (Win32, Solaris, HP-UX), Daniel Steffen <[email protected]> (Mac OS X), Alexandre Ferrieux <[email protected]>

   1. ''Event Loops'' - Jan Nijtmans <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Timer Events'' - Kevin Kenny <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Async Events'' - Joe Mistachkin <[email protected]>

   1. ''XT Notifier'' - 

   1. ''Time Measurement'' -  Kevin Kenny <[email protected]>,
 			      Jeff Hobbs <[email protected]>

   1. ''Variables'' - Miguel Sofer <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Environment Variables'' - Jeff Hobbs <[email protected]>

   1. ''Linked C Variables'' - Jeff Hobbs <[email protected]>

   1. ''Objects'' - Miguel Sofer <[email protected]>, Alexandre Ferrieux <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Conversions from String'' - Jeff Hobbs <[email protected]>

   1. ''ByteArray Objects'' - Donal K. Fellows <dkf@users.sf.net>, Jan Nijtmans <[email protected]>, Alexandre Ferrieux <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Index Object'' - Jan Nijtmans <j.n[email protected]>, Jeff Hobbs <[email protected]>

   1. ''List Object'' - Jan Nijtmans <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Dict Object'' - Donal K. Fellows <dkf@users.sf.net>

   1. ''Commands A-H'' - Donal K. Fellows <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Commands I-L'' - Donal K. Fellows <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Commands M-Z'' - Donal K. Fellows <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''[[history]]'' - Jeff Hobbs <[email protected]>

   1. ''[[interp]]'' - Jeff Hobbs <[email protected]>

   1. ''[[namespace]]'' - Miguel Sofer <[email protected]>,





      Jeff Hobbs <[email protected]>,
      Donal K. Fellows <[email protected]> (especially ensembles)

   1. ''[[proc]] and [[uplevel]]'' - Miguel Sofer <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''[[scan]]'' - Jeff Hobbs <[email protected]>

   1. ''Channel Commands'' - Andreas Kupries <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Channel System'' - Andreas Kupries <[email protected]>, Alexandre Ferrieux <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Channel Transforms'' - Andreas Kupries <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Channel Types'' - Andreas Kupries <[email protected]>,
                          Rolf Schroedter <[email protected]> (WinSerial),
			  Jeff Hobbs <[email protected]>

   1. ''dde Package'' - Pat Thoyts <[email protected]>,
                         Kevin Kenny <[email protected]>

   1. ''http Package'' - Pat Thoyts <[email protected]>,
                         Jeff Hobbs <[email protected]>

   1. ''msgcat Package'' - Harald Oehlmann <[email protected]>

   1. ''opt Package'' - Jan Nijtmans <[email protected]>

   1. ''registry Package'' - Kevin Kenny <[email protected]>

   1. ''Safe Base'' - Jeff Hobbs <[email protected]>

   1. ''tcltest Package'' - Jeff Hobbs <[email protected]>,
	Melissa Chawla <[email protected]>,
        Don Porter <[email protected]>

   1. ''TclOO Package'' - Donal K. Fellows <[email protected]>

   1. ''Pathname Management'' -
	Vincent Darley <[email protected]>,
	Jeff Hobbs <[email protected]>

   1. ''File System'' - Vincent Darley <[email protected]>,
			Jeff Hobbs <[email protected]>,
                        Daniel Steffen <[email protected]> (Mac OS X),
                        Jim Ingham <[email protected]> (Mac OS X)

   1. ''Init - Library - Autoload'' -
        Don Porter <[email protected]>,
        Jeff Hobbs <[email protected]>,
        Daniel Steffen <[email protected]> (Mac OS X),
        Jim Ingham <[email protected]> (Mac OS X)

   1. ''Package Manager'' -  Don Porter <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Dynamic Loading'' -  Kevin Kenny <[email protected]>,
                             Jan Nijtmans <[email protected]>,
			     Jeff Hobbs <[email protected]>,
                             Daniel Steffen <[email protected]> (Mac OS X),
                             Jim Ingham <[email protected]> (Mac OS X)

   1. ''Memory Allocation'' - Jeff Hobbs <[email protected]>,
                              Joe Mistachkin <[email protected]>

   1. ''Memory Preservation'' - Jeff Hobbs <[email protected]>

   1. ''Regexp'' - Pavel Goran <[email protected]>,
		Colin McCormack <[email protected]>

   1. ''UTF-8 Strings'' - Jan Nijtmans <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Parsing and Eval'' - Miguel Sofer <[email protected]>, Jeff Hobbs <[email protected]>, Don Porter <[email protected]>

   1. ''Traces'' - Don Porter <[email protected]>

   1. ''Bytecode Compiler'' - Miguel Sofer <[email protected]>, Jeff Hobbs <[email protected]>

   1. ''Number Handling'' - Don Porter <[email protected]>, Kevin Kenny <[email protected]>

   1. ''Threading'' - Andreas Kupries <[email protected]>,
		      Jeff Hobbs <[email protected]>,
                      Joe Mistachkin <[email protected]>

   1. ''Embedding Support'' - Don Porter <[email protected]>,
			      Jeff Hobbs <[email protected]>,
                              Joe Mistachkin <[email protected]>

   1. ''Release Notes'' - Don Porter <[email protected]>,
                          Jeff Hobbs <[email protected]>,
                          Daniel Steffen <[email protected]> (Mac OS X),
                          Jim Ingham <[email protected]> (Mac OS X)

   1. ''Portability Support'' -
        Mo DeJong <[email protected]>,
	Jeff Hobbs <[email protected]>,
	Zoran Vasiljevic <[email protected]>

   1. ''Configure and Build Tools'' - Mo DeJong <[email protected]>,
        Jeff Hobbs <[email protected]>,
	Lloyd Lim <[email protected]>,
	Acacio Cruz <[email protected]> (BSD),
        Daniel Steffen <[email protected]> (Mac OS X),
        Jim Ingham <[email protected]> (Mac OS X),
	Pat Thoyts <[email protected]> (Windows)

   1. ''Configuration Reporting'' - Andreas Kupries <[email protected]>

   1. ''Other Tools'' - Jeff Hobbs <[email protected]>

   1. ''LibTomMath'' - Kevin Kenny <[email protected]>

   1. ''zlib'' - Donal K. Fellows <[email protected]>

~ Orphaned Categories

The following Categories in Tcl's SourceForge Bug Tracker should be
mapped to new Categories corresponding to a maintained area of Tcl,
when seeking the appropriate maintainer:

   67. ''[[resource]] (obsolete)'' - Used for closed old reports about
		the '''resource''' command that was implemented only on
		the now unsupported Mac Classic platform.

   68. ''Mac Classic (obsolete)'' - Used for closed old reports about
		other issues on the now unsupported Mac Classic platform.

   69. ''Other'' - Used for reports that span several categories.  Also
		  includes many closed old reports from before the time
		  the current categories were established.

~ Sections Without Maintainers

Those sections without a maintainer are maintained by the Tcl Core
Team with each change requiring TYANNOTT review.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
|
>

|


|

|


|

|






|
|







|

|

|

|

|

|


|

<
<
|

<
<
|

|

|

|

|

|

|

|

|

|

<
>
>
>
>
>

|

|

|

|

|

|

|
|


|


|


|

|

|

|

|



|

|



|

|
|

|


|
|

|

|


|
|

|


|

|


|

|

|

|

|

|



|



|

|
|

|




|


|
|
|
|

|

|

|

|

|





|
|


|


|



|




|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

# TIP 24: Tcl Maintainer Assignments

	Author:         Don Porter <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         Kevin B. Kenny <[email protected]>
	Author:         Jeff Hobbs <[email protected]>
	Author:         Pavel Goran <[email protected]>
	Author:         Daniel A. Steffen <[email protected]>
	Author:         miguel sofer <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        29-Jan-2001
	Post-History:   
-----

# Abstract

This document keeps a record of who maintains each functional area
of Tcl \([[16]](16.md)\).

# Assignments

Listed below are Tcl's functional units, in the same order as
in [[16]](16.md).  See [[16]](16.md) for the precise definition of what code belongs to
what area.  The area names are changed to match the Categories in Tcl's
SourceForge Bug Manager <http://sourceforge.net/bugs/?group_id=10894> .

Note that an area can have more than one maintainer.  When the
maintenance of the entire area requires several types of
expertise, it is desirable to have more than one maintainer.

In several of the areas below, there are maintainers who have
volunteered to provide special expertise \(for example, assistance
with programming and testing for the Mac platform\) to assist
in maintaining an area, but who have not taken on the whole area.
These maintainers are indicated by a parenthesized designation
of their expertise.

For each of Tcl's functional units, the following maintainers are
assigned:

   1. _Notifier_ - Kevin Kenny <[email protected]> \(Win32, Solaris, HP-UX\), Daniel Steffen <[email protected]> \(Mac OS X\), Alexandre Ferrieux <[email protected]>

   1. _Event Loops_ - Jan Nijtmans <[email protected]>, Jeff Hobbs <[email protected]>

   1. _Timer Events_ - Kevin Kenny <[email protected]>, Jeff Hobbs <[email protected]>

   1. _Async Events_ - Joe Mistachkin <[email protected]>

   1. _XT Notifier_ - 

   1. _Time Measurement_ -  Kevin Kenny <[email protected]>,
 			      Jeff Hobbs <[email protected]>

   1. _Variables_ - Miguel Sofer <[email protected]>, Jeff Hobbs <[email protected]>



   1. _Environment Variables_ - Jeff Hobbs <[email protected]>



   1. _Linked C Variables_ - Jeff Hobbs <[email protected]>

   1. _Objects_ - Miguel Sofer <msofer@users.sf.net>, Alexandre Ferrieux <[email protected]>, Jeff Hobbs <[email protected]>

   1. _Conversions from String_ - Jeff Hobbs <[email protected]>

   1. _ByteArray Objects_ - Donal K. Fellows <[email protected]>, Jan Nijtmans <[email protected]>, Alexandre Ferrieux <[email protected]>, Jeff Hobbs <[email protected]>

   1. _Index Object_ - Jan Nijtmans <j.nijtmans@chello.nl>, Jeff Hobbs <JeffH@ActiveState.com>

   1. _List Object_ - Jan Nijtmans <j.nijtmans@chello.nl>, Jeff Hobbs <[email protected]>

   1. _Dict Object_ - Donal K. Fellows <[email protected]>

   1. _Commands A-H_ - Donal K. Fellows <[email protected]>, Jeff Hobbs <[email protected]>

   1. _Commands I-L_ - Donal K. Fellows <[email protected]>, Jeff Hobbs <[email protected]>

   1. _Commands M-Z_ - Donal K. Fellows <dkf@users.sf.net>, Jeff Hobbs <[email protected]>


   1. _[history]_ - Jeff Hobbs <[email protected]>

   1. _[interp]_ - Jeff Hobbs <[email protected]>

   1. _[namespace]_ - Miguel Sofer <[email protected]>,
      Jeff Hobbs <[email protected]>,
      Donal K. Fellows <[email protected]> \(especially ensembles\)

   1. _[proc] and [uplevel]_ - Miguel Sofer <[email protected]>, Jeff Hobbs <[email protected]>

   1. _[scan]_ - Jeff Hobbs <[email protected]>

   1. _Channel Commands_ - Andreas Kupries <[email protected]>, Jeff Hobbs <[email protected]>

   1. _Channel System_ - Andreas Kupries <[email protected]>, Alexandre Ferrieux <[email protected]>, Jeff Hobbs <[email protected]>

   1. _Channel Transforms_ - Andreas Kupries <[email protected]>, Jeff Hobbs <[email protected]>

   1. _Channel Types_ - Andreas Kupries <[email protected]>,
                          Rolf Schroedter <[email protected]> \(WinSerial\),
			  Jeff Hobbs <[email protected]>

   1. _dde Package_ - Pat Thoyts <[email protected]>,
                         Kevin Kenny <[email protected]>

   1. _http Package_ - Pat Thoyts <[email protected]>,
                         Jeff Hobbs <[email protected]>

   1. _msgcat Package_ - Harald Oehlmann <[email protected]>

   1. _opt Package_ - Jan Nijtmans <[email protected]>

   1. _registry Package_ - Kevin Kenny <[email protected]>

   1. _Safe Base_ - Jeff Hobbs <[email protected]>

   1. _tcltest Package_ - Jeff Hobbs <[email protected]>,
	Melissa Chawla <[email protected]>,
        Don Porter <[email protected]>

   1. _TclOO Package_ - Donal K. Fellows <[email protected]>

   1. _Pathname Management_ -
	Vincent Darley <[email protected]>,
	Jeff Hobbs <[email protected]>

   1. _File System_ - Vincent Darley <[email protected]>,
			Jeff Hobbs <[email protected]>,
                        Daniel Steffen <[email protected]> \(Mac OS X\),
                        Jim Ingham <[email protected]> \(Mac OS X\)

   1. _Init - Library - Autoload_ -
        Don Porter <[email protected]>,
        Jeff Hobbs <[email protected]>,
        Daniel Steffen <[email protected]> \(Mac OS X\),
        Jim Ingham <[email protected]> \(Mac OS X\)

   1. _Package Manager_ -  Don Porter <[email protected]>, Jeff Hobbs <[email protected]>

   1. _Dynamic Loading_ -  Kevin Kenny <[email protected]>,
                             Jan Nijtmans <[email protected]>,
			     Jeff Hobbs <[email protected]>,
                             Daniel Steffen <[email protected]> \(Mac OS X\),
                             Jim Ingham <[email protected]> \(Mac OS X\)

   1. _Memory Allocation_ - Jeff Hobbs <[email protected]>,
                              Joe Mistachkin <[email protected]>

   1. _Memory Preservation_ - Jeff Hobbs <[email protected]>

   1. _Regexp_ - Pavel Goran <[email protected]>,
		Colin McCormack <[email protected]>

   1. _UTF-8 Strings_ - Jan Nijtmans <[email protected]>, Jeff Hobbs <[email protected]>

   1. _Parsing and Eval_ - Miguel Sofer <[email protected]>, Jeff Hobbs <[email protected]>, Don Porter <[email protected]>

   1. _Traces_ - Don Porter <[email protected]>

   1. _Bytecode Compiler_ - Miguel Sofer <[email protected]>, Jeff Hobbs <[email protected]>

   1. _Number Handling_ - Don Porter <[email protected]>, Kevin Kenny <[email protected]>

   1. _Threading_ - Andreas Kupries <[email protected]>,
		      Jeff Hobbs <[email protected]>,
                      Joe Mistachkin <[email protected]>

   1. _Embedding Support_ - Don Porter <[email protected]>,
			      Jeff Hobbs <[email protected]>,
                              Joe Mistachkin <[email protected]>

   1. _Release Notes_ - Don Porter <[email protected]>,
                          Jeff Hobbs <[email protected]>,
                          Daniel Steffen <[email protected]> \(Mac OS X\),
                          Jim Ingham <[email protected]> \(Mac OS X\)

   1. _Portability Support_ -
        Mo DeJong <[email protected]>,
	Jeff Hobbs <[email protected]>,
	Zoran Vasiljevic <[email protected]>

   1. _Configure and Build Tools_ - Mo DeJong <[email protected]>,
        Jeff Hobbs <[email protected]>,
	Lloyd Lim <[email protected]>,
	Acacio Cruz <[email protected]> \(BSD\),
        Daniel Steffen <[email protected]> \(Mac OS X\),
        Jim Ingham <[email protected]> \(Mac OS X\),
	Pat Thoyts <[email protected]> \(Windows\)

   1. _Configuration Reporting_ - Andreas Kupries <[email protected]>

   1. _Other Tools_ - Jeff Hobbs <[email protected]>

   1. _LibTomMath_ - Kevin Kenny <[email protected]>

   1. _zlib_ - Donal K. Fellows <[email protected]>

# Orphaned Categories

The following Categories in Tcl's SourceForge Bug Tracker should be
mapped to new Categories corresponding to a maintained area of Tcl,
when seeking the appropriate maintainer:

   67. _[resource] \(obsolete\)_ - Used for closed old reports about
		the **resource** command that was implemented only on
		the now unsupported Mac Classic platform.

   68. _Mac Classic \(obsolete\)_ - Used for closed old reports about
		other issues on the now unsupported Mac Classic platform.

   69. _Other_ - Used for reports that span several categories.  Also
		  includes many closed old reports from before the time
		  the current categories were established.

# Sections Without Maintainers

Those sections without a maintainer are maintained by the Tcl Core
Team with each change requiring TYANNOTT review.

# Copyright

This document has been placed in the public domain.

Name change from tip/240.tip to tip/240.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
136
137
138


139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

157
158
159
160
161
162
163
164

165
166
167
168
169

170
171
172
173

174
175
176
177
178


179
180

181
182
183
184
185
186
187
188
189
190
191
192


193
194
195
196
197
198
199
200
201
202
203
204
205


206
207
208
209
210
211
212

213
214
215
216

217
218
219
220
221
222

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329

TIP:            240
Title:          An Ensemble Command to Manage Processes
Version:        $Revision: 1.14 $
Author:         Steve Bold <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        22-Feb-2005
Post-History:   
Keywords:       Tcl
Obsoletes:      88
Tcl-Version:    8.7


~ Abstract

This TIP proposes some new commands through which Tcl scripts can create and
monitor child processes.

~ Rationale

This TIP is intended to overcome the following limitations of the existing
'''exec''' and '''open''' commands:

 1. While the stderr stream of a child process can be redirected to a file, it
    cannot be directed to a pipe and so cannot be captured progressively as
    the process runs. [202] has partially addressed this issue but only for
    the case where the child's stderr stream is directed to the same pipe as
    its stdout stream. Independent progressive capture of both stdout and
    stderr is still not possible.

 2. In the (admittedly rare) case that a program has a significant delay
    between closing its standard streams and the process itself terminating, a
    Tcl script running that program as a background process cannot determine
    the exit status without blocking until the process terminates.

 3. The existing '''exec''' and '''open''' commands impose a special
    interpretation on the characters ''<>|&''. This causes two kinds of
    problems:

 > * scripts wishing to invoke a command on a remote computer using an ''rsh''
     or similar command will sometimes wish to have characters such as
     ''<>|&'' interpreted on the remote machine

 > * scripts may pass a user entered string as an argument to exec. Such
     scripts may break unexpectedly if the comment string contains one of the
     special characters. Such problems could be considered a security weakness
     in Tcl.

 4. Multiple child processes can be launched together with pipes used to link
    the streams of adjacent processes. However, little flexibility is provided
    in such cases, for example you can only capture the exit status of the
    last process in the pipeline.

A more general problem is that each process related command is a separate
top-level command. This is inconsistent with much else in Tcl, makes it harder
to find the related commands in some forms of documentation and increases the
risk of name clashes as new process related commands are introduced.

The BLT toolkit contains the command '''bgexec''' which addresses items (1)
and (2) in the above list. However, the resulting implementation is complex
and does not appear easy to transfer to the Tcl core. In addition, it is not
clear to the author how '''bgexec''' could be extended to address items (3)
and (4).

A variety of other approaches to addressing these problems are listed on the
Wiki [http://wiki.tcl.tk/1353]. This suggests that it may be difficult to
achieve a consensus on what the ideal command(s) for launching processes
should look like. This TIP provides a basis through which many of these
approaches could be implemented in pure Tcl. The commands specified in this
TIP map easily onto the existing low level process related functions in the
Tcl core, so the implementation cost is low.

~ Specification

There shall be a new ensemble command, '''process''', with at least four
subcommands.

 1. The sub-command '''invoke''' takes 4 arguments and invokes a sub-process,
    returning the process id of the child process. The arguments are (in
    order):

 > * a list containing the program name invoke and its arguments

 > * a channel to be connected to the stdin stream of the child process (or an
     empty string if the channel is to be disconnected in the child process).

 > * a channel to be connected to the stdout stream of the child process (or
     an empty string if the channel is to be disconnected in the child
     process).

 > * a channel to be connected to the stderr stream of the child process (or
     an empty string if the channel is to be disconnected in the child
     process).

 2. The sub-command '''pipe''' takes no arguments and returns a two element
    list containing the input and output channels of the pipe in that order.

 3. The sub-command '''status''' takes a single argument which is a process id
    and returns a two element list. The first element is either ''running'' or
    ''completed'' The second element is the exit status of the process.

 > A process will report an arbitrary exit status of zero while it is running.

 4. The sub-command '''wait''' is similar to '''status''' but blocks until the
    child process has completed.

~ Examples

The following shows how the commands proposed here can be used to produce a
'''bgexec''' like command in pure Tcl. Not all the '''bgexec''' options are
included and the implementation lacks the error handling needed for a robust
implementation.

|proc bgExecCloseHandler {pid cmd} {
|   lassign [process status $pid] status exitCode
|   if {$status eq "running"} {
|      puts "... deferring close handling for $pid"
|      after 1000 [list bgExecCloseHandler $pid $cmd]
|   } else {
|      if {$cmd ne ""} {
|         {expand}$cmd $pid $exitCode
|      }
|   }
|}



|
|proc bgExecReadHandler {chan cmd} {
|   if {[gets $chan line] == -1} {
|      close $chan
|      
|      if {[info exists ::bgExecCloseInfo($chan)]} {
|         lassign $::bgExecCloseInfo($chan) pid cmd
|         after 0 bgExecCloseHandler $pid $cmd
|         unset ::bgExecCloseInfo($chan)
|      }

|   } else {
|      {expand}$cmd $line
|   }
|}


|
|proc bgExecLike {args} {
|   set outChan ""; set errChan ""
|   set i 0
|   set exitCmd ""; set parentOutChan ""
|   while {$i != [llength $args]} {
|      set arg [lindex $args $i]
|      switch -glob -- $arg {
|      	
|      	-onoutput {
|      	   incr i
|      	   set cmd [lindex $args $i]
|      	   lassign [process pipe] parentChan outChan
|      	   fileevent $parentChan readable [list \
|                  bgExecReadHandler $parentChan $cmd]
|      	   set outCmd $cmd
|      	   set parentOutChan $parentChan
|      	}

|      	
|      	-onerror {
|      	   incr i
|      	   set cmd [lindex $args $i]
|      	   lassign [process pipe] parentChan errChan
|      	   fileevent $parentChan readable [list \
|                  bgExecReadHandler $parentChan $cmd]
|      	}

|      	
|      	-onexit {
|      	   incr i
|      	   set exitCmd [lindex $args $i]
|      	}

|      	
|      	-* {
|      	   error "Unknown switch $arg"
|      	}

|      	
|      	* {
|      	   break
|      	}
|      }


|      incr i
|   }

|   
|   set cmdLine [lrange $args $i end]
|
|   # puts [list process invoke $cmdLine "" $outChan $errChan]
|   set pid [process invoke $cmdLine "" $outChan $errChan]
|
|   # Close the child end of the pipes - if we opened them.
|   foreach var {outChan errChan} {
|      if {[set $var] ne ""} {
|         close [set $var]
|      }
|   }


|   
|   if {$parentOutChan eq ""} {
|      # Poll for child process exit then notify client, or at least
|      # clean up the zombie.
|      after 0 bgExecCloseHandler $pid $exitCmd
|   } else {
|      # We copy BLT's trick of deferring polling till the stdout pipe
|      # closes. This is marginally more efficient, more importantly
|      # it stops clients being notified of their process until at stdout
|      # channel has closed.
|      set ::bgExecCloseInfo($parentOutChan) [list $pid $exitCmd]
|   }   
|}


|
|
|# now show bgExecLike in action ...
|
|proc showExit {pid code} {
|   puts "$pid terminated with code $code"
|}

|
|proc showLine {channel line} {
|   puts "$channel: $line"
|}

|
|proc runLs {args} {
|   puts "invoking ls on $args"
|   bgExecLike -onoutput "showLine stdout" -onerror "showLine stderr" \
|           -onexit showExit ls {expand}$args
|}

|
|# Sample invocations: note when running under tclsh, there is no event loop,
|# use 'update' to see the output to see what's happening.
|
|# successful listing
|runLs .
|
|# Unsuccessful listing
|runLs not-found
|
|# Listing of (non existent) files containing exec/open meta characters
|runLs < > | &

~ Limitations

 1. For convenient use, the functionality proposed here needs to be
    supplemented with additional commands providing a higher level interface,
    perhaps one of them being similar to the '''bgExecLike''' example given
    previously. The author has decided to omit this feature from the TIP
    because:

 > * such commands can be implemented in pure Tcl using the commands described
     here

 > * the exact nature of the high level commands may produce lengthy
     discussions

 > * it could even be argued that such commands are more appropriate in tcllib
     rather than the Tcl core

 2. As with the current implementation of '''exec''', each channel passed to
    '''process invoke''' must have a valid underlying OS file handle.
    Consequently when running on Windows:

 > * use of a wish standard channel will be immediately rejected

 > * use of a socket will be accepted but will trigger an error in the child
     process.

 3. Efficiency - The author has not yet attempted a detailed performance
    study, but this proposal does have some theoretical inefficiencies when
    compared to a pure C implementation, such as '''bgexec''':

 > * an intermediate Tcl procedure is used to capture output from a pipe

 > * each end of each pipe has to be wrapped in a ''CommandChannel'' before it
     can be passed back to the calling script, even if the pipe is just going
     to be used to link together two processes in a pipeline.

~ Related Possibilities for Future Enhancements

 1. For Windows, an important limitation that is not addressed by this TIP, is
    the lack of control over the console window settings when invoking a
    process. This will require changes to ''TclpCreateProcess''.

 2. A '''kill''' subcommand would be a useful addition to the '''process'''
    ensemble. On Windows, the ability to kill a child console process cleanly
    is related to the choice of console mode, so this issue would ideally be
    addressed in conjunction with item (1) above.

 3. A command to categorise an exit status obtained from '''process status'''
    or '''process wait''' along similar lines to the data placed in
    ''$errorCode'' by ''TclCleanupChildren()''.

 4. Some aspects of the existing '''exec''' command depend on use of temporary
    files. Since this TIP transfers the high level implementation of process
    launching into Tcl scripts, support for creation of uniquely named
    temporary files, as proposed in [210], would be useful.

 5. The wish console on Windows could be improved, using this mechanism, so
    that program names typed interactively will run in the background,
    allowing output to be seen before the process completes.

 6. The ability to define ''argv[[0]]'', independently from the program name,
    would occasionally be useful. For example, some UNIX shells run as login
    shells when ''argv[[0]]'' begins with a dash.

 7. Public C functions for invoking a process and creating a pipe wrapped in
    command channels.

 8. Support for detaching process and for reaping detached processes.

 9. The existing '''exit''' command could be duplicated in the '''process'''
    ensemble.

 10. The basic form of the existing '''pid''' command, which obtains the
     process id of the current process, could be added to the '''process'''
     ensemble.

 11. In some cases, it is more appropriate to run a child process with its
     streams connected to a null file rather than disconnected. Since the name
     of the null file is platform specific, it would be helpful to have a
     platform independent way of accessing the name.

 12. An option to obtain full status information. On Windows, process exit
     codes are 32 bit. On UNIX, higher bits of a waitpid() status value
     distinguish termination via exit() from termination via an uncaught
     signal.

~ Reference Implementation

Submitted as patch 1315115
[https://sourceforge.net/support/tracker.php?aid=1315115]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|




|


|



|




|




|
|


|

|

|














|
|

|
|


|
|





|

|


|
|
|

|

|
|

|

|

|

|

|


|
|
|

|

|


|


|



|
|
|
|
|
|
|
|
<
<
<
>
>
>
|
|
|
|
|
|
|
|
|
<
>
|
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
<
>
|
|
|
<
<
>
>
|
<
>
|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|

|



|



|


|


|


|
|


|

|




|

|

|



|



|

|


|

|
|
|

|


|





|

|






|


|
|








|
|


|


|

|


>

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


136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

155
156
157
158
159
160
161
162

163
164
165
166
167

168
169
170
171

172
173
174
175


176
177
178

179
180
181
182
183
184
185
186
187
188
189


190
191
192
193
194
195
196
197
198
199
200
201
202


203
204
205
206
207
208
209
210

211
212
213
214

215
216
217
218
219
220

221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329

# TIP 240: An Ensemble Command to Manage Processes

	Author:         Steve Bold <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        22-Feb-2005
	Post-History:   
	Keywords:       Tcl
	Obsoletes:      88
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes some new commands through which Tcl scripts can create and
monitor child processes.

# Rationale

This TIP is intended to overcome the following limitations of the existing
**exec** and **open** commands:

 1. While the stderr stream of a child process can be redirected to a file, it
    cannot be directed to a pipe and so cannot be captured progressively as
    the process runs. [[202]](202.md) has partially addressed this issue but only for
    the case where the child's stderr stream is directed to the same pipe as
    its stdout stream. Independent progressive capture of both stdout and
    stderr is still not possible.

 2. In the \(admittedly rare\) case that a program has a significant delay
    between closing its standard streams and the process itself terminating, a
    Tcl script running that program as a background process cannot determine
    the exit status without blocking until the process terminates.

 3. The existing **exec** and **open** commands impose a special
    interpretation on the characters _<>\|&_. This causes two kinds of
    problems:

	 > \* scripts wishing to invoke a command on a remote computer using an _rsh_
     or similar command will sometimes wish to have characters such as
     _<>\|&_ interpreted on the remote machine

	 > \* scripts may pass a user entered string as an argument to exec. Such
     scripts may break unexpectedly if the comment string contains one of the
     special characters. Such problems could be considered a security weakness
     in Tcl.

 4. Multiple child processes can be launched together with pipes used to link
    the streams of adjacent processes. However, little flexibility is provided
    in such cases, for example you can only capture the exit status of the
    last process in the pipeline.

A more general problem is that each process related command is a separate
top-level command. This is inconsistent with much else in Tcl, makes it harder
to find the related commands in some forms of documentation and increases the
risk of name clashes as new process related commands are introduced.

The BLT toolkit contains the command **bgexec** which addresses items \(1\)
and \(2\) in the above list. However, the resulting implementation is complex
and does not appear easy to transfer to the Tcl core. In addition, it is not
clear to the author how **bgexec** could be extended to address items \(3\)
and \(4\).

A variety of other approaches to addressing these problems are listed on the
Wiki <http://wiki.tcl.tk/1353> . This suggests that it may be difficult to
achieve a consensus on what the ideal command\(s\) for launching processes
should look like. This TIP provides a basis through which many of these
approaches could be implemented in pure Tcl. The commands specified in this
TIP map easily onto the existing low level process related functions in the
Tcl core, so the implementation cost is low.

# Specification

There shall be a new ensemble command, **process**, with at least four
subcommands.

 1. The sub-command **invoke** takes 4 arguments and invokes a sub-process,
    returning the process id of the child process. The arguments are \(in
    order\):

	 > \* a list containing the program name invoke and its arguments

	 > \* a channel to be connected to the stdin stream of the child process \(or an
     empty string if the channel is to be disconnected in the child process\).

	 > \* a channel to be connected to the stdout stream of the child process \(or
     an empty string if the channel is to be disconnected in the child
     process\).

	 > \* a channel to be connected to the stderr stream of the child process \(or
     an empty string if the channel is to be disconnected in the child
     process\).

 2. The sub-command **pipe** takes no arguments and returns a two element
    list containing the input and output channels of the pipe in that order.

 3. The sub-command **status** takes a single argument which is a process id
    and returns a two element list. The first element is either _running_ or
    _completed_ The second element is the exit status of the process.

	 > A process will report an arbitrary exit status of zero while it is running.

 4. The sub-command **wait** is similar to **status** but blocks until the
    child process has completed.

# Examples

The following shows how the commands proposed here can be used to produce a
**bgexec** like command in pure Tcl. Not all the **bgexec** options are
included and the implementation lacks the error handling needed for a robust
implementation.

	proc bgExecCloseHandler {pid cmd} {
	   lassign [process status $pid] status exitCode
	   if {$status eq "running"} {
	      puts "... deferring close handling for $pid"
	      after 1000 [list bgExecCloseHandler $pid $cmd]
	   } else {
	      if {$cmd ne ""} {
	         {expand}$cmd $pid $exitCode



	      }
	   }
	}
	
	proc bgExecReadHandler {chan cmd} {
	   if {[gets $chan line] == -1} {
	      close $chan
	      
	      if {[info exists ::bgExecCloseInfo($chan)]} {
	         lassign $::bgExecCloseInfo($chan) pid cmd
	         after 0 bgExecCloseHandler $pid $cmd
	         unset ::bgExecCloseInfo($chan)

	      }
	   } else {
	      {expand}$cmd $line


	   }
	}
	
	proc bgExecLike {args} {
	   set outChan ""; set errChan ""
	   set i 0
	   set exitCmd ""; set parentOutChan ""
	   while {$i != [llength $args]} {
	      set arg [lindex $args $i]
	      switch -glob -- $arg {
	      	
	      	-onoutput {
	      	   incr i
	      	   set cmd [lindex $args $i]
	      	   lassign [process pipe] parentChan outChan
	      	   fileevent $parentChan readable [list \
	                  bgExecReadHandler $parentChan $cmd]
	      	   set outCmd $cmd
	      	   set parentOutChan $parentChan

	      	}
	      	
	      	-onerror {
	      	   incr i
	      	   set cmd [lindex $args $i]
	      	   lassign [process pipe] parentChan errChan
	      	   fileevent $parentChan readable [list \
	                  bgExecReadHandler $parentChan $cmd]

	      	}
	      	
	      	-onexit {
	      	   incr i
	      	   set exitCmd [lindex $args $i]

	      	}
	      	
	      	-* {
	      	   error "Unknown switch $arg"

	      	}
	      	
	      	* {
	      	   break


	      	}
	      }
	      incr i

	   }
	   
	   set cmdLine [lrange $args $i end]
	
	   # puts [list process invoke $cmdLine "" $outChan $errChan]
	   set pid [process invoke $cmdLine "" $outChan $errChan]
	
	   # Close the child end of the pipes - if we opened them.
	   foreach var {outChan errChan} {
	      if {[set $var] ne ""} {
	         close [set $var]


	      }
	   }
	   
	   if {$parentOutChan eq ""} {
	      # Poll for child process exit then notify client, or at least
	      # clean up the zombie.
	      after 0 bgExecCloseHandler $pid $exitCmd
	   } else {
	      # We copy BLT's trick of deferring polling till the stdout pipe
	      # closes. This is marginally more efficient, more importantly
	      # it stops clients being notified of their process until at stdout
	      # channel has closed.
	      set ::bgExecCloseInfo($parentOutChan) [list $pid $exitCmd]


	   }   
	}
	
	
	# now show bgExecLike in action ...
	
	proc showExit {pid code} {
	   puts "$pid terminated with code $code"

	}
	
	proc showLine {channel line} {
	   puts "$channel: $line"

	}
	
	proc runLs {args} {
	   puts "invoking ls on $args"
	   bgExecLike -onoutput "showLine stdout" -onerror "showLine stderr" \
	           -onexit showExit ls {expand}$args

	}
	
	# Sample invocations: note when running under tclsh, there is no event loop,
	# use 'update' to see the output to see what's happening.
	
	# successful listing
	runLs .
	
	# Unsuccessful listing
	runLs not-found
	
	# Listing of (non existent) files containing exec/open meta characters
	runLs < > | &

# Limitations

 1. For convenient use, the functionality proposed here needs to be
    supplemented with additional commands providing a higher level interface,
    perhaps one of them being similar to the **bgExecLike** example given
    previously. The author has decided to omit this feature from the TIP
    because:

	 > \* such commands can be implemented in pure Tcl using the commands described
     here

	 > \* the exact nature of the high level commands may produce lengthy
     discussions

	 > \* it could even be argued that such commands are more appropriate in tcllib
     rather than the Tcl core

 2. As with the current implementation of **exec**, each channel passed to
    **process invoke** must have a valid underlying OS file handle.
    Consequently when running on Windows:

	 > \* use of a wish standard channel will be immediately rejected

	 > \* use of a socket will be accepted but will trigger an error in the child
     process.

 3. Efficiency - The author has not yet attempted a detailed performance
    study, but this proposal does have some theoretical inefficiencies when
    compared to a pure C implementation, such as **bgexec**:

	 > \* an intermediate Tcl procedure is used to capture output from a pipe

	 > \* each end of each pipe has to be wrapped in a _CommandChannel_ before it
     can be passed back to the calling script, even if the pipe is just going
     to be used to link together two processes in a pipeline.

# Related Possibilities for Future Enhancements

 1. For Windows, an important limitation that is not addressed by this TIP, is
    the lack of control over the console window settings when invoking a
    process. This will require changes to _TclpCreateProcess_.

 2. A **kill** subcommand would be a useful addition to the **process**
    ensemble. On Windows, the ability to kill a child console process cleanly
    is related to the choice of console mode, so this issue would ideally be
    addressed in conjunction with item \(1\) above.

 3. A command to categorise an exit status obtained from **process status**
    or **process wait** along similar lines to the data placed in
    _$errorCode_ by _TclCleanupChildren\(\)_.

 4. Some aspects of the existing **exec** command depend on use of temporary
    files. Since this TIP transfers the high level implementation of process
    launching into Tcl scripts, support for creation of uniquely named
    temporary files, as proposed in [[210]](210.md), would be useful.

 5. The wish console on Windows could be improved, using this mechanism, so
    that program names typed interactively will run in the background,
    allowing output to be seen before the process completes.

 6. The ability to define _argv[[0]](0.md)_, independently from the program name,
    would occasionally be useful. For example, some UNIX shells run as login
    shells when _argv[[0]](0.md)_ begins with a dash.

 7. Public C functions for invoking a process and creating a pipe wrapped in
    command channels.

 8. Support for detaching process and for reaping detached processes.

 9. The existing **exit** command could be duplicated in the **process**
    ensemble.

 10. The basic form of the existing **pid** command, which obtains the
     process id of the current process, could be added to the **process**
     ensemble.

 11. In some cases, it is more appropriate to run a child process with its
     streams connected to a null file rather than disconnected. Since the name
     of the null file is platform specific, it would be helpful to have a
     platform independent way of accessing the name.

 12. An option to obtain full status information. On Windows, process exit
     codes are 32 bit. On UNIX, higher bits of a waitpid\(\) status value
     distinguish termination via exit\(\) from termination via an uncaught
     signal.

# Reference Implementation

Submitted as patch 1315115
<https://sourceforge.net/support/tracker.php?aid=1315115> 

# Copyright

This document has been placed in the public domain.

Name change from tip/241.tip to tip/241.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

TIP:            241
Title:          Case-Insensitive Switches and List Searching and Sorting
Version:        $Revision: 1.6 $
Author:         Joe Mistachkin <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        26-Feb-2005
Post-History:   
Keywords:       Tcl,sorted lists,matching
Tcl-Version:    8.5


~ Abstract

This TIP proposes a '''-nocase''' option for the '''lsearch''',
'''lsort''' and '''switch''' commands to allow for case-insensitive
handling of the specified list.

~ Rationale

The '''lsearch''', '''lsort''' and '''switch''' commands are very flexible
and powerful. However, in certain situations the ability to perform
case-insensitive searching and sorting is absolutely required (such as
searching fully qualified file names on file systems that do not
differentiate between upper and lower case). Without the '''-nocase'''
option, various unnatural workarounds are required. In addition, the
'''-nocase''' option will finally bring the '''lsearch''' command into
parity with the other comparison related operations, including
'''string compare''', '''string match''', and '''regexp'''.

~ Specification

Options will be added like this:

 > '''lsearch''' ?'''-nocase'''? ''list'' ''pattern''

 > '''lsort''' ?'''-nocase'''? ''list''

 > '''switch''' ?'''-nocase'''? ''string bodyDefinition''

For '''lsearch''', the '''-nocase''' option can be used with the
'''-ascii''', '''-exact''', '''-glob''', and '''-regexp''' options. It
indicates that the string of the found entry of ''list'' should match
''pattern'' case-insensitively. It is compatible with the '''-all''',
'''-decreasing''', '''-increasing''', '''-inline''', '''-not''' and
'''-start''' options.

For '''lsort''', the '''-nocase''' option can be used with the
'''-ascii''' option. It indicates that the list should be sorted based
on a case-insensitive ordering. It is compatible with the
'''-decreasing''', '''-increasing''', '''-index''' and '''-unique'''
options.

For both '''lsearch''' and '''lsort''', the '''-nocase''' option has
no effect when used with the '''-dictionary''', '''-integer''', or
'''-real''' options. For '''lsort''', the '''-nocase''' option has no
effect when used with the '''-command''' option.

For '''switch''', the '''-nocase''' option can be used with all three
matching modes ('''-exact''', '''-glob''', '''-regexp''') and
indicates that the matching of ''string'' should be performed in a
case-insensitive manner.

~ Reference Implementation

A reference implementation of this TIP is available
[http://sourceforge.net/tracker/index.php?func=detail&aid=1152746&group_id=10894&atid=310894].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|


|

|

|

|

|

|

|



|

|

|

|
|
|
|
|
|

|
|

|


|
|
|
|

|
|
|


|


|

|


>

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

# TIP 241: Case-Insensitive Switches and List Searching and Sorting

	Author:         Joe Mistachkin <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        26-Feb-2005
	Post-History:   
	Keywords:       Tcl,sorted lists,matching
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes a **-nocase** option for the **lsearch**,
**lsort** and **switch** commands to allow for case-insensitive
handling of the specified list.

# Rationale

The **lsearch**, **lsort** and **switch** commands are very flexible
and powerful. However, in certain situations the ability to perform
case-insensitive searching and sorting is absolutely required \(such as
searching fully qualified file names on file systems that do not
differentiate between upper and lower case\). Without the **-nocase**
option, various unnatural workarounds are required. In addition, the
**-nocase** option will finally bring the **lsearch** command into
parity with the other comparison related operations, including
**string compare**, **string match**, and **regexp**.

# Specification

Options will be added like this:

 > **lsearch** ?**-nocase**? _list_ _pattern_

 > **lsort** ?**-nocase**? _list_

 > **switch** ?**-nocase**? _string bodyDefinition_

For **lsearch**, the **-nocase** option can be used with the
**-ascii**, **-exact**, **-glob**, and **-regexp** options. It
indicates that the string of the found entry of _list_ should match
_pattern_ case-insensitively. It is compatible with the **-all**,
**-decreasing**, **-increasing**, **-inline**, **-not** and
**-start** options.

For **lsort**, the **-nocase** option can be used with the
**-ascii** option. It indicates that the list should be sorted based
on a case-insensitive ordering. It is compatible with the
**-decreasing**, **-increasing**, **-index** and **-unique**
options.

For both **lsearch** and **lsort**, the **-nocase** option has
no effect when used with the **-dictionary**, **-integer**, or
**-real** options. For **lsort**, the **-nocase** option has no
effect when used with the **-command** option.

For **switch**, the **-nocase** option can be used with all three
matching modes \(**-exact**, **-glob**, **-regexp**\) and
indicates that the matching of _string_ should be performed in a
case-insensitive manner.

# Reference Implementation

A reference implementation of this TIP is available
<http://sourceforge.net/tracker/index.php?func=detail&aid=1152746&group_id=10894&atid=310894> .

# Copyright

This document has been placed in the public domain.

Name change from tip/242.tip to tip/242.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

TIP:            242
Title:          Preselect Filter on tk_get*File Dialogs
Version:        $Revision: 1.8 $
Author:         Brian Griffin <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        03-Mar-2005
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes adding an '''-typevariable''' option to the
'''tk_getOpenFile''' and '''tk_getSaveFile''' dialog box
commands. This option will preselect the filter from the
'''-filetypes''' list based on the type name.

~ Rationale

The standard Open and Save dialog boxes currently allow you to seed
the initial directory and the initial file. The path returned by the call can be saved and used to seed future calls to these dialgo boxes. However, the selected filter cannot be choosen nor read, nor is examining the returned file path sufficient to guess at the filter setting.  

One common aspect of good U/I design is remembering prior selections so the user does not have to repeat actions each time a dialog is used. The initial directory and initial file options provide partially for this ability in the File dialog boxes, but the selected filter type is not controllable. 

The filter selection can also be used for format selection when the file extension is insufficient or not present as is typical in the Mac OS X environment. One example might be a file with the extension .xml, where the file contents may be data, schema, or a dtd. By selecting "XML Schema", over "XML DTD", the user can control the formatting of the .xml file.

By giving the application access to the filter selection, the UI can be made friendlier to the user.

~ Proposed Change

Since the requirement is to be able to set and read the filter selection, the proposal is to use a variable to control and access this feature of the dialog boxes. This is done by adding a 
'''-typevariable''' option to '''tk_getOpenFile''' and '''tk_getSaveFile'''. 

The variable specified is read once at the begining to select the appropriate filter. If the variable does not exist, or it's value does not match any filter typename, or is empty ({}), the dialog box will revert to the default behavior of selecting the first filter in the list.

When the dialog box is closed by using the Ok button, the variable is set to the typename value of the currently selected filter. The variable will not be updated while the dialog box is open and the user makes various selections. If the dialog box is closed using the Cancel button, the variable is not changed.

Example:

|    set types {
|        {{Text Files}       {.txt}        }
|        {{TCL Scripts}      {.tcl}        }
|        {{C Source Files}   {.c}      TEXT}
|        {{GIF Files}        {.gif}        }
|        {{GIF Files}        {}        GIFF}
|        {{All Files}        *             }
|    }

|    set type {C Source Files}
|    tk_getOpenFile -filetypes $types -typevariable type
|    set type
| => {TCL Scripts}

To preselect .c files for the filter, set type {C Source Files}. 
If the filter is changed to {TCL Scripts}, for example, the variable 
"type" is modified to the value {TCL Scripts}.

~ Reference Implementation

A reference implementation will be posted to Tk patches[http://sf.net/tracker/?func=detail&aid=1156388&group_id=12997&atid=312997]. I have
modified ''tkfbox.tcl'' and ''tkWinDialog.c''. I have not looked at
MacOSX yet.

~ Acknowledgement

Thanks to Michael Kirkham and Donal Fellows for their valuable suggestions.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|

|

|










|


|

|





|
|
|
|
|
|
|
<
>
|
|
|
|

|
|
|

|

|
|


|



|


>

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

# TIP 242: Preselect Filter on tk_get*File Dialogs

	Author:         Brian Griffin <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        03-Mar-2005
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes adding an **-typevariable** option to the
**tk\_getOpenFile** and **tk\_getSaveFile** dialog box
commands. This option will preselect the filter from the
**-filetypes** list based on the type name.

# Rationale

The standard Open and Save dialog boxes currently allow you to seed
the initial directory and the initial file. The path returned by the call can be saved and used to seed future calls to these dialgo boxes. However, the selected filter cannot be choosen nor read, nor is examining the returned file path sufficient to guess at the filter setting.  

One common aspect of good U/I design is remembering prior selections so the user does not have to repeat actions each time a dialog is used. The initial directory and initial file options provide partially for this ability in the File dialog boxes, but the selected filter type is not controllable. 

The filter selection can also be used for format selection when the file extension is insufficient or not present as is typical in the Mac OS X environment. One example might be a file with the extension .xml, where the file contents may be data, schema, or a dtd. By selecting "XML Schema", over "XML DTD", the user can control the formatting of the .xml file.

By giving the application access to the filter selection, the UI can be made friendlier to the user.

# Proposed Change

Since the requirement is to be able to set and read the filter selection, the proposal is to use a variable to control and access this feature of the dialog boxes. This is done by adding a 
**-typevariable** option to **tk\_getOpenFile** and **tk\_getSaveFile**. 

The variable specified is read once at the begining to select the appropriate filter. If the variable does not exist, or it's value does not match any filter typename, or is empty \(\{\}\), the dialog box will revert to the default behavior of selecting the first filter in the list.

When the dialog box is closed by using the Ok button, the variable is set to the typename value of the currently selected filter. The variable will not be updated while the dialog box is open and the user makes various selections. If the dialog box is closed using the Cancel button, the variable is not changed.

Example:

	    set types {
	        {{Text Files}       {.txt}        }
	        {{TCL Scripts}      {.tcl}        }
	        {{C Source Files}   {.c}      TEXT}
	        {{GIF Files}        {.gif}        }
	        {{GIF Files}        {}        GIFF}
	        {{All Files}        *             }

	    }
	    set type {C Source Files}
	    tk_getOpenFile -filetypes $types -typevariable type
	    set type
	 => {TCL Scripts}

To preselect .c files for the filter, set type \{C Source Files\}. 
If the filter is changed to \{TCL Scripts\}, for example, the variable 
"type" is modified to the value \{TCL Scripts\}.

# Reference Implementation

A reference implementation will be posted to Tk patches<http://sf.net/tracker/?func=detail&aid=1156388&group_id=12997&atid=312997> . I have
modified _tkfbox.tcl_ and _tkWinDialog.c_. I have not looked at
MacOSX yet.

# Acknowledgement

Thanks to Michael Kirkham and Donal Fellows for their valuable suggestions.

# Copyright

This document has been placed in the public domain.

Name change from tip/243.tip to tip/243.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

TIP:		243
Title:		Supply Find Dialog for the Text Widget
Version:	$Revision: 1.3 $
Author:		R�diger H�rtel <[email protected]>
State:		Draft
Type:		Project
Vote:		Pending
Created:	16-Mar-2005
Tcl-Version:	8.7
Post-History:	
Keywords:	Tk


~Abstract

This TIP adds a ''find dialog'' to the Tk '''text''' widget.

~Rationale

In using the '''text''' widget it often is a desire to search the
input, and the text widget itself provides already all means to search
text. However, until now there is no GUI based support, so each
application developer needing it has to reinvent much of this
particular wheel. Tk should provide a scripted find dialog in its
library scripts so that simple applications can be built more easily
and to a higher quality. Additionally, a ''replace dialog'' is
desirable, and it should be developed at the same time.

~Reference Implementation

A reference implementation for a ''find dialog'' is available at
[http://sf.net/tracker/?func=detail&aid=1167420&group_id=12997&atid=312997].

~Example Use

| package require Tk
| namespace import ::msgcat::*
| 
| mclocale en
| ::msgcat::mcset	en	LblSearchString		"Search String"
| ::msgcat::mcset	en	LblDirection		"Direction"
| ::msgcat::mcset	en	ChkBtnFindCaseOpt	"Case"
| ::msgcat::mcset	en	ChkBtnFindRegexpOpt	"Regexp"
| ::msgcat::mcset	en	RdoBtnFindDirOpt1	"Forward"
| ::msgcat::mcset	en	RdoBtnFindDirOpt2	"Backward"
| ::msgcat::mcset	en	BtnFind			"  Find  "
| ::msgcat::mcset	en	BtnFindNext		"  Next  "
| ::msgcat::mcset	en	BtnClose		"  Close  "
| 
| set b1 .button
| set t1 .t1
| 
| button $b1 -text Find -command [list \
|        tk_textFind $t1 -searchstring hallo -highlightcolor green \
|        -title "Find Dialog"]
| text $t1
| 
| grid $b1 -row 0 -column 1
| grid $t1 -row 1 -column 0 -columnspan 2
| 
| set fd [open [file join . tk_find.tcl] r]
| set content [read $fd]
| close $fd
| 
| $t1 insert 0.0 $content
| set content ""

~Copyright

This document is in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|

|

|





|


|

|
|

|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|


>

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

# TIP 243: Supply Find Dialog for the Text Widget

	Author:		Rüdiger Härtel <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		Pending
	Created:	16-Mar-2005
	Tcl-Version:	8.7
	Post-History:	
	Keywords:	Tk
-----

# Abstract

This TIP adds a _find dialog_ to the Tk **text** widget.

# Rationale

In using the **text** widget it often is a desire to search the
input, and the text widget itself provides already all means to search
text. However, until now there is no GUI based support, so each
application developer needing it has to reinvent much of this
particular wheel. Tk should provide a scripted find dialog in its
library scripts so that simple applications can be built more easily
and to a higher quality. Additionally, a _replace dialog_ is
desirable, and it should be developed at the same time.

# Reference Implementation

A reference implementation for a _find dialog_ is available at
<http://sf.net/tracker/?func=detail&aid=1167420&group_id=12997&atid=312997> .

# Example Use

	 package require Tk
	 namespace import ::msgcat::*
	 
	 mclocale en
	 ::msgcat::mcset	en	LblSearchString		"Search String"
	 ::msgcat::mcset	en	LblDirection		"Direction"
	 ::msgcat::mcset	en	ChkBtnFindCaseOpt	"Case"
	 ::msgcat::mcset	en	ChkBtnFindRegexpOpt	"Regexp"
	 ::msgcat::mcset	en	RdoBtnFindDirOpt1	"Forward"
	 ::msgcat::mcset	en	RdoBtnFindDirOpt2	"Backward"
	 ::msgcat::mcset	en	BtnFind			"  Find  "
	 ::msgcat::mcset	en	BtnFindNext		"  Next  "
	 ::msgcat::mcset	en	BtnClose		"  Close  "
	 
	 set b1 .button
	 set t1 .t1
	 
	 button $b1 -text Find -command [list \
	        tk_textFind $t1 -searchstring hallo -highlightcolor green \
	        -title "Find Dialog"]
	 text $t1
	 
	 grid $b1 -row 0 -column 1
	 grid $t1 -row 1 -column 0 -columnspan 2
	 
	 set fd [open [file join . tk_find.tcl] r]
	 set content [read $fd]
	 close $fd
	 
	 $t1 insert 0.0 $content
	 set content ""

# Copyright

This document is in the public domain.

Name change from tip/244.tip to tip/244.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

TIP:            244
Title:          PNG Photo Image Support for Tk
Version:        $Revision: 1.7 $
Author:         Michael Kirkham <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        22-Mar-2005
Post-History:   
Discussions-To: news:comp.lang.tcl
Tcl-Version:    8.6


~ Abstract

Tk's photo image type has had support for alpha channels internally since
version 8.3. However, to date there is no photo format in the core that
exposes this functionality. This TIP proposes adding support for the PNG
(Portable Network Graphics) format.

~ Rationale

There is a current push for "beautifying" Tcl/Tk with more modern appearing
widgets and default configuration options. One method that can provide
significant improvement in appearance is the use of images with alpha channels
for antialiasing and smooth blending into the background of the GUI. While the
Tk core supports alpha channels, this support is neither exposed through the
Tk_GetColor() format used by '''image put''' and similar interfaces, nor by
the only photo image format, GIF, which allows only fully-opaque or
fully-transparent pixels. Instead, a third party package is currently required
to add a format supporting alpha channels, which may not have a suitable
license or increase the number of external dependencies unreasonably.

The PNG image format is an open standard supporting a wide range of colors,
from 1 bit per pixel black and white to 16 bit per pixel RGBA, with loss-less
compression. It's becoming increasingly widely used as the image format of
choice in many areas including GUI and web page design for its color range,
alpha support and small image size. As such it is the obvious choice for
adding alpha support to Tk. An implementation can be light-weight and not add
any new dependencies (such as on libpng) to Tk: while the format also depends
on the zlib format for compression, [234] proposes zlib support for the Tcl
core.

~ Specification

The implementation shall use the ''Tk_CreatePhotoImageFormat()'' mechanisms to
supply handlers to Tk for PNG support. The implementation must:

   1. Support the full range of color types and bit depths allowed and
      required by the PNG standard, including alpha channels and boolean
      transparency.

   2. Support reading of interlaced images.

   3. Support base64 encoded data through '''image create photo -data'''.

   4. Otherwise conform to the requirements of the PNG specification, such as
      the handling of unsupported ancillary and critical chunks and support
      for all required filter types.

In addition, the implementation should:

   5. Support exporting to the PNG format through '''image data''' and
      '''image write'''.

   6. Allow modification of the overall alpha transparency of imported images
      through '''-format "png -alpha value"'''.

   7. Allow application of display gamma (if known) in conjunction with the
      "gAMA" chunk of imported images, if present, through '''-format "png
      -gamma value"'''.

~ Reference Implementation

A reference implementation is available
[http://www.muonics.com/FreeStuff/TkPNG/]. This reference implementation has
been done as a loadable extension, but requires only the file ''tkImgPNG.c''
and the ''Tk_CreatePhototoImageFormat()'' invocation from ''tkImgPNGInit.c''
to be added to ''CreateTopLevelWindow()'' in ''tkWindow.c'' to be built into
the core.

The only new dependency for this implementation is on zlib. It currently meets
requirements 1 - 6; it does not implement 7.

~~ Notes

   1. It is understood that there will likely be some reformatting required to
      conform to the Tcl Style Guide if this TIP is accepted.

   2. Performance is currently comparable to Img for small (i.e., toolbar
      button) sized images - a little faster or slower depending on the image.
      It seems to be somewhat slower for larger images, but there may be room
      for additional optimizations.

   3. At this time there is a bug (1155596) in Tk Aqua bevel buttons that will
      crash Tk if images with partially transparent pixels are used. This is
      not the fault of the extension, but occurs also with Img. The author is
      attempting to find a fix, however.

   4. The implementation has been tested with PngSuite, which is fairly
      exhaustive, but more tests would probably be useful.

~ Copyright

This document has been placed in the public domain.

~ References

 * PngSuite
   [http://www.schaik.com/pngsuite/pngsuite.html]

 * Portable Network Graphics (PNG) Specification and Extensions
   [http://www.libpng.org/pub/png/spec/]

 * zlib Compression Library
   [http://www.gzip.org/zlib/]

 * zlib Specifications
   [http://www.gzip.org/zlib/zlib_docs.html]

<
|
<
|
|
|
|
|
|
|
|
>

|




|

|






|











|
|


|

|








|







|
|


|

|
|
|

|


|
|
|
|





|




|
|



|







|



|


|

|
|


|


|
>

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

# TIP 244: PNG Photo Image Support for Tk

	Author:         Michael Kirkham <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        22-Mar-2005
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Tcl-Version:    8.6
-----

# Abstract

Tk's photo image type has had support for alpha channels internally since
version 8.3. However, to date there is no photo format in the core that
exposes this functionality. This TIP proposes adding support for the PNG
\(Portable Network Graphics\) format.

# Rationale

There is a current push for "beautifying" Tcl/Tk with more modern appearing
widgets and default configuration options. One method that can provide
significant improvement in appearance is the use of images with alpha channels
for antialiasing and smooth blending into the background of the GUI. While the
Tk core supports alpha channels, this support is neither exposed through the
Tk\_GetColor\(\) format used by **image put** and similar interfaces, nor by
the only photo image format, GIF, which allows only fully-opaque or
fully-transparent pixels. Instead, a third party package is currently required
to add a format supporting alpha channels, which may not have a suitable
license or increase the number of external dependencies unreasonably.

The PNG image format is an open standard supporting a wide range of colors,
from 1 bit per pixel black and white to 16 bit per pixel RGBA, with loss-less
compression. It's becoming increasingly widely used as the image format of
choice in many areas including GUI and web page design for its color range,
alpha support and small image size. As such it is the obvious choice for
adding alpha support to Tk. An implementation can be light-weight and not add
any new dependencies \(such as on libpng\) to Tk: while the format also depends
on the zlib format for compression, [[234]](234.md) proposes zlib support for the Tcl
core.

# Specification

The implementation shall use the _Tk\_CreatePhotoImageFormat\(\)_ mechanisms to
supply handlers to Tk for PNG support. The implementation must:

   1. Support the full range of color types and bit depths allowed and
      required by the PNG standard, including alpha channels and boolean
      transparency.

   2. Support reading of interlaced images.

   3. Support base64 encoded data through **image create photo -data**.

   4. Otherwise conform to the requirements of the PNG specification, such as
      the handling of unsupported ancillary and critical chunks and support
      for all required filter types.

In addition, the implementation should:

   5. Support exporting to the PNG format through **image data** and
      **image write**.

   6. Allow modification of the overall alpha transparency of imported images
      through **-format "png -alpha value"**.

   7. Allow application of display gamma \(if known\) in conjunction with the
      "gAMA" chunk of imported images, if present, through **-format "png
      -gamma value"**.

# Reference Implementation

A reference implementation is available
<http://www.muonics.com/FreeStuff/TkPNG/> . This reference implementation has
been done as a loadable extension, but requires only the file _tkImgPNG.c_
and the _Tk\_CreatePhototoImageFormat\(\)_ invocation from _tkImgPNGInit.c_
to be added to _CreateTopLevelWindow\(\)_ in _tkWindow.c_ to be built into
the core.

The only new dependency for this implementation is on zlib. It currently meets
requirements 1 - 6; it does not implement 7.

## Notes

   1. It is understood that there will likely be some reformatting required to
      conform to the Tcl Style Guide if this TIP is accepted.

   2. Performance is currently comparable to Img for small \(i.e., toolbar
      button\) sized images - a little faster or slower depending on the image.
      It seems to be somewhat slower for larger images, but there may be room
      for additional optimizations.

   3. At this time there is a bug \(1155596\) in Tk Aqua bevel buttons that will
      crash Tk if images with partially transparent pixels are used. This is
      not the fault of the extension, but occurs also with Img. The author is
      attempting to find a fix, however.

   4. The implementation has been tested with PngSuite, which is fairly
      exhaustive, but more tests would probably be useful.

# Copyright

This document has been placed in the public domain.

# References

 * PngSuite
   <http://www.schaik.com/pngsuite/pngsuite.html> 

 * Portable Network Graphics \(PNG\) Specification and Extensions
   <http://www.libpng.org/pub/png/spec/> 

 * zlib Compression Library
   <http://www.gzip.org/zlib/> 

 * zlib Specifications
   <http://www.gzip.org/zlib/zlib_docs.html> 

Name change from tip/245.tip to tip/245.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

TIP:            245
Title:          Discover User Inactivity Time
Version:        $Revision: 1.12 $
Author:         Pascal Scheffers <[email protected]>
Author:         Reinhard Max <[email protected]>
Author:         Neil Madden <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        15-Apr-2005
Post-History:   
Keywords:       Tk
Tcl-Version:    8.5


~ Abstract

This TIP proposes a new subcommand, '''inactive''', to the '''tk'''
command, as well as '''Tk_GetUserInactiveTime''' and '''Tk_ResetUserInactiveTime''' C functions to discover
the number of milliseconds the user has been inactive and reset that timer to zero respectively. For most environments, this is the time since the user last used the keyboard
or mouse.

~ Rationale

User inactivity is used by screen-savers, chat applications and for
security conscious applications to quit or lock themselves after some
inactive time has elapsed. It would make it easier for authors of
these kinds of applications to use Tk if there was a simple way to get
the length of time which the user has been inactive, which is
information available on all supported platforms.

Applications that take some kind of user input from channels that bypass the system's mechanisms for detecting user activity might want to tell the system to reset the inactivity timer because they received input that has to be treated as user activity. An example for this would be barcode readers connected via serial lines that are read directly by the application.

~ Specification

~~ Tcl API

A single new subcommand will be added to '''tk''',
'''inactive'''. This command takes an optional argument
?'''-displayof''' ''window''?. It returns a positive integer, the
number of milliseconds since the last time the user interacted with
the system. If the -displayof option is given then the return value
refers to the display of ''window''; otherwise it refers to the
display of the application's main window.

If querying the user inactive time is not supported by the system,
'''tk inactive''' will return -1.

If the literal string '''reset''' is given as an additional argument, the timer is reset and an empty string is returned.

 > '''tk''' '''inactive''' ?'''-displayof''' ''window''? ?'''reset'''?

~~ C API

long '''Tk_GetUserInactiveTime'''(''display'')

 Display *display (in): used to determine which display to query for
    user inactive time.

'''Tk_GetUserInactiveTime()''' returns a positive integer, the number of
milliseconds since the last time the user interacted with the system
(note that this is not necessarily the time since the user interacted
with the application.)

void '''Tk_ResetUserInactiveTime'''(''display'')

 Display *display (in): used to determine on which display the user inactivity timer is to be reset.

~ Safe Interpreters

User inactive time can be used for timing attacks and will not be made
available in safe interpreters, '''tk inactive''' will return -1 in
safe interpreters. Calling '''tk inactive reset''' in a safe interpreter will throw an error.

~ Implementation Notes

Windows 2000 and later have ''GetLastInputInfo'' to obtain the
information, earlier platforms do not have this symbol in user32.dll.
This symbol will be dynamically obtained upon the first call of
''Tk_UserInactiveTime()'' on windows. If the symbol is not available,
''Tk_UserInactiveTime()'' will return -1. ''GetLastInputInfo()'' has no
notion of displays, and as a result the display argument is
ignored. The behaviour of the command is unknown for terminal
services, remote desktop, VNC, Citrix and other remote screen systems.

For X, this patch introduces two additional library dependencies -
libXext and libXss. The authors do not know if a similar situation to
Windows could exist on the X Window System, where the build host has
libXss, and yet not all installations for that platform have libXss. A
proper solution for that scenario would require an additional TIP to
export TclLoadFile, Tcl_FSLoadFile is not sufficient, to resolve the
symbols at runtime. (The other library, libXext, is virtually
universally available.)

For Win9x, Microsoft has published example code at [http://www.microsoft.com/msj/0200/c/c0200.aspx].

~ Reference Implementation

A reference implementation is available as Patch #1185731 on
SourceForge[http://sf.net/support/tracker.php?aid=1185731].

~ Comments

[[ Insert here please ]]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|
|



|










|

|

|
|
|


|



|

|

|

|

|

|


|

|
|

|

|

|


|
|

|

|


|
|









|
|
|

|

|

|
|

|

|

|


>

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

# TIP 245: Discover User Inactivity Time

	Author:         Pascal Scheffers <[email protected]>
	Author:         Reinhard Max <[email protected]>
	Author:         Neil Madden <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        15-Apr-2005
	Post-History:   
	Keywords:       Tk
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes a new subcommand, **inactive**, to the **tk**
command, as well as **Tk\_GetUserInactiveTime** and **Tk\_ResetUserInactiveTime** C functions to discover
the number of milliseconds the user has been inactive and reset that timer to zero respectively. For most environments, this is the time since the user last used the keyboard
or mouse.

# Rationale

User inactivity is used by screen-savers, chat applications and for
security conscious applications to quit or lock themselves after some
inactive time has elapsed. It would make it easier for authors of
these kinds of applications to use Tk if there was a simple way to get
the length of time which the user has been inactive, which is
information available on all supported platforms.

Applications that take some kind of user input from channels that bypass the system's mechanisms for detecting user activity might want to tell the system to reset the inactivity timer because they received input that has to be treated as user activity. An example for this would be barcode readers connected via serial lines that are read directly by the application.

# Specification

## Tcl API

A single new subcommand will be added to **tk**,
**inactive**. This command takes an optional argument
?**-displayof** _window_?. It returns a positive integer, the
number of milliseconds since the last time the user interacted with
the system. If the -displayof option is given then the return value
refers to the display of _window_; otherwise it refers to the
display of the application's main window.

If querying the user inactive time is not supported by the system,
**tk inactive** will return -1.

If the literal string **reset** is given as an additional argument, the timer is reset and an empty string is returned.

 > **tk** **inactive** ?**-displayof** _window_? ?**reset**?

## C API

long **Tk\_GetUserInactiveTime**\(_display_\)

 Display \*display \(in\): used to determine which display to query for
    user inactive time.

**Tk\_GetUserInactiveTime\(\)** returns a positive integer, the number of
milliseconds since the last time the user interacted with the system
\(note that this is not necessarily the time since the user interacted
with the application.\)

void **Tk\_ResetUserInactiveTime**\(_display_\)

 Display \*display \(in\): used to determine on which display the user inactivity timer is to be reset.

# Safe Interpreters

User inactive time can be used for timing attacks and will not be made
available in safe interpreters, **tk inactive** will return -1 in
safe interpreters. Calling **tk inactive reset** in a safe interpreter will throw an error.

# Implementation Notes

Windows 2000 and later have _GetLastInputInfo_ to obtain the
information, earlier platforms do not have this symbol in user32.dll.
This symbol will be dynamically obtained upon the first call of
_Tk\_UserInactiveTime\(\)_ on windows. If the symbol is not available,
_Tk\_UserInactiveTime\(\)_ will return -1. _GetLastInputInfo\(\)_ has no
notion of displays, and as a result the display argument is
ignored. The behaviour of the command is unknown for terminal
services, remote desktop, VNC, Citrix and other remote screen systems.

For X, this patch introduces two additional library dependencies -
libXext and libXss. The authors do not know if a similar situation to
Windows could exist on the X Window System, where the build host has
libXss, and yet not all installations for that platform have libXss. A
proper solution for that scenario would require an additional TIP to
export TclLoadFile, Tcl\_FSLoadFile is not sufficient, to resolve the
symbols at runtime. \(The other library, libXext, is virtually
universally available.\)

For Win9x, Microsoft has published example code at <http://www.microsoft.com/msj/0200/c/c0200.aspx> .

# Reference Implementation

A reference implementation is available as Patch \#1185731 on
SourceForge<http://sf.net/support/tracker.php?aid=1185731> .

# Comments

[ Insert here please ]

# Copyright

This document has been placed in the public domain.

Name change from tip/246.tip to tip/246.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
136
137

TIP:            246
Title:          Unify Pattern Matching
Version:        $Revision: 1.5 $
Author:         Reinhard Max <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        27-Apr-2005
Post-History:   
Keywords:       pattern,match,glob,exact,regexp,case sensitive,Tcl
Tcl-Version:    8.7


~ Abstract

Many Tcl commands take arguments that are patterns to match
against. Some of these commands allow options to specify whether the
pattern should be treated as a literal, a glob pattern, or a regular
expression, and whether or not matching should be case sensitive.
This TIP proposes a unique set of options for all commands that accept
pattern arguments.

~ Rationale

It is hard to memorize which of the commands that take a pattern
argument allows to modify the matching mode, and in which way. With
this TIP in place pattern matching will be orthogonal throughout Tcl,
so the rules learned once can be applied to every command that uses
pattern matching.

~ Current situation

The following commands currently take pattern arguments with varying
combinations of switches to specify their behaviour:

   * '''array get''' ''arrayName'' ?''pattern''?

   * '''array names''' ''arrayName'' ?''mode''? ?''pattern''?

   * '''array values''' ''arrayName'' ?''pattern''?

   * '''array unset''' ''arrayName'' ?''pattern''?

   * '''dict filter''' ''dictionaryValue'' '''key''' ''globPattern''

   * '''dict filter''' ''dictionaryValue'' '''value''' ''globPattern''

   * '''dict keys''' ''dictionaryValue'' ?''globPattern''?

   * '''dict values''' ''dictionaryValue'' ?''globPattern''?

   * '''lsearch''' ?''options...''? ''list pattern''

   * '''parray''' ''arrayName'' ?''pattern''?

   * '''string match''' ?'''-nocase'''? ''pattern string''

   * '''switch''' ?''options...''? ''string pattern body''

   * '''namespace children''' ?''namespace''? ?''pattern''?

   * '''namespace export''' ?'''-clear'''? ?''pattern pattern ...''?

   * '''namespace forget''' ?''pattern pattern ...''?

   * '''namespace import''' ?'''-force'''? ?''pattern pattern ...''?

   * '''info commands''' ?''pattern''?

   * '''info functions''' ?''pattern''?

   * '''info globals''' ?''pattern''?

   * '''info locals''' ?''pattern''?

   * '''info procs''' ?''pattern''?

   * '''info vars''' ?''pattern''?

   * '''registry keys''' ''keyName'' ?''pattern''?

   * '''registry values''' ''keyName'' ?''pattern''?

The following commands which also take pattern arguments are outside
the scope of this TIP:

   * Commands that match patterns against file names: '''auto_import''',
     '''auto_mkindex''', '''pkg_mkIndex''', '''tcltest'''.

   * Commands that use regular expressions by design: '''regexp''',
     and '''regsub'''.

   * The '''case''' command, because it is deprecated

~ Specification

The commands listed above shall allow for two optional switches, one
that specifies the matching mode, and can be '''-exact''',
'''-glob''', or '''-regexp''', and one that specifies case
sensitivity, and can be '''-case''', or '''-nocase'''. Their current
behaviour shall become the default behaviour in absence of the
respective switch. (Some commands may accept other switches as well.)

Also shall there be two new manual pages, one that describes glob
matching similar to the ''re_syntax'' page, and one that describes the
pattern matching options. These manuals shall be referenced by the
manuals for the individual commands instead of repeating the detailed
descriptions.

~ Objections

Some of the mentioned commands could become somewhat slower when they
need to check for more options. This needs to be checked when
implementing this TIP.

~ Reference Implementation

There is no reference implementation yet.

The idea is to have common code for option checking, and matching,
that can be used by all mentioned commands. That way it would be easy
to add new algorithms or options, and have them immediately available
for all commands that can do pattern matching.

The C API for this will first be worked out as a private API when
creating the reference implementation and later be published by a
separate TIP, so that extensions can also make use of it.

~ Notes

There might be need for a similar unification in Tk as well, but
that's outside the scope of this TIP, and should be easy to add once
this TIP is implemented so that Tcl provides the needed
infrastructure.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|








|







|




|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|




|
|

|
|

|

|


|
|
|

|


|




|





|












|






|


>

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
136
137

# TIP 246: Unify Pattern Matching

	Author:         Reinhard Max <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        27-Apr-2005
	Post-History:   
	Keywords:       pattern,match,glob,exact,regexp,case sensitive,Tcl
	Tcl-Version:    8.7
-----

# Abstract

Many Tcl commands take arguments that are patterns to match
against. Some of these commands allow options to specify whether the
pattern should be treated as a literal, a glob pattern, or a regular
expression, and whether or not matching should be case sensitive.
This TIP proposes a unique set of options for all commands that accept
pattern arguments.

# Rationale

It is hard to memorize which of the commands that take a pattern
argument allows to modify the matching mode, and in which way. With
this TIP in place pattern matching will be orthogonal throughout Tcl,
so the rules learned once can be applied to every command that uses
pattern matching.

# Current situation

The following commands currently take pattern arguments with varying
combinations of switches to specify their behaviour:

   * **array get** _arrayName_ ?_pattern_?

   * **array names** _arrayName_ ?_mode_? ?_pattern_?

   * **array values** _arrayName_ ?_pattern_?

   * **array unset** _arrayName_ ?_pattern_?

   * **dict filter** _dictionaryValue_ **key** _globPattern_

   * **dict filter** _dictionaryValue_ **value** _globPattern_

   * **dict keys** _dictionaryValue_ ?_globPattern_?

   * **dict values** _dictionaryValue_ ?_globPattern_?

   * **lsearch** ?_options..._? _list pattern_

   * **parray** _arrayName_ ?_pattern_?

   * **string match** ?**-nocase**? _pattern string_

   * **switch** ?_options..._? _string pattern body_

   * **namespace children** ?_namespace_? ?_pattern_?

   * **namespace export** ?**-clear**? ?_pattern pattern ..._?

   * **namespace forget** ?_pattern pattern ..._?

   * **namespace import** ?**-force**? ?_pattern pattern ..._?

   * **info commands** ?_pattern_?

   * **info functions** ?_pattern_?

   * **info globals** ?_pattern_?

   * **info locals** ?_pattern_?

   * **info procs** ?_pattern_?

   * **info vars** ?_pattern_?

   * **registry keys** _keyName_ ?_pattern_?

   * **registry values** _keyName_ ?_pattern_?

The following commands which also take pattern arguments are outside
the scope of this TIP:

   * Commands that match patterns against file names: **auto\_import**,
     **auto\_mkindex**, **pkg\_mkIndex**, **tcltest**.

   * Commands that use regular expressions by design: **regexp**,
     and **regsub**.

   * The **case** command, because it is deprecated

# Specification

The commands listed above shall allow for two optional switches, one
that specifies the matching mode, and can be **-exact**,
**-glob**, or **-regexp**, and one that specifies case
sensitivity, and can be **-case**, or **-nocase**. Their current
behaviour shall become the default behaviour in absence of the
respective switch. \(Some commands may accept other switches as well.\)

Also shall there be two new manual pages, one that describes glob
matching similar to the _re\_syntax_ page, and one that describes the
pattern matching options. These manuals shall be referenced by the
manuals for the individual commands instead of repeating the detailed
descriptions.

# Objections

Some of the mentioned commands could become somewhat slower when they
need to check for more options. This needs to be checked when
implementing this TIP.

# Reference Implementation

There is no reference implementation yet.

The idea is to have common code for option checking, and matching,
that can be used by all mentioned commands. That way it would be easy
to add new algorithms or options, and have them immediately available
for all commands that can do pattern matching.

The C API for this will first be worked out as a private API when
creating the reference implementation and later be published by a
separate TIP, so that extensions can also make use of it.

# Notes

There might be need for a similar unification in Tk as well, but
that's outside the scope of this TIP, and should be easy to add once
this TIP is implemented so that Tcl provides the needed
infrastructure.

# Copyright

This document has been placed in the public domain.

Name change from tip/247.tip to tip/247.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
TIP:		247
Title:		Tcl/Tk Engineering Manual
State:		Draft
Type:		Informational
Vote:		Pending
Post-History:	
Version:	$Revision: 1.9 $
Author:		John K. Ousterhout <[email protected]>
Author:		Donal K. Fellows <[email protected]>
Created:	01-Jun-2005


~ Abstract

This document describes the set of conventions used for writing C code to go
into the Tcl and Tk core. It is also recommended that extensions be written in
the same style for clarity.

~~NOTE

''A transcription of the original version (dated September 1, 1994) of this
file into PDF is available online at http://tcl.sourceforge.net/engManual.pdf
- Donal K. Fellows''

''Also note that the figures might lag the text. We'll fix them eventually.''

~ Introduction

This is a manual for people who are developing C code for Tcl, Tk, and their
extensions and applications. It describes a set of conventions for writing
code and the associated test scripts. There are two reasons for the
conventions. First, the conventions ensure that certain important things get
done; for example, every procedure must have documentation that describes each
of its arguments and its result, and there must exist test scripts that
exercise every line of code. Second, the conventions guarantee that all of the
Tcl and Tk code has a uniform style. This makes it easier for us to use, read,
and maintain each other's code.

Most of the conventions originated in the Sprite operating system project at
U.C. Berkeley. At the beginning of the Sprite project my students and I
decided that we wanted a uniform style for our code and documentation, so we
held a series of meetings to choose the rules. The result of these meetings
was a document called ''The Sprite Engineering Manual''. None of us was
completely happy with all the rules, but we all managed to live by them during
the project and I think everyone was happy with the results. When I started
work on Tcl and Tk, I decided to stick with the Sprite conventions. This
document is based heavily on ''The Sprite Engineering Manual''.

There are few things that I consider non-negotiable, but the contents of this
manual are one of them. I don't claim that these conventions are the best
possible ones, but the exact conventions don't really make that much
difference. The most important thing is that we all do things the same way.
Given that the core Tcl and Tk code follows the conventions, changing the
rules now would cause more harm than good.
<
|
|
|
|
|
<
|
|
|
>

|





|

|
|
|

|

|















|



|








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

# TIP 247: Tcl/Tk Engineering Manual
	State:		Draft
	Type:		Informational
	Vote:		Pending
	Post-History:	

	Author:		John K. Ousterhout <[email protected]>
	Author:		Donal K. Fellows <[email protected]>
	Created:	01-Jun-2005
-----

# Abstract

This document describes the set of conventions used for writing C code to go
into the Tcl and Tk core. It is also recommended that extensions be written in
the same style for clarity.

## NOTE

_A transcription of the original version \(dated September 1, 1994\) of this
file into PDF is available online at <http://tcl.sourceforge.net/engManual.pdf>
- Donal K. Fellows_

_Also note that the figures might lag the text. We'll fix them eventually._

# Introduction

This is a manual for people who are developing C code for Tcl, Tk, and their
extensions and applications. It describes a set of conventions for writing
code and the associated test scripts. There are two reasons for the
conventions. First, the conventions ensure that certain important things get
done; for example, every procedure must have documentation that describes each
of its arguments and its result, and there must exist test scripts that
exercise every line of code. Second, the conventions guarantee that all of the
Tcl and Tk code has a uniform style. This makes it easier for us to use, read,
and maintain each other's code.

Most of the conventions originated in the Sprite operating system project at
U.C. Berkeley. At the beginning of the Sprite project my students and I
decided that we wanted a uniform style for our code and documentation, so we
held a series of meetings to choose the rules. The result of these meetings
was a document called _The Sprite Engineering Manual_. None of us was
completely happy with all the rules, but we all managed to live by them during
the project and I think everyone was happy with the results. When I started
work on Tcl and Tk, I decided to stick with the Sprite conventions. This
document is based heavily on _The Sprite Engineering Manual_.

There are few things that I consider non-negotiable, but the contents of this
manual are one of them. I don't claim that these conventions are the best
possible ones, but the exact conventions don't really make that much
difference. The most important thing is that we all do things the same way.
Given that the core Tcl and Tk code follows the conventions, changing the
rules now would cause more harm than good.
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
Section 4 desribes the Tcl/Tk naming conventions. Section 5 presents low-level
coding conventions, such as how to indent and where to put curly braces.
Section 6 contains a collection of rules and suggestions for writing comments.
Section 7 describes how to write and maintain test suites. Section 8 describes
how to make code portable without making it unreadable too. Section 9 contains
a few miscellaneous topics, such as keeping a change log.

~ Packages and Header Files

Tcl applications consist of collections of ''packages''. Each package provides
code to implement a related set of features. For example, Tcl itself is a
package, as is Tk; various extensions such as Tcl-DP, TclX, Expect, and BLT
are also packages. Packages are the units in which code is developed and
distributed: a single package is typically developed by a single person or
group and distributed as a unit. One of the best things about Tcl is that it
is possible to combine many independently-developed packages into a single
application; packages should be designed with this in mind. This section
describes the file structure of packages with an emphasis on header files;
later sections discuss conventions for code files. You may also wish to review
Chapter 31 of the Tcl book for additional information on packages, such as how
to interface them to the rest of an application.

~~Package Prefixes

Each package has a unique short ''prefix''. The prefix is used in file names,
procedure names, and variable names in order to prevent name conflicts with
other packages. For example, the prefix for Tcl is tcl; Tcl's exported header
file is called tcl.h and exported procedures and variables have names like
Tcl_Eval.

~~Version Numbers

Each package has a two-part version number such as 7.4. The first number (7)
is called the major version number and the second (4) is called the minor
version number. The version number changes with each public release of the
package. If a new release contains only bug fixes, new features, and other
upwardly compatible changes, so that code and scripts that worked with the old
version will also work with the new version, then the minor version number
increments and the major version number stays the same (e.g., from 7.4 to
7.5). If the new release contains substantial incompatibilities, so that
existing code and scripts will have to be modified to run with the new
version, then the major version number increments and the minor version number
resets to zero (e.g., from 7.4 to 8.0).

~~Overall Structure

A package typically consists of several code files, plus at least two header
files, plus additional files for building and configuring the package, such as
a Makefile and a configure.in file for the autoconf program. The header files
for a package generally fall into the following categories:

 * A ''package header file'', which is named after the package, such as tcl.h
   or tk.h. This header file describes all of the externally-visible features
   of the package, such as procedures, global variables, and structure
   declarations. The package header file is eventually installed in a system
   directory such as /usr/local/include; it is what clients of the package
   #include in their C code. As a general rule of thumb, the package header
   file should define as few things as possible: it's very hard to change an
   exported feature since it breaks client code that uses the package, so the
   less you export, the easier it will be to make changes to the package.
   Thus, for example, try not to make the internal fields of structures
   visible in package header files.

 * An ''internal header file'', which is typically #included by all of the C
   files in the package. The internal header file has a name like tclInt.h or
   tkInt.h, consisting of the the package prefix followed by Int.h. The
   internal header file describes features that are used in multiple files
   within the package but aren't exported out of the package. For example, key
   package structures and internal utility procedures are defined in the
   internal header file. The internal header file should also contain
   #includes for other headers that are used widely within the package, so
   they don't have to be included over and over in each code file. As with the
   package header, the internal header file should be as small as possible:
   structures and procedures that are only used in a single C file in the
   package should not appear in it.

 * A ''porting header file'', which contains definitions that hide the
   differences between the systems on which the package can be used. The name
   of the porting header should consist of the package prefix follwed by
   Port.h, such as tclPort.h.

 * Other internal header files for various subpackages within the package. For
   example, there is a file tkText.h in Tk that is shared among all the files
   that implement text widgets and another file tkCanvas.h that is shared
   among all the widgets implementing canvases.

I recommend having as few header files as possible in each package. In almost
all cases a package header file, a single internal header file, and a porting
header file will be sufficient, and in many cases the porting header file may
not be necessary. The internal header file should automatically #include the
package header file and perhaps even the porting header file, so each C file
in the package only needs to #include one or at most two header files. I
recommend keeping the porting header separate from the internal header file in
order to maintain a clean separation between porting code and the rest of the
module. Other internal headers should only be necessary in unusual cases, such
as the Tk text and canvas widgets (each of tkText.h and tkCanvas.h is many
hundred lines long, due to the complexity of the widgets, and they are needed
only in the source files that implement the particular widgets, so I thought
it would be easier to manage these headers separately from tkInt.h). If you
have lots of internal header files, such as one for each source file, then you
will end up with lots of #include statements in each C file and you'll find
that either ''(a)'' you #include every header in every C file (in which case
there's not much advantage to having the separate .h files) or ''(b)'' you are
constantly adding and deleting #include statements as you modify source files.

~~Header File Structure

Figure 1 illustrates the format of a header file. Your header files should
follow this structure exactly: same indentation, same order of information,
and so on. To make this as easy as possible, the directory engManual in the
Tcl source tree contains templates for various pieces of source files. For
example, the file proto.h contains a template for a header file; there are
also templates for code files and procedure headers. You should be able to set
up your editor to incorporate the templates when needed, then you can modify
them for the particular situation in which they are used. This should make it
easy for you to conform to the conventions without a lot of typing overhead.

#image:247fig1 Figure 1. An example of a header file. The file
engManual/proto.h contains a template for header files.

Each header file contains the following parts, which are labelled in Figure 1:

 Abstract: the first few lines give the name of the file plus a short
    description of its overall purpose.

 Copyright notice: this protects the ownership of the file and controls
    distribution; different notices may be used on different files, depending
    on whether the file is to be released freely or restricted. The wording in
    copyright notices is sensitive (e.g.  the use of upper case is important)
    so don't make changes in notices without checking with a legal authority.

 Revision string: the contents of this string are managed automatically by the
    source code control system for the file, such as RCS or SCCS (RCS is used
    in the example in the figure). It identifies the file's current revision,
    date of last modification, and so on.

 Multiple include #ifdef: when a large application is developed with many
    related packages, it is hard to arrange the #include statements so that
    each include file is included exactly once For example, files a.h and b.h
    might both include c.h, and a particular code file might include both a.h
    and b.h. This will cause c.h to be processed twice, and could potentially
    result in compiler errors such as multiply-defined symbols. With the
    recursion #ifdef, plus the matching #endif at the end of the file, the
    header file can be #included multiple times without problems.  The symbol
    _TCL is defined the first time the header file is included; if the header
    is included again the presence of the symbol causes the body of the header
    file to be skipped. The symbol used in any given header file should be the
    same as the name of the header file except with the .h stripped off, a _
    prepended, and everything else capitalized.

 Version defines: for each package, three symbols related to the current
    version number should be defined. The first gives the full version number
    as a string, and the second and third give the major and minor numbers
    separately as integers. The names for these symbols should be derived from
    the package prefix as in Figure 1.

 Declarations: the rest of the header file consists of declarations for the
    things that are exported from the package to its clients. Most of the
    conventions for coding these declarations will be discussed later. When
    declaring variables and procedures, use EXTERN instead of extern to
    declare them external. The symbol EXTERN can then be #defined to either
    extern or extern "C" to allow the header file to be used in both C and C++
    programs. The header file tcl.h contains code to #define the EXTERN
    symbol; if your header file doesn't #include tcl.h, you can copy the code
    from tcl.h to your header file.

~~_ANSI_ARGS_ Prototypes

Procedure prototypes ''may'' use the _ANSI_ARGS_ macro as shown in Figure 1.
_ANSI_ARGS_ makes it possible to write full procedure prototypes for the
normal case where an ANSI C compiler will be used, yet it also allows the file
to be used with older non-ANSI compilers. To use _ANSI_ARGS_, specify the
entire argument list, including parentheses, as an argument to the _ANSI_ARGS_
macro; _ANSI_ARGS_ will evaluate to either this argument list or (), depending
on whether or not an ANSI C compiler is being used. The _ANSI_ARGS_ macro is
defined in ''tcl.h''.

In the argument lists in procedure prototypes, be sure to specify names for
the arguments as well as their types. The names aren't required for
compilation (for example, the declaration for Tcl_Eval could have been written
as

|   EXTERN int Tcl_Eval _ANSI_ARGS_((Tcl_Interp *, const char *));

in Figure 1) but the names provide additional information about the arguments.

Note that for modern code, it is usually preferred to omit this macro,
resulting in the above example looking like:

|   EXTERN int Tcl_Eval(Tcl_Interp *interp, const char *scriptPtr);

~~MODULE_LOCAL Prototypes

''(Not yet shown in any figure, to be used from Tcl 8.5 onwards for the Tcl
and Tk core only.)''

Where a function is only exported so that it may be accessed from a file other
than the file that declares it, that function should be declared as being
MODULE_LOCAL. While this does not have an effect with all toolchains, some
(such as the ones used for MS Windows and MacOS X) can use this information
during the linking stage to ensure that the symbol in the resulting library
cannot be linked against by external code. This is useful for keeping the
internal implementation of library code away from casual misuse.

Example of usage:

|   MODULE_SCOPE int TclIsLocalScalar(const char *src, int len);

~How to Organize a Code File

Each source code file should contain a related set of procedures, such as the
implementation of a widget or canvas item type, or a set of procedures to
implement hash tables. Before writing any code you should think carefully
about what functions are to be provided and divide them up into files in a
logical way. In my experience, the most manageable size for files is usually
in the range of 500-2000 lines. If a file gets much larger than this, it will
be hard to remember everything that the file does. If a file is much shorter
than this, then you may end up with too many files in a directory, which is
also hard to manage. Code files are divided into pages separated by formfeed
(control-L) characters. The first page of the file is a header page containing
information that is used throughout the file. Each additional page of the file
contains one procedure. This approach has two advantages. First, when you
print a code file each procedure header will start at the top of the page,
which makes for easier reading. Second, you can browse through all of the
procedures in a file by searching for the formfeed characters.

~~The File Header Page

The first page of a code file is a header page. It contains overall
information that is relevant throughout the file, which consists of everything
but the definitions of the file's procedures. The header page typically has
six parts, as shown in Figure 2:

#image:247fig2 Figure 2. An example of a header page. Part of the text of the
copyright notice has been omitted. The file engManual/proto.c contains a
template for a header page.

 Abstract: the first few lines give the name of the file and a brief
    description of the overall functions provided by the file, just as in
    header files.

 Copyright notice: protects ownership of the file, just as in header files.

 Revision string: similar to the revision strings in header files, except that
    its value is used to initialize a string variable. This allows the
    revision information to be checked in the executable object file.

 Include statements: all of the #include statements for the file should appear
    on the header file just after the version string. In general there should
    be very few #include statements in a given code file, typically just for
    the package's internal header file and porting header file. If additional
    #includes are needed they should appear in the package's internal header
    file or porting header file.

 Declarations: any structures used only in this file should be declared on the
    header page (exported structures must be declared in header files). In
    addition, if the file defines any static or global variables then they
    should be declared on the header page. This makes it easy to tell whether
    or not a file has static variables, which is important if the file is ever
    used in a multi-threaded environment. Static variables are generally
    undesirable and should be avoided as much as possible.

 Prototypes: procedure prototypes for procedures referenced only in this file
    should appear at the very end of the header page (prototypes for exported
    procedures must appear in the package header file). Use the _ANSI_ARGS_
    macro described in Section 2.5.

Please structure your header pages in exactly the order given above and follow
the syntax of Figure 2 as closely as possible. The file engManual/proto.c
provides a template for a header page.

Source files should never contain extern statements. Instead, create header
files to hold the extern statements and #include the header files. This makes
code files easier to read and makes it easier to manage the extern statements,
since they're centralized in .h files instead of spread around dozens of code
files. For example, the internal header file for a package has extern
statements for all of the procedures that are used by multiple files within
the package but aren't exported outside it.

~~Procedure Headers

Each page after the first one in a file should contain exactly one procedure.
The page should begin with a procedure header that gives overall documentation
for the procedure, followed by the declaration and body for the procedure. See
Figures 3 and 4 for examples. The header should contain everything that a
caller of the procedure needs to know in order to use the procedure, and
nothing else. It consists of three parts:

#image:247fig3 Figure 3. The header comments and declaration for a procedure.
 The file engManual/prochead contains a template for this information.

#image:247fig4 Figure 4. The header for a procedure with side effects.

 Abstract: the first lines in the header give the procedure's name, followed
    by a brief description of what the procedure does. This should not be a
    detailed description of how the procedure is implemented, but rather a
    high-level summary of its overall function. In some cases, such as
    callback procedures, I recommend also describing the conditions under
    which the procedure is invoked and who calls the procedure, as in Figure 4.







|

|












|

|



|

|

|
|




|
|


|

|






|




|






|






|





|












|

|



|


|

|
|
|
|

|











|










|



|
|


|
|




|
|
|


|












|
|
|
|


|

|
|

|
|
|
|
|



|


|

|




|

|

|
|



|
|






|

|










|






|






|













|

|

|



|







|
|







|






|








|


|







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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
Section 4 desribes the Tcl/Tk naming conventions. Section 5 presents low-level
coding conventions, such as how to indent and where to put curly braces.
Section 6 contains a collection of rules and suggestions for writing comments.
Section 7 describes how to write and maintain test suites. Section 8 describes
how to make code portable without making it unreadable too. Section 9 contains
a few miscellaneous topics, such as keeping a change log.

# Packages and Header Files

Tcl applications consist of collections of _packages_. Each package provides
code to implement a related set of features. For example, Tcl itself is a
package, as is Tk; various extensions such as Tcl-DP, TclX, Expect, and BLT
are also packages. Packages are the units in which code is developed and
distributed: a single package is typically developed by a single person or
group and distributed as a unit. One of the best things about Tcl is that it
is possible to combine many independently-developed packages into a single
application; packages should be designed with this in mind. This section
describes the file structure of packages with an emphasis on header files;
later sections discuss conventions for code files. You may also wish to review
Chapter 31 of the Tcl book for additional information on packages, such as how
to interface them to the rest of an application.

## Package Prefixes

Each package has a unique short _prefix_. The prefix is used in file names,
procedure names, and variable names in order to prevent name conflicts with
other packages. For example, the prefix for Tcl is tcl; Tcl's exported header
file is called tcl.h and exported procedures and variables have names like
Tcl\_Eval.

## Version Numbers

Each package has a two-part version number such as 7.4. The first number \(7\)
is called the major version number and the second \(4\) is called the minor
version number. The version number changes with each public release of the
package. If a new release contains only bug fixes, new features, and other
upwardly compatible changes, so that code and scripts that worked with the old
version will also work with the new version, then the minor version number
increments and the major version number stays the same \(e.g., from 7.4 to
7.5\). If the new release contains substantial incompatibilities, so that
existing code and scripts will have to be modified to run with the new
version, then the major version number increments and the minor version number
resets to zero \(e.g., from 7.4 to 8.0\).

## Overall Structure

A package typically consists of several code files, plus at least two header
files, plus additional files for building and configuring the package, such as
a Makefile and a configure.in file for the autoconf program. The header files
for a package generally fall into the following categories:

 * A _package header file_, which is named after the package, such as tcl.h
   or tk.h. This header file describes all of the externally-visible features
   of the package, such as procedures, global variables, and structure
   declarations. The package header file is eventually installed in a system
   directory such as /usr/local/include; it is what clients of the package
   \#include in their C code. As a general rule of thumb, the package header
   file should define as few things as possible: it's very hard to change an
   exported feature since it breaks client code that uses the package, so the
   less you export, the easier it will be to make changes to the package.
   Thus, for example, try not to make the internal fields of structures
   visible in package header files.

 * An _internal header file_, which is typically \#included by all of the C
   files in the package. The internal header file has a name like tclInt.h or
   tkInt.h, consisting of the the package prefix followed by Int.h. The
   internal header file describes features that are used in multiple files
   within the package but aren't exported out of the package. For example, key
   package structures and internal utility procedures are defined in the
   internal header file. The internal header file should also contain
   \#includes for other headers that are used widely within the package, so
   they don't have to be included over and over in each code file. As with the
   package header, the internal header file should be as small as possible:
   structures and procedures that are only used in a single C file in the
   package should not appear in it.

 * A _porting header file_, which contains definitions that hide the
   differences between the systems on which the package can be used. The name
   of the porting header should consist of the package prefix follwed by
   Port.h, such as tclPort.h.

 * Other internal header files for various subpackages within the package. For
   example, there is a file tkText.h in Tk that is shared among all the files
   that implement text widgets and another file tkCanvas.h that is shared
   among all the widgets implementing canvases.

I recommend having as few header files as possible in each package. In almost
all cases a package header file, a single internal header file, and a porting
header file will be sufficient, and in many cases the porting header file may
not be necessary. The internal header file should automatically \#include the
package header file and perhaps even the porting header file, so each C file
in the package only needs to \#include one or at most two header files. I
recommend keeping the porting header separate from the internal header file in
order to maintain a clean separation between porting code and the rest of the
module. Other internal headers should only be necessary in unusual cases, such
as the Tk text and canvas widgets \(each of tkText.h and tkCanvas.h is many
hundred lines long, due to the complexity of the widgets, and they are needed
only in the source files that implement the particular widgets, so I thought
it would be easier to manage these headers separately from tkInt.h\). If you
have lots of internal header files, such as one for each source file, then you
will end up with lots of \#include statements in each C file and you'll find
that either _\(a\)_ you \#include every header in every C file \(in which case
there's not much advantage to having the separate .h files\) or _\(b\)_ you are
constantly adding and deleting \#include statements as you modify source files.

## Header File Structure

Figure 1 illustrates the format of a header file. Your header files should
follow this structure exactly: same indentation, same order of information,
and so on. To make this as easy as possible, the directory engManual in the
Tcl source tree contains templates for various pieces of source files. For
example, the file proto.h contains a template for a header file; there are
also templates for code files and procedure headers. You should be able to set
up your editor to incorporate the templates when needed, then you can modify
them for the particular situation in which they are used. This should make it
easy for you to conform to the conventions without a lot of typing overhead.

![Figure 1. An example of a header file. The file](../assets/247fig1.png)
engManual/proto.h contains a template for header files.

Each header file contains the following parts, which are labelled in Figure 1:

 Abstract: the first few lines give the name of the file plus a short
    description of its overall purpose.

 Copyright notice: this protects the ownership of the file and controls
    distribution; different notices may be used on different files, depending
    on whether the file is to be released freely or restricted. The wording in
    copyright notices is sensitive \(e.g.  the use of upper case is important\)
    so don't make changes in notices without checking with a legal authority.

 Revision string: the contents of this string are managed automatically by the
    source code control system for the file, such as RCS or SCCS \(RCS is used
    in the example in the figure\). It identifies the file's current revision,
    date of last modification, and so on.

 Multiple include \#ifdef: when a large application is developed with many
    related packages, it is hard to arrange the \#include statements so that
    each include file is included exactly once For example, files a.h and b.h
    might both include c.h, and a particular code file might include both a.h
    and b.h. This will cause c.h to be processed twice, and could potentially
    result in compiler errors such as multiply-defined symbols. With the
    recursion \#ifdef, plus the matching \#endif at the end of the file, the
    header file can be \#included multiple times without problems.  The symbol
    \_TCL is defined the first time the header file is included; if the header
    is included again the presence of the symbol causes the body of the header
    file to be skipped. The symbol used in any given header file should be the
    same as the name of the header file except with the .h stripped off, a \_
    prepended, and everything else capitalized.

 Version defines: for each package, three symbols related to the current
    version number should be defined. The first gives the full version number
    as a string, and the second and third give the major and minor numbers
    separately as integers. The names for these symbols should be derived from
    the package prefix as in Figure 1.

 Declarations: the rest of the header file consists of declarations for the
    things that are exported from the package to its clients. Most of the
    conventions for coding these declarations will be discussed later. When
    declaring variables and procedures, use EXTERN instead of extern to
    declare them external. The symbol EXTERN can then be \#defined to either
    extern or extern "C" to allow the header file to be used in both C and C\+\+
    programs. The header file tcl.h contains code to \#define the EXTERN
    symbol; if your header file doesn't \#include tcl.h, you can copy the code
    from tcl.h to your header file.

## \_ANSI\_ARGS\_ Prototypes

Procedure prototypes _may_ use the \_ANSI\_ARGS\_ macro as shown in Figure 1.
\_ANSI\_ARGS\_ makes it possible to write full procedure prototypes for the
normal case where an ANSI C compiler will be used, yet it also allows the file
to be used with older non-ANSI compilers. To use \_ANSI\_ARGS\_, specify the
entire argument list, including parentheses, as an argument to the \_ANSI\_ARGS\_
macro; \_ANSI\_ARGS\_ will evaluate to either this argument list or \(\), depending
on whether or not an ANSI C compiler is being used. The \_ANSI\_ARGS\_ macro is
defined in _tcl.h_.

In the argument lists in procedure prototypes, be sure to specify names for
the arguments as well as their types. The names aren't required for
compilation \(for example, the declaration for Tcl\_Eval could have been written
as

	   EXTERN int Tcl_Eval _ANSI_ARGS_((Tcl_Interp *, const char *));

in Figure 1\) but the names provide additional information about the arguments.

Note that for modern code, it is usually preferred to omit this macro,
resulting in the above example looking like:

	   EXTERN int Tcl_Eval(Tcl_Interp *interp, const char *scriptPtr);

## MODULE\_LOCAL Prototypes

_\(Not yet shown in any figure, to be used from Tcl 8.5 onwards for the Tcl
and Tk core only.\)_

Where a function is only exported so that it may be accessed from a file other
than the file that declares it, that function should be declared as being
MODULE\_LOCAL. While this does not have an effect with all toolchains, some
\(such as the ones used for MS Windows and MacOS X\) can use this information
during the linking stage to ensure that the symbol in the resulting library
cannot be linked against by external code. This is useful for keeping the
internal implementation of library code away from casual misuse.

Example of usage:

	   MODULE_SCOPE int TclIsLocalScalar(const char *src, int len);

# How to Organize a Code File

Each source code file should contain a related set of procedures, such as the
implementation of a widget or canvas item type, or a set of procedures to
implement hash tables. Before writing any code you should think carefully
about what functions are to be provided and divide them up into files in a
logical way. In my experience, the most manageable size for files is usually
in the range of 500-2000 lines. If a file gets much larger than this, it will
be hard to remember everything that the file does. If a file is much shorter
than this, then you may end up with too many files in a directory, which is
also hard to manage. Code files are divided into pages separated by formfeed
\(control-L\) characters. The first page of the file is a header page containing
information that is used throughout the file. Each additional page of the file
contains one procedure. This approach has two advantages. First, when you
print a code file each procedure header will start at the top of the page,
which makes for easier reading. Second, you can browse through all of the
procedures in a file by searching for the formfeed characters.

## The File Header Page

The first page of a code file is a header page. It contains overall
information that is relevant throughout the file, which consists of everything
but the definitions of the file's procedures. The header page typically has
six parts, as shown in Figure 2:

![Figure 2. An example of a header page. Part of the text of the](../assets/247fig2.png)
copyright notice has been omitted. The file engManual/proto.c contains a
template for a header page.

 Abstract: the first few lines give the name of the file and a brief
    description of the overall functions provided by the file, just as in
    header files.

 Copyright notice: protects ownership of the file, just as in header files.

 Revision string: similar to the revision strings in header files, except that
    its value is used to initialize a string variable. This allows the
    revision information to be checked in the executable object file.

 Include statements: all of the \#include statements for the file should appear
    on the header file just after the version string. In general there should
    be very few \#include statements in a given code file, typically just for
    the package's internal header file and porting header file. If additional
    \#includes are needed they should appear in the package's internal header
    file or porting header file.

 Declarations: any structures used only in this file should be declared on the
    header page \(exported structures must be declared in header files\). In
    addition, if the file defines any static or global variables then they
    should be declared on the header page. This makes it easy to tell whether
    or not a file has static variables, which is important if the file is ever
    used in a multi-threaded environment. Static variables are generally
    undesirable and should be avoided as much as possible.

 Prototypes: procedure prototypes for procedures referenced only in this file
    should appear at the very end of the header page \(prototypes for exported
    procedures must appear in the package header file\). Use the \_ANSI\_ARGS\_
    macro described in Section 2.5.

Please structure your header pages in exactly the order given above and follow
the syntax of Figure 2 as closely as possible. The file engManual/proto.c
provides a template for a header page.

Source files should never contain extern statements. Instead, create header
files to hold the extern statements and \#include the header files. This makes
code files easier to read and makes it easier to manage the extern statements,
since they're centralized in .h files instead of spread around dozens of code
files. For example, the internal header file for a package has extern
statements for all of the procedures that are used by multiple files within
the package but aren't exported outside it.

## Procedure Headers

Each page after the first one in a file should contain exactly one procedure.
The page should begin with a procedure header that gives overall documentation
for the procedure, followed by the declaration and body for the procedure. See
Figures 3 and 4 for examples. The header should contain everything that a
caller of the procedure needs to know in order to use the procedure, and
nothing else. It consists of three parts:

![Figure 3. The header comments and declaration for a procedure.](../assets/247fig3.png)
 The file engManual/prochead contains a template for this information.

![Figure 4. The header for a procedure with side effects.](../assets/247fig4.png)

 Abstract: the first lines in the header give the procedure's name, followed
    by a brief description of what the procedure does. This should not be a
    detailed description of how the procedure is implemented, but rather a
    high-level summary of its overall function. In some cases, such as
    callback procedures, I recommend also describing the conditions under
    which the procedure is invoked and who calls the procedure, as in Figure 4.
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698

699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718

719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826

827
828
829
830
831
832
833
834
835
836

837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327

    section should not describe every internal variable modified by the
    procedure. It should simply provide the sort of information that users of
    the procedure need in order to use the procedure correctly. See Figure 4
    for an example.

The file engManual/prochead contains a template for a procedure header, which
you can include from your editor to save typing. Follow the syntax of Figures
3 and 4 exactly (same indentation, double-dash after the procedure name,
etc.).

The Results and Side Effects parts of the header may be omitted ''only'' if
the function has no results or side effects respectively.

~~Procedure Declarations

The procedure declaration should also follow exactly the syntax in Figures 3
and 4. The first line gives the type of the procedure's result. All procedures
must be typed: use void if the procedure returns no result. The second line
gives the procedure's name and its argument list. If there are many arguments,
they may spill onto additional lines (see Sections 5.1 and 5.5 for information
about indentation). After this come the declarations of argument types, one
argument per line, indented, with a comment after each argument giving a brief
description of the argument. Every argument must be explicitly declared, and
every argument must have a comment.

This form for argument declarations is the old form that predates ANSI C. It's
important to use the old form so that your code will compile on older pre-ANSI
compilers. Hopefully there aren't too many of these compilers left, and
perhaps in a few years we can switch to the ANSI form, but for now let's be
safe. Every procedure should also have an ANSI-style prototype either on the
file's header page or in a header file, so this approach still allows full
argument checking.

''Note that'' for new code it is preferred to use ANSI declarations,
especially if the code will not build on non-ANSI compilers.

~~Parameter Order

Procedure parameters may be divided into three categories. In parameters only
pass information into the procedure (either directly or by pointing to
information that the procedure reads). Out parameters point to things in the
caller's memory that the procedure modifies. In-out parameters do both. Below
is a set of rules for deciding on the order of parameters to a procedure:

 1. Parameters should normally appear in the order in, in/out, out, except
    where overridden by the rules below.

 2. If there is a group of procedures, all of which operate on structures of a
    particular type, such as a hash table, the token for the structure should
    be the first argument to each of the procedures.

 3. When two parameters are the address of a callback procedure and a
    ClientData value to pass to that procedure, the procedure address should
    appear in the argument list immediately before the ClientData.

 4. If a callback procedure takes a ClientData argument (and all callbacks
    should), the ClientData argument should be the first argument to the
    procedure. Typically the ClientData is a pointer to the structure managed
    by the callback, so this is really the same as rule 2.

~~Procedure Bodies

The body of a procedure follows the declaration. See Section 5 for the coding
conventions that govern procedure bodies. The curly braces enclosing the body
should be on separate lines as shown in Figures 3 and 4.

~Naming Conventions

Choosing names is one of the most important aspects of programming. Good names
clarify the function of a program and reduce the need for other documentation.
Poor names result in ambiguity, confusion, and error. For example, in the
Sprite operating system we spent four months tracking down a subtle problem
with the file system that caused seemingly random blocks on disk to be
overwritten from time to time. It turned out that the same variable name was
used in some places to refer to physical blocks on disk, and in other places
to logical blocks in a file; unfortunately, in one place the variable was
accidentally used for the wrong purpose. The bug probably would not have
occurred if different variable names had been used for the two kinds of block
identifiers.

This section gives some general principles to follow when choosing names, then
lists specific rules for name syntax, such as capitalization, and finally
describes how to use package prefixes to clarify the module structure of your
code.

~~General Considerations

The ideal variable name is one that instantly conveys as much information as
possible about the purpose of the variable it refers to. When choosing names,
play devil's advocate with yourself to see if there are ways that a name might
be misinterpreted or confused. Here are some things to consider:

 1. Are you consistent? Use the same name to refer to the same thing
    everywhere. For example, in the Tcl implementation the name ''interp'' is
    used consistently for pointers to the uservisible Tcl_Interp structure.
    Within the code for each widget, a standard name is always used for a
    pointer to the widget record, such as ''butPtr'' in the button widget code
    and ''menuPtr'' in the menu widget code.

 2. If someone sees the name out of context, will they realize what it stands
    for, or could they confuse it with something else? For example, in Sprite
    the procedure for doing byte-swapping and other format conversion was
    originally called Swap_Buffer. When I first saw that name I assumed it had
    something to do with I/O buffer management, not reformatting. We
    subsequently changed the name to Fmt_Convert.

 3. Could this name be confused with some other name? For example, it's
    probably a mistake to have two variables ''s'' and ''string'' in the same
    procedure, both referring to strings: it will be hard for anyone to
    remember which is which. Instead, change the names to reflect their
    functions. For example, if the strings are used as source and destination
    for a copy operation, name them ''src'' and ''dst''.

 4. Is the name so generic that it doesn't convey any information? The
    variable ''s'' from the previous paragraph is an example of this; changing
    its name to ''src'' makes the name less generic and hence conveys more
    information.

~~Basic Syntax Rules

Below are some specific rules governing the syntax of names. Please follow the
rules exactly, since they make it possible to determine certain properties of
a variable just from its name.

 1. Variable names always start with a lower-case letter. Procedure and type
    names always start with an upper-case letter.

|   int counter;
|   extern char *FindElement();
|   typedef int Boolean;

 2. In multi-word names, the first letter of each trailing word is
    capitalized. Do not use underscores as separators between the words of a
    name, except as described in rule 5 below and in Section 4.3.

|   int numWindows;

 3. Any name that refers to a pointer ends in Ptr. If the name refers to a
    pointer to a pointer, then it ends in PtrPtr, and so on. There are two
    exceptions to this rule. The first is for variables that are opaque
    handles for structures, such as variables of type Tk_Window. These
    variables are actually pointers, but they are never dereferenced outside
    Tk (clients can never look at the structure they point to except by
    invoking Tk macros and procedures). In this case the Ptr is omitted in
    variable names. The second exception to the rule is for strings. We
    decided in Sprite not to require Ptr suffixes for strings, since they are
    always referenced with pointers. However, if a variable holds a pointer to
    a string pointer, then it must have the Ptr suffix (there's just one less
    level of Ptr for strings than for other structures).

|   TkWindow *winPtr;
|   char *name;
|   char **namePtr;

 4. Variables that hold the addresses of functions should have names ending in
    Proc (for "procedure"). Typedefs for these variables should also have
    names ending in Proc.

|   typedef void (Tk_ImageDeleteProc)(ClientData clientData);

 5. #defined constants and macros have names that are all capital letters,
    except for macros that are used as replacements for procedures, in which
    case you should follow the naming conventions for procedures. If names in
    all caps contain multiple words, use underscores to separate the words.

|   #define NULL 0
|   #define BUFFER_SIZE 1024
|   #define Min(a,b) (((a) < (b)) ? (a) : (b))

 6. Names of programs, Tcl commands, and keyword arguments to Tcl commands
    (such as Tk configuration options) are usually entirely in lower case, in
    spite of the rules above. The reason for this rule is that these names are
    likely to typed interactively, and I thought that using all lower case
    would make it easier to type them. In retrospect I'm not sure this was a
    good idea; in any case, Tcl procedure and variable names should follow the
    same rules as C procedures and variables.

~~Names Reflect Package Structure

Names that are exported outside a single file must include the package prefix
in order to make sure that they don't conflict with global names defined in
other packages. The following rules define how to use package prefixes in
names:

 1. If a variable or procedure or type is exported by its package, the first
    letters of its name must consist of the package prefix followed by an
    underscore. Only the first letter of the prefix is ever capitalized, and
    it is subject to the capitalization rules from Section 4.2. The first
    letter after the prefix is always capitalized. The first example below
    shows an exported variable, and the second shows an exported type and
    exported procedure.

|   extern int tk_numMainWindows;
|   extern Tcl_Interp *Tcl_CreateInterp(void);

 2. If a module contains several files, and if a name is used in several of
    those files but isn't used outside the package, then the name must have
    the package prefix but no underscore. The prefix guarantees that the name
    won't conflict with a similar name from a different package; the missing
    underscore indicates that the name is private to the package.

|   extern void TkEventDeadWindow(TkWindow *winPtr);

 3. If a name is only used within a single procedure or file, then it need not
    have the module prefix. To avoid conflicts with similar names in other
    files, variables and procedures declared outside procedures must always be
    declared static if they have no module prefix.

|   static int initialized;

~~Standard Names

The following variable names are used consistently throughout Tcl and Tk.
Please use these names for the given purposes in any code you write, and don't
use the names for other purposes.

 clientData: Used for variables of type ClientData, which are associated with
    callback procedures.

 interp: Used for variables of type Tcl_Interp. These are the (mostly) opaque
    handles for interpreters that are given to Tcl clients. These variables
    should really have a Ptr extension, but the name was chosen at a time when
    interpreters were totally opaque to clients.

 iPtr: Used for variables of type Interp *, which are pointers to Tcl's
    internal structures for interpreters. Tcl procedures often have an
    argument named interp, which is copied into a local variable named iPtr in
    order to access the contents of the interpreter.

 nextPtr: A field with this name is used in structures to point to the next
    structure in a linked list. This is usally the last field of the
    structure.

 tkwin: Used for variables of type Tk_Window, which are opaque handles for the
    window structures managed by Tk.

 winPtr: Used for variables of type TkWindow *, which are pointers to Tk's
    internal structures for windows. Tk procedures often take an argument
    named tkwin and immediately copy the argument into a local variable named
    winPtr in order to access the contents of the window structure.

~Low-Level Coding Conventions

This section describes several low-level syntactic rules for writing C code.
The reason for having these rules is not because they're better than all other
ways of structuring code, but in order to make all our code look the same.

~~Indents are 4 Spaces

Each level of indentation should be four spaces. There are ways to set 4-space
indents in all editors that I know of. Be sure that your editor really uses
four spaces for the indent, rather than just displaying tabs as four spaces
wide; if you use the latter approach then the indents will appear eight spaces
wide in other editors.

If you use tabs, they ''must'' be to 8-space indents.

~~Code Comments Occupy Full Lines

Comments that document code (as opposed to declarations) should occupy full
lines, rather than being tacked onto the ends of lines containing code. The
reason for this is that side-byside comments are hard to see, particularly if
neighboring statements are long enough to overlap the side-by-side comments.
Comments must have exactly the structure shown in Figure 5, including a
leading /* line, a trailing */ line, and additional blank lines above and
below. The leading blank line can be omitted if the comment is at the
beginning of a block, as is the case in the second comment in Figure 5. Each
comment should be indented to the same level as the surrounding code. Use
proper English in comments: write complete sentences, capitalize the first
word of each sentence, and so on.

#image:247fig5 Figure 5. Comments in code have the form shown above, using
full lines, with lined-up stars, the /* and */ symbols on separate lines, and
blank separator lines around each comment (except that the leading blank line
can be omitted if the comment is at the beginning of a code block).

~~Declaration Comments are Side-By-Side

When documenting the arguments for procedures and the members of structures,
place the comments on the same lines as the declarations. Figures 3 and 4 show
comments for procedure arguments and Figure 6 shows a simple structure
declaration. The format for comments is the same in both cases. Place the
comments to the right of the declarations, with all the left edges of all the
comments lined up. When a comment requires more than one line, indent the
additional lines to the same level as the first line, with the closing */ on
the same line as the end of the text. For structure declarations it is usually
useful to have a block of comments preceding the declaration, as in Figure
6. This comments before the declaration use the format given in Section 5.2.

#image:247fig6 Figure 6. Use side-by-side comments when declaring structure
members and procedure arguments.

Declaration comments should normally begin in the 33rd column (i.e. where you
would be after 32 spaces or 4 tabs).

~~Curly Braces: { Goes at the End of a Line

Open curly braces should not (normally) appear on lines by themselves.
Instead, they should be placed at the end of the preceding line. Close curly
braces always appear as the first non-blank character on a line. Figure 5
shows how to use curly braces in statements such as if and while, and Figure 6
shows how curly braces should be used in structure declarations. If an if
statement has an else clause then else appears on the same line as the
preceding } and the following {. Close curly braces are indented to the same
level as the outer code, i.e., four spaces less than the statements they
enclose.

The only cases where a { appears on a line by itself are the initial { for the
body of a procedure (see Figures 3 and 4) or where a block is being started
''without'' being the body of an if, do, for, while or switch construct.

Always use curly braces around compound statements, even if there is only one
statement in the block. Thus you shouldn't write code like

|   if (filePtr->numLines == 0) return -1;

but rather

|   if (filePtr->numLines == 0) {
|       return -1;
|   }


This approach makes code less dense, but it avoids potential mistakes when
adding additional lines to an existing single-statement block. It also makes
it easier to set breakpoints in a debugger, since it guarantees that each
statement on is on a separate line and can be named individually.

There is one exception to the rule about enclosing blocks in {}. For if
statements with cascaded else if clauses, you may use a form like the
following:

|   if (strcmp(argv[1], "delete") == 0) {
|       ...
|   } else if (strcmp(argv[1], "get") == 0) {
|       ...
|   } else if (strcmp(argv[1], "set") == 0) {
|       ...
|   } else {
|       ...
|   }


~~Continuation Lines are Indented 8 Spaces

You should use continuation lines to make sure that no single line exceeds 80
characters in length. Continuation lines should be indented 8 spaces so that
they won't be confused with an immediately-following nested block (see Figure
7). Pick clean places to break your lines for continuation, so that the
continuation doesn't obscure the structure of the statement. For example, if a
procedure call requires continuation lines, make sure that each argument is on
a single line. If the test for an if or while command spans lines, try to make
each line have the same nesting level of parentheses if possible. I try to
start each continuation line with an operator such as *, &&, or ||; this makes
it clear that the line is a continuation, since a new statement would never
start with such an operator.

#image:247fig7 Figure 7. Continuation lines are indented 8 spaces.

~~Avoid Macros Except for Simple Things

#define statements provide a fine mechanism for specifying constants
symbolically, and you should always use them instead of embedding specific
numbers in your code. However, it is generally a bad idea to use macros for
complex operations; procedures are almost always better (for example, you can
set breakpoints inside procedures but not in the middle of macros). The only
time that it is OK to use #define's for complex operations is if the
operations are critical to performance and there is no other way to get the
performance (have you measured the performance before and after to be sure it
matters?).

When defining macros, remember always to enclose the arguments in parentheses:

|   #define Min(a,b) (((a) < (b)) ? (a) : (b))

Otherwise, if the macro is invoked with a complex argument such as a*b or
small||red it may result in a parse error or, even worse, an unintended result
that is difficult to debug.

~Documenting Code

The purpose of documentation is to save time and reduce errors. Documentation
is typically used for two purposes. First, people will read the documentation
to find out how to use your code. For example, they will read procedure
headers to learn how to call the procedures.  Ideally, people should have to
learn as little as possible about your code in order to use it correctly.
Second, people will read the documentation to find out how your code works
internally, so they can fix bugs or add new features; again, good
documentation will allow them to make their fixes or enhancements while
learning the minimum possible about your code. More documentation isn't
necessarily better: wading through pages of documentation may not be any
easier than deciphering the code. Try to pick out the most important things
that will help people to understand your code and focus on these in your
documentation.

~~Document Things with Wide Impact

The most important things to document are those that affect many different
pieces of a program. Thus it is essential that every procedure interface,
every structure declaration, and every global variable be documented clearly.
If you haven't documented one of these things it will be necessary to look at
all the uses of the thing to figure out how it's supposed to work; this will
be time-consuming and error-prone.

On the other hand, things with only local impact may not need much
documentation. For example, in short procedures I don't usually have comments
explaining the local variables. If the overall function of the procedure has
been explained, and if there isn't much code in the procedure, and if the
variables have meaningful names, then it will be easy to figure out how they
are used. On the other hand, for long procedures with many variables I usually
document the key variables. Similarly, when I write short procedures I don't
usually have any comments in the procedure's code: the procedure header
provides enough information to figure out what is going on. For long
procedures I place a comment block before each major piece of the procedure to
clarify the overall flow through the procedure.

~~Don't Just Repeat What's in the Code

The most common mistake I see in documentation (besides it not being there at
all) is that it repeats what is already obvious from the code, such as this
trivial (but exasperatingly common) example:

|   /*
|    * Increment i.
|    */
|   i += 1;

Documentation should provide higher-level information about the overall
function of the code, helping readers to understand what a complex collection
of statements really means. For example, the comment

|   /*
|    * Probe into the hash table to see if the symbol exists.
|    */

is likely to be much more helpful than

|   /*
|    * Mask off all but the lower 8 bits of x, then index into table
|    * t, then traverse the list looking for a character string
|    * identical to s.
|    */

Everything in this second comment is probably obvious from the code that
follows it. Another thing to consider in your comments is word choice. Use
different words in the comments than the words that appear in variable or
procedure names. For example, the comment

|   /*
|    * VmMapPage --
|    *

|    * Map a page.
|    * ...

which appears in the header for the Sprite procedure VmMapPage, doesn't
provide any new information. Everything in the comment is already obvious from
the procedure's name. Here is a much more useful comment:

|   /*
|    * VmMapPage --
|    *

|    * Make the given physical page addressable in the kernel's
|    * virtual address space. This procedure is used when the
|    * kernel needs to access a user's page.
|    * ...

This comment tells why you might want to use the procedure, in addition to
what it does, which makes the comment much more useful.

~~Document Each Thing in Exactly One Place

Systems evolve over time. If something is documented in several places, it
will be hard to keep the documentation up to date as the system changes.
Instead, try to document each major design decision in exactly one place, as
near as possible to the code that implements the design decision. For example,
put the documentation for each structure right next to the declaration for the
structure, including the general rules for how the structure is used. You need
not explain the fields of the structure again in the code that uses the
structure; people can always refer back to the structure declaration for this.
The principal documentation for each procedure goes in the procedure header.
There's no need to repeat this information again in the body of the procedure
(but you might have additional comments in the procedure body to fill in
details not described in the procedure header). If a library procedure is
documented thoroughly in a manual entry, then I may make the header for the
procedure very terse, simply referring to the manual entry. For example, I use
this terse form in the headers for all Tcl command procedures, since there is
a separate manual entry describing each command.

The other side of this coin is that every major design decision needs to be
documented at least once. If a design decision is used in many places, it may
be hard to pick a central place to document it. Try to find a data structure
or key procedure where you can place the main body of comments; then reference
this body in the other places where the decision is used. If all else fails,
add a block of comments to the header page of one of the files implementing
the decision.

~~Write Clean Code

The best way to produce a well-documented system is to write clean and simple
code. This way there won't be much to document. If code is clean, it means
that there are a few simple ideas that explain its operation; all you have to
do is to document those key ideas. When writing code, ask yourself if there is
a simple concept behind the code. If not, perhaps you should rethink the code.
If it takes a lot of documentation to explain a piece of code, it is a sign
that you haven't found an elegant solution to the problem.

~~Document As You Go

It is extremely important to write the documentation as you write the code.
It's very tempting to put off the documentation until the end; after all, the
code will change, so why waste time writing documentation now when you'll have
to change it later? The problem is that the end never comes - there is always
more code to write. Also, the more undocumented code that you accumulate, the
harder it is to work up the energy to document it. So, you just write more
undocumented code. I've seen many people start a project fully intending to go
back at the end and write all the documentation, but I've never seen anyone
actually do it.

If you do the documentation as you go, it won't add much to your coding time
and you won't have to worry about doing it later. Also, the best time to
document code is when the key ideas are fresh in your mind, which is when
you're first writing the code. When I write new code, I write all of the
header comments for a group of procedures before I fill in any of the bodies
of the procedures. This way I can think about the overall structure and how
the pieces fit together before getting bogged down in the details of
individual procedures.

~~Document Tricky Situations

If code is non-obvious, meaning that its structure and correctness depend on
information that won't be obvious to someone reading it for the first time, be
sure to document the non-obvious information. One good indicator of a tricky
situation is a bug. If you discover a subtle property of your program while
fixing a bug, be sure to add a comment explaining the problem and its
solution. Of course, it's even better if you can fix the bug in a way that
eliminates the subtle behavior, but this isn't always possible.

~Testing

One of the environments where Tcl works best is for testing. If all the
functionality of an application is available as Tcl commands, you should be
able to write Tcl scripts that exercise the application and verify that it
behaves correctly. For example, Tcl contains a large suite of tests that
exercise nearly all of the Tcl functionality. Whenever you write new code you
should write Tcl test scripts to go with that code and save the tests in files
so that they can be re-run later. Writing test scripts isn't as tedious as it
may sound. If you're developing your code carefully you're already doing a lot
of testing; all you need to do is type your test cases into a script file
where they can be re-used, rather than typing them interactively where they
vanish into the void after they're run.

~~Basics

Tests should be organized into script files, where each file contains a
collection of related tests. Individual tests should be based on the procedure
test, just like in the Tcl and Tk test suites. Here are two examples:

|   test expr-3.1 {floating-point operators} {
|       expr 2.3*.6
|   } 1.38
|   test expr-3.2 {floating-point operators} {
|       list [catch {expr 2.3/0} msg] $msg
|   } {1 {divide by zero}}

test is a procedure defined in a script file named defs, which is sourced by
each test file. The '''test''' command takes four arguments: a test
identifier, a string describing the test, a test script, and the expected
result of the script. test evaluates the script and checks to be sure that it
produces the expected result. If not, it prints a message like the following:

|   ==== expr-3.1 floating-point operators
|   ==== Contents of test case:
|
|       expr 2.3*.6
|
|   ==== Result was:
|   1.39
|   ---- Result should have been:
|   1.38
|   ---- expr-2.1 FAILED

To run a set of tests, you start up the application and source a test file. If
all goes well no messages appear; if errors are detected, a message is printed
for each one.

The test identifier, such as expr-3.1, is printed when errors occur. It can be
used to search a test script to locate the source for a failed test. The first
part of the identifier, such as expr, should be the same as the name of the
test file, except that the test file should have a .test extension, such as
expr.test. The two numbers allow you to divide your tests into groups. The
tests in a particular group (e.g., all the expr-3.n tests) relate to a single
sub-feature, such as a single C procedure or a single option of a Tcl
command. The tests should appear in the test file in the same order as their
numbers.

The test name, such as floating-point operators, is printed when errors occur.
It provides human-readable information about the general nature of the test.

Before writing tests I suggest that you look over some of the test files for
Tcl and Tk to see how they are structured. You may also want to look at the
README files in the Tcl and Tk test directories to learn about additional
features that provide more verbose output or restrict the set of tests that
are run.

Although it is possible to automatically generate names for tests, this is not
recommended because it makes it difficult to search for the specific test in
the test suite if all you have to go on is the test name.

~~Organizing Tests

Organize your tests to match the code being tested. The best way to do this is
to have one test file for each source code file, with the name of the test
file derived from the name of the source file in an obvious way (e.g.
textWind.test contains tests for the code in tkTextWind.c). Within the test
file, have one group of tests for each procedure (for example, all the
textWind-2.n tests in textWind.test are for the procedure TkTextWindowCmd).
The order of the tests within a group should be the same as the order of the
code within the procedure. This approach makes it easy to find the tests for a
particular piece of code and add new tests as the code changes.

The Tcl test suite was written a long time ago and uses a different style
where there is one file for each Tcl command or group of related commands, and
the tests are grouped within the file by sub-command or features. In this
approach the relationship between tests and particular pieces of code is much
less obvious, so it is harder to maintain the tests as the code evolves. I
don't recommend using this approach for new tests.

~~Coverage

When writing tests, you should attempt to exercise every line of source code
at least once. There will be occasionally be code that you can't exercise,
such as code that exits the application, but situations like this are rare.
You may find it hard to exercise some pieces of code because existing Tcl
commands don't provide fine enough control to generate all the possible
execution paths (for example, at the time I wrote the test suite for Tcl's
dynamic string facility there were very few Tcl commands using the facility;
some of the procedures were not called at all). In situations like this, write
one or more new Tcl commands just for testing purposes. For example, the file
tclTest.c in the Tcl source directory contains a command testdstring, which
provides a number of options that allow all of the dynamic string code to be
exercised. tclTest.c is only included in a special testing version of tclsh,
so the testdstring command isn't present in normal Tcl applications. Use a
similar approach in your own code, where you have an extra file with
additional commands for testing.

It's not sufficient just to make sure each line of code is executed by your
tests. In addition, your tests must discriminate between code that executes
correctly and code that isn't correct. For example, write tests to make sure
that the then and else branches of each if statement are taken under the
correct conditions. For loops, run different tests to make the loop execute
zero times, one time, and two or more times. If a piece of code removes an
element from a list, try cases where the element to be removed is the first
element, last element, only element, and neither first element nor last. Try
to find all the places where different pieces of code interact in unusual
ways, and exercise the different possible interactions.

~~Memory Allocation

Tcl and Tk use a modified memory allocator that checks for several kinds of
memory allocation errors, such as freeing a block twice, failing to free a
block, or writing past the end of a block. In order to use this allocator,
don't call malloc, free, or realloc directly. Call ckalloc instead of malloc,
ckfree instead of free, and ckrealloc instead of realloc. These procedures
behave identically to malloc, free, and realloc except that they monitor
memory usage. Ckalloc, ckfree, and ckrealloc are actually macros that can be
configured with a compiler switch: if TCL_MEM_DEBUG is defined, they perform
the checks but run more slowly and use more memory; if TCL_MEM_DEBUG is not
defined, then the macros are just #defined to malloc, free, and realloc so
there is no penalty in efficiency. I always run with TCL_MEM_DEBUG in my
development environment and you should too. Official releases typically do not
have TCL_MEM_DEBUG set.

If you set TCL_MEM_DEBUG anywhere in your code then you must set it everywhere
(including the Tcl and Tk libraries); the memory allocator will get hopelessly
confused if a block of memory is allocated with malloc and freed with ckfree,
or allocated with ckalloc and freed with free.

There is nothing equivalent to calloc in the debugging memory allocator. If
you need a new block to be zeroed, call memset to clear its contents.

If you compile with TCL_MEM_DEBUG, then an additional Tcl command named memory
will appear in your application (assuming that you're using the standard Tcl
or Tk main program). The memory command has the following options:

'''memory active''' ''file''

 > Dumps a list of all allocated blocks (and where they were allocated) to
   ''file''. Memory leaks can be tracked down by comparing dumps made at
   different times.

'''memory break_on_malloc''' ''number''

 > Enter the debugger after ''number'' calls to '''ckalloc'''.

'''memory info'''

 > Prints a report containing the total allocations and frees since Tcl began,
   the number of blocks currently allocated, the number of bytes currently
   allocated, and the maximum number of blocks and bytes allocated at any one
   time.

'''memory init''' ''onoff''

 > If ''onoff'' is on, new blocks of memory are initialized with a strange
   value to help locate uninitialized uses of the block. Any other value for
   ''onoff'' turns initialization off. Initialization is on by default.

'''memory trace''' ''onoff''

 > If ''onoff'' is on, one line will be printed to stderr for each call to
   '''ckalloc'''. Any other value for ''onoff'' turns tracing off. Tracing is
   off by default.

'''memory trace_on_at_malloc''' ''number''

 > Arranges for tracing to be turned on after ''number'' calls to
   '''ckalloc'''.

'''memory validate''' ''onoff''

 > If ''onoff'' is on, guard zones around every allocated block are checked on
   every call to '''ckalloc''' or '''ckfree''' in order to detect memory
   overruns as soon as possible. If ''onoff'' is anything other than on,
   checks are made only during '''ckfree''' calls and only for the block being
   freed. Memory validation has a very large performance impact, so it is off
   by default.

The debugging memory allocator is inferior in many ways to commercial products
like Purify, so its worth using one of the commercial products if possible.
Even so, please use '''ckalloc''' and '''ckfree''' everywhere in your code, so
that other people without access to the commercial checkers can still use the
Tcl debugging allocator.

~~Fixing Bugs

Whenever you find a bug in your code it means that the test suite wasn't
complete. As part of fixing the bug, you should add new tests that detect the
presence of the bug. I recommend writing the tests after you've located the
bug but before you fix it. That way you can verify that the bug happens before
you implement the fix and goes away afterwards, so you'll know you've really
fixed something. Use bugs to refine your testing approach: think about what
you might be able to do differently when you write tests in the future to keep
bugs like this one from going undetected.

~~Tricky Features

I also use tests as a way of illustrating the need for tricky code. If a piece
of code has an unusual structure, and particularly if the code is hard to
explain, I try to write additional tests that will fail if the code is
implemented in the obvious manner instead of using the tricky approach. This
way, if someone comes along later, doesn't understand the documentation for
the code, decides the complex structure is unnecessary, and changes the code
back to the simple (but incorrect) form, the test will fail and the person
will be able to use the test to understand why the code needs to be the way it
is. Illustrative tests are not a substitute for good documentation, but they
provide a useful addition.

~~Test Independence

Try to make tests independent of each other, so that each test can be
understood in isolation. For example, one test shouldn't depend on commands
executed in a previous test. This is important because the test suite allows
tests to be run selectively: if the tests depend on each other, then false
errors will be reported when someone runs a few of the tests without the
others.

For convenience, you may execute a few statements in the test file to set up a
test configuration and then run several tests based on that configuration. If
you do this, put the setup code outside the calls to the test procedure so it
will always run even if the individual tests aren't run. I suggest keeping a
very simple structure consisting of setup followed by a group of tests.  Don't
perform some setup, run a few tests, modify the setup slightly, run a few more
tests, modify the setup again, and so on. If you do this, it will be hard for
people to figure out what the setup is at any given point and when they add
tests later they are likely to break the setup.

~Porting Issues

The X Window System, ANSI C, and POSIX provide a standard set of interfaces
that make it possible to write highly portable code. However, some additional
work will still be needed if code is to port among all of the UNIX platforms.
As Tcl and Tk move from the UNIX world onto PCs and Macintoshes, porting
issues will become even more important. This section contains a few tips on
how to write code that can run on many different platforms.

~~Stick to Standards

The easiest way to make your code portable is to use only library interfaces
that are available everywhere (or nearly everywhere). For example, the ANSI C
library procedures, POSIX system calls, and Xlib windowing calls are available
on many platforms; if you code to these standards your packages will be quite
portable. Avoid using system-specific library procedures, since they will
introduce porting problems.

~~Minimize #ifdefs

Although there will be situations where you have to do things differently on
different machines, #ifdefs are rarely the best way to deal with these
problems. If you load up your code with #ifdef statements based on various
machines and operating systems, the code will turn into spaghetti. #ifdefs
make code unreadable: it is hard to look at #ifdef-ed code and figure out
exactly what will happen on any one machine. Furthermore, #ifdefs encourage a
style where lots of machine dependencies creep all through the code; it is
much better to isolate machine dependencies in a few well-defined places.

Thus you should almost never use #ifdefs. Instead, think carefully about the
ways in which systems differ and define procedural interfaces to the
machine-dependent code. Then provide a different implementation of the
machine-dependent procedures for each machine. When linking, choose the
version appropriate for the current machine. This way all of the machine
dependencies for a particular system are located in one or a few files that
are totally separate from the machine-dependent code for other systems and
from the main body of your code. The only "conditional" code left will be the
code that selects which version to link with.

You won't be able to eliminate #ifdefs completely, but please avoid them as
much as possible. If you end up with code that has a lot of #ifdefs, this
should be a warning to you that something is wrong. See if you can find a way
to re-organize the code (perhaps using the techniques described later in this
section) to reduce the number of #ifdefs.

~~Organize by Feature, Not by System

Don't think about porting issues in terms of specific systems. Instead, think
in terms of specific features that are present or absent in the systems. For
example, don't divide your code up according to what is needed in HP-UX versus
Solaris versus Windows. Instead, consider what features are present in the
different systems; for example, some systems have a waitpid procedure, while
others don't yet provide one, and some systems have ANSI C compilers that
support procedure prototypes, while some systems do not.

The feature-based approach has a number of advantages over the system-based
approach. First, many systems have features in common, so you can share
feature-based porting code among different systems. Second, if you think in
terms of features then you can consider each feature separately ("what do I do
if there is no waitpid?"); this replaces one large problem with several
smaller problems that can be dealt with individually. Lastly, the autoconf
program can be used to check for the presence or absence of particular
features and configure your code automatically. Once you've gotten your code
running on several different systems, you'll find that many new systems can be
handled with no additional work: their features are similar to those in
systems you've already considered, so autoconf can handle them automatically.

~~Use Emulation

One of the cleanest ways to handle porting problems is with emulation: assume
the existence of certain procedures, such as those in the POSIX standard, and
if they don't exist on a given system then write procedures to emulate the
desired functionality with the facilities that are present on the system. For
example, when Tcl first started being used widely I discovered that many
systems did not support the waitpid kernel call, even though it was part of
the POSIX standard. So, I wrote a waitpid procedure myself, which emulated the
functionality of waitpid using the wait and wait3 kernel calls. The best way
to emulate waitpid was with wait3, but unfortunately wait3 wasn't available
everywhere either, so the emulation worked differently on systems that had
wait3 and those that supported only wait. The autoconf program checks to see
which of the kernel calls are available, includes the emulation for waitpid if
it isn't available, and sets a compiler flag that indicates to the emulation
code whether or not wait3 is available.

You can also emulate using #defines in a header file. For example, not all
systems support symbolic links, and those that don't support symbolic links
don't support the lstat kernel call either. For these systems Tcl uses stat to
emulate lstat with the following statement in tclUnix.h:

|   #define lstat stat

If a header file is missing on a particular system, write your own version of
the header file to supply the definitions needed by your code. Then you can
#include your version in your code if the system doesn't have a version of its
own. For example, here is the code in tclUnix.h that handles unistd.h, which
isn't yet available on all UNIX systems:

|   #ifdef HAVE_UNISTD_H
|   #include <unistd.h>
|   #else
|   #include "compat/unistd.h"
|   #endif

The configure script generated by autoconf checks for the existence of
unistd.h in the system include directories and sets HAVE_UNISTD_H if it is
present. If it isn't present, tclUnix.h includes a version from the Tcl source
tree.

~~Use Autoconf

The GNU autoconf program provides a powerful way to configure your code for
different systems. With autoconf you write a script called configure.in that
describes the porting issues for your software in terms of particular features
that are needed and what to do if they aren't present. Before creating a
release of your software you run autoconf, which processes configure.in and
generates a shell script called configure. You then include configure with
your distribution.

When it is time to install the distribution on a particular system, the
installer runs the configure script. configure pokes around in the system to
find out what features are present, then it modifies the Makefile accordingly.
The modifications typically consist of compiling additional files to
substitute for missing procedures, or setting compiler flags that can be used
for conditional compilation in the code.

Use of libtool is not recommended; it tends to inhibit porting to anything
other than fairly conventional UNIX platforms.

~~Porting Header File

In spite of all the above advice, you will still end up needing some
conditional compilation, for example to include alternate header files where
standard ones are missing or to #define symbols that aren't defined on the
system. Put all of this code in the porting header file for the package, then
#include this header file in each of the source files of the package. With
this approach you only need to change a single place if you have to modify
your approach to portability, and you can see all of the porting issues in one
place. You can look at tclPort.h and tkPort.h for examples of porting header
files.

~Miscellaneous

~~Changes Files

Each package should contain a file named changes that keeps a log of all
significant changes made to the package. The changes file provides a way for
users to find out what's new in each new release, what bugs have been fixed,
and what compatibility problems might be introduced by the new release. The
changes file should be in chronological order.  Just add short blurbs to it
each time you make a change. Here is a sample from the Tk changes file:

|   5/19/94 (bug fix) Canvases didn't generate proper Postscript for
|   stippled text.
|
|   5/20/94 (new feature) Added "bell" command to ring the display's bell.
|
|   5/26/94 (feature removed) Removed support for "fill" justify mode
|   from Tk_GetJustify and from the TK_CONFIG_JUSTIFY configuration
|   option. None of the built-in widgets ever supported this mode
|   anyway.
|   *** POTENTIAL INCOMPATIBILITY ***

The entries in the changes file can be relatively terse; once someone finds a
change that is relevant, they can always go to the manual entries or code to
find out more about it. Be sure to highlight changes that cause compatibility
problems, so people can scan the changes file quickly to locate the
incompatibilities.

''(The Tcl and Tk core additionally uses a ChangeLog file that has a much
higher detail within it. This has the advantage of having more tooling
support, but tends to be so verbose that the shorter summaries in the changes
file are still written up by the core maintainers before each release.)''

~ Copyright

This document has been placed in the public domain.








|
|

|


|





|
|












|


|


|
|














|
|



|





|


















|







|
|

|
|




|

|


|



|


|
|


|








|
|
|





|




|

|
|



|
|

|
|
|


|


|

|




|
|
|


|






|














|
|







|






|

|








|




|








|


|




|





|







|

|

|




|






|
|
|
|

|







|




|


|
|

|

|





|



|
|
|




|



|
|
<
>






|



|
|
|
|
|
|
|
|
<
|
>
|



|
|




|



|

|

|


|
|
|

|
|



|

|
|


|















|




















|

|
|
|

|
|
|
|





|
|
|



|
|
|
|
|






|
|
<
>
|
|





|
|
<
>
|
|
|
|




|











|
|













|









|




















|









|













|





|
|
|
|
|
|


|




|
|
|
|
|
|
|
|
|
|










|

















|



|
|
|
|











|






|

|



















|








|
|
|
|

|

|
|






|
|
|

|

|
|


|

|

|






|

|

|

|

|
|


|

|
|

|

|
|
|
|





|



|










|







|




|


















|








|


|





|


|
|
|
|
|



|









|
|

|
|

|












|
|







|
















|




|



|



|
|
|
|
|


|



|



















|



|

|





|

|








|
|
|
|
|
|
|
|
|
|







|


|

|


>
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696

697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715

716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824

825
826
827
828
829
830
831
832
833
834

835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
    section should not describe every internal variable modified by the
    procedure. It should simply provide the sort of information that users of
    the procedure need in order to use the procedure correctly. See Figure 4
    for an example.

The file engManual/prochead contains a template for a procedure header, which
you can include from your editor to save typing. Follow the syntax of Figures
3 and 4 exactly \(same indentation, double-dash after the procedure name,
etc.\).

The Results and Side Effects parts of the header may be omitted _only_ if
the function has no results or side effects respectively.

## Procedure Declarations

The procedure declaration should also follow exactly the syntax in Figures 3
and 4. The first line gives the type of the procedure's result. All procedures
must be typed: use void if the procedure returns no result. The second line
gives the procedure's name and its argument list. If there are many arguments,
they may spill onto additional lines \(see Sections 5.1 and 5.5 for information
about indentation\). After this come the declarations of argument types, one
argument per line, indented, with a comment after each argument giving a brief
description of the argument. Every argument must be explicitly declared, and
every argument must have a comment.

This form for argument declarations is the old form that predates ANSI C. It's
important to use the old form so that your code will compile on older pre-ANSI
compilers. Hopefully there aren't too many of these compilers left, and
perhaps in a few years we can switch to the ANSI form, but for now let's be
safe. Every procedure should also have an ANSI-style prototype either on the
file's header page or in a header file, so this approach still allows full
argument checking.

_Note that_ for new code it is preferred to use ANSI declarations,
especially if the code will not build on non-ANSI compilers.

## Parameter Order

Procedure parameters may be divided into three categories. In parameters only
pass information into the procedure \(either directly or by pointing to
information that the procedure reads\). Out parameters point to things in the
caller's memory that the procedure modifies. In-out parameters do both. Below
is a set of rules for deciding on the order of parameters to a procedure:

 1. Parameters should normally appear in the order in, in/out, out, except
    where overridden by the rules below.

 2. If there is a group of procedures, all of which operate on structures of a
    particular type, such as a hash table, the token for the structure should
    be the first argument to each of the procedures.

 3. When two parameters are the address of a callback procedure and a
    ClientData value to pass to that procedure, the procedure address should
    appear in the argument list immediately before the ClientData.

 4. If a callback procedure takes a ClientData argument \(and all callbacks
    should\), the ClientData argument should be the first argument to the
    procedure. Typically the ClientData is a pointer to the structure managed
    by the callback, so this is really the same as rule 2.

## Procedure Bodies

The body of a procedure follows the declaration. See Section 5 for the coding
conventions that govern procedure bodies. The curly braces enclosing the body
should be on separate lines as shown in Figures 3 and 4.

# Naming Conventions

Choosing names is one of the most important aspects of programming. Good names
clarify the function of a program and reduce the need for other documentation.
Poor names result in ambiguity, confusion, and error. For example, in the
Sprite operating system we spent four months tracking down a subtle problem
with the file system that caused seemingly random blocks on disk to be
overwritten from time to time. It turned out that the same variable name was
used in some places to refer to physical blocks on disk, and in other places
to logical blocks in a file; unfortunately, in one place the variable was
accidentally used for the wrong purpose. The bug probably would not have
occurred if different variable names had been used for the two kinds of block
identifiers.

This section gives some general principles to follow when choosing names, then
lists specific rules for name syntax, such as capitalization, and finally
describes how to use package prefixes to clarify the module structure of your
code.

## General Considerations

The ideal variable name is one that instantly conveys as much information as
possible about the purpose of the variable it refers to. When choosing names,
play devil's advocate with yourself to see if there are ways that a name might
be misinterpreted or confused. Here are some things to consider:

 1. Are you consistent? Use the same name to refer to the same thing
    everywhere. For example, in the Tcl implementation the name _interp_ is
    used consistently for pointers to the uservisible Tcl\_Interp structure.
    Within the code for each widget, a standard name is always used for a
    pointer to the widget record, such as _butPtr_ in the button widget code
    and _menuPtr_ in the menu widget code.

 2. If someone sees the name out of context, will they realize what it stands
    for, or could they confuse it with something else? For example, in Sprite
    the procedure for doing byte-swapping and other format conversion was
    originally called Swap\_Buffer. When I first saw that name I assumed it had
    something to do with I/O buffer management, not reformatting. We
    subsequently changed the name to Fmt\_Convert.

 3. Could this name be confused with some other name? For example, it's
    probably a mistake to have two variables _s_ and _string_ in the same
    procedure, both referring to strings: it will be hard for anyone to
    remember which is which. Instead, change the names to reflect their
    functions. For example, if the strings are used as source and destination
    for a copy operation, name them _src_ and _dst_.

 4. Is the name so generic that it doesn't convey any information? The
    variable _s_ from the previous paragraph is an example of this; changing
    its name to _src_ makes the name less generic and hence conveys more
    information.

## Basic Syntax Rules

Below are some specific rules governing the syntax of names. Please follow the
rules exactly, since they make it possible to determine certain properties of
a variable just from its name.

 1. Variable names always start with a lower-case letter. Procedure and type
    names always start with an upper-case letter.

		   int counter;
		   extern char *FindElement();
		   typedef int Boolean;

 2. In multi-word names, the first letter of each trailing word is
    capitalized. Do not use underscores as separators between the words of a
    name, except as described in rule 5 below and in Section 4.3.

		   int numWindows;

 3. Any name that refers to a pointer ends in Ptr. If the name refers to a
    pointer to a pointer, then it ends in PtrPtr, and so on. There are two
    exceptions to this rule. The first is for variables that are opaque
    handles for structures, such as variables of type Tk\_Window. These
    variables are actually pointers, but they are never dereferenced outside
    Tk \(clients can never look at the structure they point to except by
    invoking Tk macros and procedures\). In this case the Ptr is omitted in
    variable names. The second exception to the rule is for strings. We
    decided in Sprite not to require Ptr suffixes for strings, since they are
    always referenced with pointers. However, if a variable holds a pointer to
    a string pointer, then it must have the Ptr suffix \(there's just one less
    level of Ptr for strings than for other structures\).

		   TkWindow *winPtr;
		   char *name;
		   char **namePtr;

 4. Variables that hold the addresses of functions should have names ending in
    Proc \(for "procedure"\). Typedefs for these variables should also have
    names ending in Proc.

		   typedef void (Tk_ImageDeleteProc)(ClientData clientData);

 5. \#defined constants and macros have names that are all capital letters,
    except for macros that are used as replacements for procedures, in which
    case you should follow the naming conventions for procedures. If names in
    all caps contain multiple words, use underscores to separate the words.

		   #define NULL 0
		   #define BUFFER_SIZE 1024
		   #define Min(a,b) (((a) < (b)) ? (a) : (b))

 6. Names of programs, Tcl commands, and keyword arguments to Tcl commands
    \(such as Tk configuration options\) are usually entirely in lower case, in
    spite of the rules above. The reason for this rule is that these names are
    likely to typed interactively, and I thought that using all lower case
    would make it easier to type them. In retrospect I'm not sure this was a
    good idea; in any case, Tcl procedure and variable names should follow the
    same rules as C procedures and variables.

## Names Reflect Package Structure

Names that are exported outside a single file must include the package prefix
in order to make sure that they don't conflict with global names defined in
other packages. The following rules define how to use package prefixes in
names:

 1. If a variable or procedure or type is exported by its package, the first
    letters of its name must consist of the package prefix followed by an
    underscore. Only the first letter of the prefix is ever capitalized, and
    it is subject to the capitalization rules from Section 4.2. The first
    letter after the prefix is always capitalized. The first example below
    shows an exported variable, and the second shows an exported type and
    exported procedure.

		   extern int tk_numMainWindows;
		   extern Tcl_Interp *Tcl_CreateInterp(void);

 2. If a module contains several files, and if a name is used in several of
    those files but isn't used outside the package, then the name must have
    the package prefix but no underscore. The prefix guarantees that the name
    won't conflict with a similar name from a different package; the missing
    underscore indicates that the name is private to the package.

		   extern void TkEventDeadWindow(TkWindow *winPtr);

 3. If a name is only used within a single procedure or file, then it need not
    have the module prefix. To avoid conflicts with similar names in other
    files, variables and procedures declared outside procedures must always be
    declared static if they have no module prefix.

		   static int initialized;

## Standard Names

The following variable names are used consistently throughout Tcl and Tk.
Please use these names for the given purposes in any code you write, and don't
use the names for other purposes.

 clientData: Used for variables of type ClientData, which are associated with
    callback procedures.

 interp: Used for variables of type Tcl\_Interp. These are the \(mostly\) opaque
    handles for interpreters that are given to Tcl clients. These variables
    should really have a Ptr extension, but the name was chosen at a time when
    interpreters were totally opaque to clients.

 iPtr: Used for variables of type Interp \*, which are pointers to Tcl's
    internal structures for interpreters. Tcl procedures often have an
    argument named interp, which is copied into a local variable named iPtr in
    order to access the contents of the interpreter.

 nextPtr: A field with this name is used in structures to point to the next
    structure in a linked list. This is usally the last field of the
    structure.

 tkwin: Used for variables of type Tk\_Window, which are opaque handles for the
    window structures managed by Tk.

 winPtr: Used for variables of type TkWindow \*, which are pointers to Tk's
    internal structures for windows. Tk procedures often take an argument
    named tkwin and immediately copy the argument into a local variable named
    winPtr in order to access the contents of the window structure.

# Low-Level Coding Conventions

This section describes several low-level syntactic rules for writing C code.
The reason for having these rules is not because they're better than all other
ways of structuring code, but in order to make all our code look the same.

## Indents are 4 Spaces

Each level of indentation should be four spaces. There are ways to set 4-space
indents in all editors that I know of. Be sure that your editor really uses
four spaces for the indent, rather than just displaying tabs as four spaces
wide; if you use the latter approach then the indents will appear eight spaces
wide in other editors.

If you use tabs, they _must_ be to 8-space indents.

## Code Comments Occupy Full Lines

Comments that document code \(as opposed to declarations\) should occupy full
lines, rather than being tacked onto the ends of lines containing code. The
reason for this is that side-byside comments are hard to see, particularly if
neighboring statements are long enough to overlap the side-by-side comments.
Comments must have exactly the structure shown in Figure 5, including a
leading /\* line, a trailing \*/ line, and additional blank lines above and
below. The leading blank line can be omitted if the comment is at the
beginning of a block, as is the case in the second comment in Figure 5. Each
comment should be indented to the same level as the surrounding code. Use
proper English in comments: write complete sentences, capitalize the first
word of each sentence, and so on.

![Figure 5. Comments in code have the form shown above, using](../assets/247fig5.png)
full lines, with lined-up stars, the /\* and \*/ symbols on separate lines, and
blank separator lines around each comment \(except that the leading blank line
can be omitted if the comment is at the beginning of a code block\).

## Declaration Comments are Side-By-Side

When documenting the arguments for procedures and the members of structures,
place the comments on the same lines as the declarations. Figures 3 and 4 show
comments for procedure arguments and Figure 6 shows a simple structure
declaration. The format for comments is the same in both cases. Place the
comments to the right of the declarations, with all the left edges of all the
comments lined up. When a comment requires more than one line, indent the
additional lines to the same level as the first line, with the closing \*/ on
the same line as the end of the text. For structure declarations it is usually
useful to have a block of comments preceding the declaration, as in Figure
6. This comments before the declaration use the format given in Section 5.2.

![Figure 6. Use side-by-side comments when declaring structure](../assets/247fig6.png)
members and procedure arguments.

Declaration comments should normally begin in the 33rd column \(i.e. where you
would be after 32 spaces or 4 tabs\).

## Curly Braces: \{ Goes at the End of a Line

Open curly braces should not \(normally\) appear on lines by themselves.
Instead, they should be placed at the end of the preceding line. Close curly
braces always appear as the first non-blank character on a line. Figure 5
shows how to use curly braces in statements such as if and while, and Figure 6
shows how curly braces should be used in structure declarations. If an if
statement has an else clause then else appears on the same line as the
preceding \} and the following \{. Close curly braces are indented to the same
level as the outer code, i.e., four spaces less than the statements they
enclose.

The only cases where a \{ appears on a line by itself are the initial \{ for the
body of a procedure \(see Figures 3 and 4\) or where a block is being started
_without_ being the body of an if, do, for, while or switch construct.

Always use curly braces around compound statements, even if there is only one
statement in the block. Thus you shouldn't write code like

	   if (filePtr->numLines == 0) return -1;

but rather

	   if (filePtr->numLines == 0) {
	       return -1;

	   }

This approach makes code less dense, but it avoids potential mistakes when
adding additional lines to an existing single-statement block. It also makes
it easier to set breakpoints in a debugger, since it guarantees that each
statement on is on a separate line and can be named individually.

There is one exception to the rule about enclosing blocks in \{\}. For if
statements with cascaded else if clauses, you may use a form like the
following:

	   if (strcmp(argv[1], "delete") == 0) {
	       ...
	   } else if (strcmp(argv[1], "get") == 0) {
	       ...
	   } else if (strcmp(argv[1], "set") == 0) {
	       ...
	   } else {
	       ...

	   }

## Continuation Lines are Indented 8 Spaces

You should use continuation lines to make sure that no single line exceeds 80
characters in length. Continuation lines should be indented 8 spaces so that
they won't be confused with an immediately-following nested block \(see Figure
7\). Pick clean places to break your lines for continuation, so that the
continuation doesn't obscure the structure of the statement. For example, if a
procedure call requires continuation lines, make sure that each argument is on
a single line. If the test for an if or while command spans lines, try to make
each line have the same nesting level of parentheses if possible. I try to
start each continuation line with an operator such as \*, &&, or \|\|; this makes
it clear that the line is a continuation, since a new statement would never
start with such an operator.

![Figure 7. Continuation lines are indented 8 spaces.](../assets/247fig7.png)

## Avoid Macros Except for Simple Things

\#define statements provide a fine mechanism for specifying constants
symbolically, and you should always use them instead of embedding specific
numbers in your code. However, it is generally a bad idea to use macros for
complex operations; procedures are almost always better \(for example, you can
set breakpoints inside procedures but not in the middle of macros\). The only
time that it is OK to use \#define's for complex operations is if the
operations are critical to performance and there is no other way to get the
performance \(have you measured the performance before and after to be sure it
matters?\).

When defining macros, remember always to enclose the arguments in parentheses:

	   #define Min(a,b) (((a) < (b)) ? (a) : (b))

Otherwise, if the macro is invoked with a complex argument such as a\*b or
small\|\|red it may result in a parse error or, even worse, an unintended result
that is difficult to debug.

# Documenting Code

The purpose of documentation is to save time and reduce errors. Documentation
is typically used for two purposes. First, people will read the documentation
to find out how to use your code. For example, they will read procedure
headers to learn how to call the procedures.  Ideally, people should have to
learn as little as possible about your code in order to use it correctly.
Second, people will read the documentation to find out how your code works
internally, so they can fix bugs or add new features; again, good
documentation will allow them to make their fixes or enhancements while
learning the minimum possible about your code. More documentation isn't
necessarily better: wading through pages of documentation may not be any
easier than deciphering the code. Try to pick out the most important things
that will help people to understand your code and focus on these in your
documentation.

## Document Things with Wide Impact

The most important things to document are those that affect many different
pieces of a program. Thus it is essential that every procedure interface,
every structure declaration, and every global variable be documented clearly.
If you haven't documented one of these things it will be necessary to look at
all the uses of the thing to figure out how it's supposed to work; this will
be time-consuming and error-prone.

On the other hand, things with only local impact may not need much
documentation. For example, in short procedures I don't usually have comments
explaining the local variables. If the overall function of the procedure has
been explained, and if there isn't much code in the procedure, and if the
variables have meaningful names, then it will be easy to figure out how they
are used. On the other hand, for long procedures with many variables I usually
document the key variables. Similarly, when I write short procedures I don't
usually have any comments in the procedure's code: the procedure header
provides enough information to figure out what is going on. For long
procedures I place a comment block before each major piece of the procedure to
clarify the overall flow through the procedure.

## Don't Just Repeat What's in the Code

The most common mistake I see in documentation \(besides it not being there at
all\) is that it repeats what is already obvious from the code, such as this
trivial \(but exasperatingly common\) example:

	   /*
	    * Increment i.
	    */
	   i += 1;

Documentation should provide higher-level information about the overall
function of the code, helping readers to understand what a complex collection
of statements really means. For example, the comment

	   /*
	    * Probe into the hash table to see if the symbol exists.
	    */

is likely to be much more helpful than

	   /*
	    * Mask off all but the lower 8 bits of x, then index into table
	    * t, then traverse the list looking for a character string
	    * identical to s.
	    */

Everything in this second comment is probably obvious from the code that
follows it. Another thing to consider in your comments is word choice. Use
different words in the comments than the words that appear in variable or
procedure names. For example, the comment

	   /*
	    * VmMapPage --

	    *
	    * Map a page.
	    * ...

which appears in the header for the Sprite procedure VmMapPage, doesn't
provide any new information. Everything in the comment is already obvious from
the procedure's name. Here is a much more useful comment:

	   /*
	    * VmMapPage --

	    *
	    * Make the given physical page addressable in the kernel's
	    * virtual address space. This procedure is used when the
	    * kernel needs to access a user's page.
	    * ...

This comment tells why you might want to use the procedure, in addition to
what it does, which makes the comment much more useful.

## Document Each Thing in Exactly One Place

Systems evolve over time. If something is documented in several places, it
will be hard to keep the documentation up to date as the system changes.
Instead, try to document each major design decision in exactly one place, as
near as possible to the code that implements the design decision. For example,
put the documentation for each structure right next to the declaration for the
structure, including the general rules for how the structure is used. You need
not explain the fields of the structure again in the code that uses the
structure; people can always refer back to the structure declaration for this.
The principal documentation for each procedure goes in the procedure header.
There's no need to repeat this information again in the body of the procedure
\(but you might have additional comments in the procedure body to fill in
details not described in the procedure header\). If a library procedure is
documented thoroughly in a manual entry, then I may make the header for the
procedure very terse, simply referring to the manual entry. For example, I use
this terse form in the headers for all Tcl command procedures, since there is
a separate manual entry describing each command.

The other side of this coin is that every major design decision needs to be
documented at least once. If a design decision is used in many places, it may
be hard to pick a central place to document it. Try to find a data structure
or key procedure where you can place the main body of comments; then reference
this body in the other places where the decision is used. If all else fails,
add a block of comments to the header page of one of the files implementing
the decision.

## Write Clean Code

The best way to produce a well-documented system is to write clean and simple
code. This way there won't be much to document. If code is clean, it means
that there are a few simple ideas that explain its operation; all you have to
do is to document those key ideas. When writing code, ask yourself if there is
a simple concept behind the code. If not, perhaps you should rethink the code.
If it takes a lot of documentation to explain a piece of code, it is a sign
that you haven't found an elegant solution to the problem.

## Document As You Go

It is extremely important to write the documentation as you write the code.
It's very tempting to put off the documentation until the end; after all, the
code will change, so why waste time writing documentation now when you'll have
to change it later? The problem is that the end never comes - there is always
more code to write. Also, the more undocumented code that you accumulate, the
harder it is to work up the energy to document it. So, you just write more
undocumented code. I've seen many people start a project fully intending to go
back at the end and write all the documentation, but I've never seen anyone
actually do it.

If you do the documentation as you go, it won't add much to your coding time
and you won't have to worry about doing it later. Also, the best time to
document code is when the key ideas are fresh in your mind, which is when
you're first writing the code. When I write new code, I write all of the
header comments for a group of procedures before I fill in any of the bodies
of the procedures. This way I can think about the overall structure and how
the pieces fit together before getting bogged down in the details of
individual procedures.

## Document Tricky Situations

If code is non-obvious, meaning that its structure and correctness depend on
information that won't be obvious to someone reading it for the first time, be
sure to document the non-obvious information. One good indicator of a tricky
situation is a bug. If you discover a subtle property of your program while
fixing a bug, be sure to add a comment explaining the problem and its
solution. Of course, it's even better if you can fix the bug in a way that
eliminates the subtle behavior, but this isn't always possible.

# Testing

One of the environments where Tcl works best is for testing. If all the
functionality of an application is available as Tcl commands, you should be
able to write Tcl scripts that exercise the application and verify that it
behaves correctly. For example, Tcl contains a large suite of tests that
exercise nearly all of the Tcl functionality. Whenever you write new code you
should write Tcl test scripts to go with that code and save the tests in files
so that they can be re-run later. Writing test scripts isn't as tedious as it
may sound. If you're developing your code carefully you're already doing a lot
of testing; all you need to do is type your test cases into a script file
where they can be re-used, rather than typing them interactively where they
vanish into the void after they're run.

## Basics

Tests should be organized into script files, where each file contains a
collection of related tests. Individual tests should be based on the procedure
test, just like in the Tcl and Tk test suites. Here are two examples:

	   test expr-3.1 {floating-point operators} {
	       expr 2.3*.6
	   } 1.38
	   test expr-3.2 {floating-point operators} {
	       list [catch {expr 2.3/0} msg] $msg
	   } {1 {divide by zero}}

test is a procedure defined in a script file named defs, which is sourced by
each test file. The **test** command takes four arguments: a test
identifier, a string describing the test, a test script, and the expected
result of the script. test evaluates the script and checks to be sure that it
produces the expected result. If not, it prints a message like the following:

	   ==== expr-3.1 floating-point operators
	   ==== Contents of test case:
	
	       expr 2.3*.6
	
	   ==== Result was:
	   1.39
	   ---- Result should have been:
	   1.38
	   ---- expr-2.1 FAILED

To run a set of tests, you start up the application and source a test file. If
all goes well no messages appear; if errors are detected, a message is printed
for each one.

The test identifier, such as expr-3.1, is printed when errors occur. It can be
used to search a test script to locate the source for a failed test. The first
part of the identifier, such as expr, should be the same as the name of the
test file, except that the test file should have a .test extension, such as
expr.test. The two numbers allow you to divide your tests into groups. The
tests in a particular group \(e.g., all the expr-3.n tests\) relate to a single
sub-feature, such as a single C procedure or a single option of a Tcl
command. The tests should appear in the test file in the same order as their
numbers.

The test name, such as floating-point operators, is printed when errors occur.
It provides human-readable information about the general nature of the test.

Before writing tests I suggest that you look over some of the test files for
Tcl and Tk to see how they are structured. You may also want to look at the
README files in the Tcl and Tk test directories to learn about additional
features that provide more verbose output or restrict the set of tests that
are run.

Although it is possible to automatically generate names for tests, this is not
recommended because it makes it difficult to search for the specific test in
the test suite if all you have to go on is the test name.

## Organizing Tests

Organize your tests to match the code being tested. The best way to do this is
to have one test file for each source code file, with the name of the test
file derived from the name of the source file in an obvious way \(e.g.
textWind.test contains tests for the code in tkTextWind.c\). Within the test
file, have one group of tests for each procedure \(for example, all the
textWind-2.n tests in textWind.test are for the procedure TkTextWindowCmd\).
The order of the tests within a group should be the same as the order of the
code within the procedure. This approach makes it easy to find the tests for a
particular piece of code and add new tests as the code changes.

The Tcl test suite was written a long time ago and uses a different style
where there is one file for each Tcl command or group of related commands, and
the tests are grouped within the file by sub-command or features. In this
approach the relationship between tests and particular pieces of code is much
less obvious, so it is harder to maintain the tests as the code evolves. I
don't recommend using this approach for new tests.

## Coverage

When writing tests, you should attempt to exercise every line of source code
at least once. There will be occasionally be code that you can't exercise,
such as code that exits the application, but situations like this are rare.
You may find it hard to exercise some pieces of code because existing Tcl
commands don't provide fine enough control to generate all the possible
execution paths \(for example, at the time I wrote the test suite for Tcl's
dynamic string facility there were very few Tcl commands using the facility;
some of the procedures were not called at all\). In situations like this, write
one or more new Tcl commands just for testing purposes. For example, the file
tclTest.c in the Tcl source directory contains a command testdstring, which
provides a number of options that allow all of the dynamic string code to be
exercised. tclTest.c is only included in a special testing version of tclsh,
so the testdstring command isn't present in normal Tcl applications. Use a
similar approach in your own code, where you have an extra file with
additional commands for testing.

It's not sufficient just to make sure each line of code is executed by your
tests. In addition, your tests must discriminate between code that executes
correctly and code that isn't correct. For example, write tests to make sure
that the then and else branches of each if statement are taken under the
correct conditions. For loops, run different tests to make the loop execute
zero times, one time, and two or more times. If a piece of code removes an
element from a list, try cases where the element to be removed is the first
element, last element, only element, and neither first element nor last. Try
to find all the places where different pieces of code interact in unusual
ways, and exercise the different possible interactions.

## Memory Allocation

Tcl and Tk use a modified memory allocator that checks for several kinds of
memory allocation errors, such as freeing a block twice, failing to free a
block, or writing past the end of a block. In order to use this allocator,
don't call malloc, free, or realloc directly. Call ckalloc instead of malloc,
ckfree instead of free, and ckrealloc instead of realloc. These procedures
behave identically to malloc, free, and realloc except that they monitor
memory usage. Ckalloc, ckfree, and ckrealloc are actually macros that can be
configured with a compiler switch: if TCL\_MEM\_DEBUG is defined, they perform
the checks but run more slowly and use more memory; if TCL\_MEM\_DEBUG is not
defined, then the macros are just \#defined to malloc, free, and realloc so
there is no penalty in efficiency. I always run with TCL\_MEM\_DEBUG in my
development environment and you should too. Official releases typically do not
have TCL\_MEM\_DEBUG set.

If you set TCL\_MEM\_DEBUG anywhere in your code then you must set it everywhere
\(including the Tcl and Tk libraries\); the memory allocator will get hopelessly
confused if a block of memory is allocated with malloc and freed with ckfree,
or allocated with ckalloc and freed with free.

There is nothing equivalent to calloc in the debugging memory allocator. If
you need a new block to be zeroed, call memset to clear its contents.

If you compile with TCL\_MEM\_DEBUG, then an additional Tcl command named memory
will appear in your application \(assuming that you're using the standard Tcl
or Tk main program\). The memory command has the following options:

**memory active** _file_

 > Dumps a list of all allocated blocks \(and where they were allocated\) to
   _file_. Memory leaks can be tracked down by comparing dumps made at
   different times.

**memory break\_on\_malloc** _number_

 > Enter the debugger after _number_ calls to **ckalloc**.

**memory info**

 > Prints a report containing the total allocations and frees since Tcl began,
   the number of blocks currently allocated, the number of bytes currently
   allocated, and the maximum number of blocks and bytes allocated at any one
   time.

**memory init** _onoff_

 > If _onoff_ is on, new blocks of memory are initialized with a strange
   value to help locate uninitialized uses of the block. Any other value for
   _onoff_ turns initialization off. Initialization is on by default.

**memory trace** _onoff_

 > If _onoff_ is on, one line will be printed to stderr for each call to
   **ckalloc**. Any other value for _onoff_ turns tracing off. Tracing is
   off by default.

**memory trace\_on\_at\_malloc** _number_

 > Arranges for tracing to be turned on after _number_ calls to
   **ckalloc**.

**memory validate** _onoff_

 > If _onoff_ is on, guard zones around every allocated block are checked on
   every call to **ckalloc** or **ckfree** in order to detect memory
   overruns as soon as possible. If _onoff_ is anything other than on,
   checks are made only during **ckfree** calls and only for the block being
   freed. Memory validation has a very large performance impact, so it is off
   by default.

The debugging memory allocator is inferior in many ways to commercial products
like Purify, so its worth using one of the commercial products if possible.
Even so, please use **ckalloc** and **ckfree** everywhere in your code, so
that other people without access to the commercial checkers can still use the
Tcl debugging allocator.

## Fixing Bugs

Whenever you find a bug in your code it means that the test suite wasn't
complete. As part of fixing the bug, you should add new tests that detect the
presence of the bug. I recommend writing the tests after you've located the
bug but before you fix it. That way you can verify that the bug happens before
you implement the fix and goes away afterwards, so you'll know you've really
fixed something. Use bugs to refine your testing approach: think about what
you might be able to do differently when you write tests in the future to keep
bugs like this one from going undetected.

## Tricky Features

I also use tests as a way of illustrating the need for tricky code. If a piece
of code has an unusual structure, and particularly if the code is hard to
explain, I try to write additional tests that will fail if the code is
implemented in the obvious manner instead of using the tricky approach. This
way, if someone comes along later, doesn't understand the documentation for
the code, decides the complex structure is unnecessary, and changes the code
back to the simple \(but incorrect\) form, the test will fail and the person
will be able to use the test to understand why the code needs to be the way it
is. Illustrative tests are not a substitute for good documentation, but they
provide a useful addition.

## Test Independence

Try to make tests independent of each other, so that each test can be
understood in isolation. For example, one test shouldn't depend on commands
executed in a previous test. This is important because the test suite allows
tests to be run selectively: if the tests depend on each other, then false
errors will be reported when someone runs a few of the tests without the
others.

For convenience, you may execute a few statements in the test file to set up a
test configuration and then run several tests based on that configuration. If
you do this, put the setup code outside the calls to the test procedure so it
will always run even if the individual tests aren't run. I suggest keeping a
very simple structure consisting of setup followed by a group of tests.  Don't
perform some setup, run a few tests, modify the setup slightly, run a few more
tests, modify the setup again, and so on. If you do this, it will be hard for
people to figure out what the setup is at any given point and when they add
tests later they are likely to break the setup.

# Porting Issues

The X Window System, ANSI C, and POSIX provide a standard set of interfaces
that make it possible to write highly portable code. However, some additional
work will still be needed if code is to port among all of the UNIX platforms.
As Tcl and Tk move from the UNIX world onto PCs and Macintoshes, porting
issues will become even more important. This section contains a few tips on
how to write code that can run on many different platforms.

## Stick to Standards

The easiest way to make your code portable is to use only library interfaces
that are available everywhere \(or nearly everywhere\). For example, the ANSI C
library procedures, POSIX system calls, and Xlib windowing calls are available
on many platforms; if you code to these standards your packages will be quite
portable. Avoid using system-specific library procedures, since they will
introduce porting problems.

## Minimize \#ifdefs

Although there will be situations where you have to do things differently on
different machines, \#ifdefs are rarely the best way to deal with these
problems. If you load up your code with \#ifdef statements based on various
machines and operating systems, the code will turn into spaghetti. \#ifdefs
make code unreadable: it is hard to look at \#ifdef-ed code and figure out
exactly what will happen on any one machine. Furthermore, \#ifdefs encourage a
style where lots of machine dependencies creep all through the code; it is
much better to isolate machine dependencies in a few well-defined places.

Thus you should almost never use \#ifdefs. Instead, think carefully about the
ways in which systems differ and define procedural interfaces to the
machine-dependent code. Then provide a different implementation of the
machine-dependent procedures for each machine. When linking, choose the
version appropriate for the current machine. This way all of the machine
dependencies for a particular system are located in one or a few files that
are totally separate from the machine-dependent code for other systems and
from the main body of your code. The only "conditional" code left will be the
code that selects which version to link with.

You won't be able to eliminate \#ifdefs completely, but please avoid them as
much as possible. If you end up with code that has a lot of \#ifdefs, this
should be a warning to you that something is wrong. See if you can find a way
to re-organize the code \(perhaps using the techniques described later in this
section\) to reduce the number of \#ifdefs.

## Organize by Feature, Not by System

Don't think about porting issues in terms of specific systems. Instead, think
in terms of specific features that are present or absent in the systems. For
example, don't divide your code up according to what is needed in HP-UX versus
Solaris versus Windows. Instead, consider what features are present in the
different systems; for example, some systems have a waitpid procedure, while
others don't yet provide one, and some systems have ANSI C compilers that
support procedure prototypes, while some systems do not.

The feature-based approach has a number of advantages over the system-based
approach. First, many systems have features in common, so you can share
feature-based porting code among different systems. Second, if you think in
terms of features then you can consider each feature separately \("what do I do
if there is no waitpid?"\); this replaces one large problem with several
smaller problems that can be dealt with individually. Lastly, the autoconf
program can be used to check for the presence or absence of particular
features and configure your code automatically. Once you've gotten your code
running on several different systems, you'll find that many new systems can be
handled with no additional work: their features are similar to those in
systems you've already considered, so autoconf can handle them automatically.

## Use Emulation

One of the cleanest ways to handle porting problems is with emulation: assume
the existence of certain procedures, such as those in the POSIX standard, and
if they don't exist on a given system then write procedures to emulate the
desired functionality with the facilities that are present on the system. For
example, when Tcl first started being used widely I discovered that many
systems did not support the waitpid kernel call, even though it was part of
the POSIX standard. So, I wrote a waitpid procedure myself, which emulated the
functionality of waitpid using the wait and wait3 kernel calls. The best way
to emulate waitpid was with wait3, but unfortunately wait3 wasn't available
everywhere either, so the emulation worked differently on systems that had
wait3 and those that supported only wait. The autoconf program checks to see
which of the kernel calls are available, includes the emulation for waitpid if
it isn't available, and sets a compiler flag that indicates to the emulation
code whether or not wait3 is available.

You can also emulate using \#defines in a header file. For example, not all
systems support symbolic links, and those that don't support symbolic links
don't support the lstat kernel call either. For these systems Tcl uses stat to
emulate lstat with the following statement in tclUnix.h:

	   #define lstat stat

If a header file is missing on a particular system, write your own version of
the header file to supply the definitions needed by your code. Then you can
\#include your version in your code if the system doesn't have a version of its
own. For example, here is the code in tclUnix.h that handles unistd.h, which
isn't yet available on all UNIX systems:

	   #ifdef HAVE_UNISTD_H
	   #include <unistd.h>
	   #else
	   #include "compat/unistd.h"
	   #endif

The configure script generated by autoconf checks for the existence of
unistd.h in the system include directories and sets HAVE\_UNISTD\_H if it is
present. If it isn't present, tclUnix.h includes a version from the Tcl source
tree.

## Use Autoconf

The GNU autoconf program provides a powerful way to configure your code for
different systems. With autoconf you write a script called configure.in that
describes the porting issues for your software in terms of particular features
that are needed and what to do if they aren't present. Before creating a
release of your software you run autoconf, which processes configure.in and
generates a shell script called configure. You then include configure with
your distribution.

When it is time to install the distribution on a particular system, the
installer runs the configure script. configure pokes around in the system to
find out what features are present, then it modifies the Makefile accordingly.
The modifications typically consist of compiling additional files to
substitute for missing procedures, or setting compiler flags that can be used
for conditional compilation in the code.

Use of libtool is not recommended; it tends to inhibit porting to anything
other than fairly conventional UNIX platforms.

## Porting Header File

In spite of all the above advice, you will still end up needing some
conditional compilation, for example to include alternate header files where
standard ones are missing or to \#define symbols that aren't defined on the
system. Put all of this code in the porting header file for the package, then
\#include this header file in each of the source files of the package. With
this approach you only need to change a single place if you have to modify
your approach to portability, and you can see all of the porting issues in one
place. You can look at tclPort.h and tkPort.h for examples of porting header
files.

# Miscellaneous

## Changes Files

Each package should contain a file named changes that keeps a log of all
significant changes made to the package. The changes file provides a way for
users to find out what's new in each new release, what bugs have been fixed,
and what compatibility problems might be introduced by the new release. The
changes file should be in chronological order.  Just add short blurbs to it
each time you make a change. Here is a sample from the Tk changes file:

	   5/19/94 (bug fix) Canvases didn't generate proper Postscript for
	   stippled text.
	
	   5/20/94 (new feature) Added "bell" command to ring the display's bell.
	
	   5/26/94 (feature removed) Removed support for "fill" justify mode
	   from Tk_GetJustify and from the TK_CONFIG_JUSTIFY configuration
	   option. None of the built-in widgets ever supported this mode
	   anyway.
	   *** POTENTIAL INCOMPATIBILITY ***

The entries in the changes file can be relatively terse; once someone finds a
change that is relevant, they can always go to the manual entries or code to
find out more about it. Be sure to highlight changes that cause compatibility
problems, so people can scan the changes file quickly to locate the
incompatibilities.

_\(The Tcl and Tk core additionally uses a ChangeLog file that has a much
higher detail within it. This has the advantage of having more tooling
support, but tends to be so verbose that the shorter summaries in the changes
file are still written up by the core maintainers before each release.\)_

# Copyright

This document has been placed in the public domain.

Name change from tip/248.tip to tip/248.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

TIP:            248
Title:          Integrate Tile into Tk as Ttk
Version:        $Revision: 1.7 $
Author:         Jeff Hobbs <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        08-Jun-2005
Post-History:   
Tcl-Version:    8.5
Obsoletes:	172


~ Abstract

This TIP proposes that the tile themed widget set be integrated into
Tk from 8.5 onwards as the static package Ttk.

~ Rationale

It is well known that Tk has been lacking in graphical glitz for a few
years; GUI standards have moved on whereas Tk has remained largely
static. The core of Tk is still great (e.g. its resizing behaviour is
second to none) but fancy shaded buttons are what modern users expect.
Through the sterling work of Joe English and others, the Tile
package is available which offers a new set of widgets for use on top
of the Tk foundation, and which provide that extra graphical polish by
leveraging underlying graphics layers (e.g. the Luna theming engine on
Windows XP, the Aqua theming on MacOSX, etc.) This is ''exactly'' what
we need, so we should ensure that every user of Tk can take advantage
of these new capabilities (universality is important) through updating
our distribution strategy.

This TIP acknowledges that Tile is a project that is still in
development, but the current state is stable enough for inclusion and
will encourage wider use.  It is expected that more changes will come
later.  This TIP proposes integration of Tile into the Tk core as the
Ttk package.  It would be part of the standard core, but have a
version different from the overarching Tk (much as Tcl has the http
package).  This will allow for minor user-level changes and continued
rapid development as part of the larger Tk framework (eg, Tk
patchlevel releases can have minor version bumps to the Ttk package).

Note that although the Tile widgets are ''mostly'' drop-in
replacements for the Tk core widgets, they are not perfect stand-ins
due to the differences in the way state is managed. This means that
this TIP categorically does not propose the replacement of Tk's
widgets with Tile's.

~ Proposed Changes

 1. Full integration of the Tile package into the Tk source tree.
    This would include renaming of source files to fit inside the
    Tk directory structure.  A static package named Ttk will
    signify their availability and specific version.

 2. To facilitate mixing of widgets between Tk and Tile, all Tk's
    widget creation commands are to be ''additionally'' declared in
    the '''::tk''' namespace and [['''namespace export''']]ed from
    there.  Allowing users to mix class Tk and themed Ttk widgets
    improves the overall richness and flexibility of Tk applications.

~ Discussion

See the discussion in the thread at
http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/2761205.

Tile is expected to continue as an 8.4-compatible package while 8.4 is
still the standard stable version.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|




|



|
|



|
|

|







|
|
|
|

|





|







|
|



|


|




|


>

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

# TIP 248: Integrate Tile into Tk as Ttk

	Author:         Jeff Hobbs <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        08-Jun-2005
	Post-History:   
	Tcl-Version:    8.5
	Obsoletes:	172
-----

# Abstract

This TIP proposes that the tile themed widget set be integrated into
Tk from 8.5 onwards as the static package Ttk.

# Rationale

It is well known that Tk has been lacking in graphical glitz for a few
years; GUI standards have moved on whereas Tk has remained largely
static. The core of Tk is still great \(e.g. its resizing behaviour is
second to none\) but fancy shaded buttons are what modern users expect.
Through the sterling work of Joe English and others, the Tile
package is available which offers a new set of widgets for use on top
of the Tk foundation, and which provide that extra graphical polish by
leveraging underlying graphics layers \(e.g. the Luna theming engine on
Windows XP, the Aqua theming on MacOSX, etc.\) This is _exactly_ what
we need, so we should ensure that every user of Tk can take advantage
of these new capabilities \(universality is important\) through updating
our distribution strategy.

This TIP acknowledges that Tile is a project that is still in
development, but the current state is stable enough for inclusion and
will encourage wider use.  It is expected that more changes will come
later.  This TIP proposes integration of Tile into the Tk core as the
Ttk package.  It would be part of the standard core, but have a
version different from the overarching Tk \(much as Tcl has the http
package\).  This will allow for minor user-level changes and continued
rapid development as part of the larger Tk framework \(eg, Tk
patchlevel releases can have minor version bumps to the Ttk package\).

Note that although the Tile widgets are _mostly_ drop-in
replacements for the Tk core widgets, they are not perfect stand-ins
due to the differences in the way state is managed. This means that
this TIP categorically does not propose the replacement of Tk's
widgets with Tile's.

# Proposed Changes

 1. Full integration of the Tile package into the Tk source tree.
    This would include renaming of source files to fit inside the
    Tk directory structure.  A static package named Ttk will
    signify their availability and specific version.

 2. To facilitate mixing of widgets between Tk and Tile, all Tk's
    widget creation commands are to be _additionally_ declared in
    the **::tk** namespace and [**namespace export**]ed from
    there.  Allowing users to mix class Tk and themed Ttk widgets
    improves the overall richness and flexibility of Tk applications.

# Discussion

See the discussion in the thread at
<http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/2761205.>

Tile is expected to continue as an 8.4-compatible package while 8.4 is
still the standard stable version.

# Copyright

This document has been placed in the public domain.

Name change from tip/249.tip to tip/249.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248

TIP:            249
Title:          Unification of Tcl's Parsing of Numbers
Version:        $Revision: 1.9 $
Author:         Kevin B. Kenny <[email protected]>
Author:         David S. Cargo <[email protected]>
Author:         Don Porter <[email protected]>
State:          Draft
Type:           Informative
Vote:           No voting
Created:        13-Jun-2005
Post-History:   


~ Abstract

This TIP proposes to unify the recognition of all of Tcl's "numeric"
objects into a single parser.  The intended effect is to improve
performance by eliminating a number of cases where a cached numeric
representation may be discarded, and to restore (more accurately,
to establish) the "everything is a string" principle in dealing with
numbers.

~ Rationale

Tcl's handling of numbers has always been problematic and ambiguous.
Even in the earliest releases of the '''expr''' command, there were
issues with the unexpected demotion of floating point numbers to
integers, causing subsequent divisions to be interpreted as integer
division with incorrect results.

Another trouble spot has been the interpretation of constants with
leading zeroes.  When these are interpreted as integers, they are
octal numbers.  They can also be interpreted as floating point
constants (at least with ''Tcl_GetDoubleFromObj''), in which case they
are decimal.  Because of this ambiguity, the '''expr''' system cannot
make effective use of the internal representation of a floating point
number; it needs to refer back to the string to make sure that the
number is not an octal integer to which ''Tcl_GetDoubleFromObj'' has
been applied.

Even more confusing is the treatment of numbers that have leading
zeroes but contain the digits 8 or 9.  These are rejected by the
'''expr''' parser as invalid octal but are accepted by
''Tcl_GetDoubleFromObj''.

~ Proposal

This TIP proposes a strict "everything is a string" interpretation
for strings as numeric values.  The set of strings that can be
interpreted as numbers shall be partitioned into disjoint subsets,
with a single "canonical" representation for each.

This change will imply that a few C calls will break compatibility.
In particular, ''Tcl_GetDoubleFromObj'' may leave an integer internal
representation in the object, despite the documentation's assertion
that the object will shimmer.  Similarly, ''Tcl_GetDoubleFromObj''
will no longer interpret octal integers as decimal; this feature
causes only surprise and consternation.

The ''Tcl_ConvertToType'' call will also no longer force conversion
to a specific numeric type.  Since it does not do so, it is not
reasonable for extensions to use it on the numeric types.  For this
reason, the numeric types ''shall not be registered;''
''Tcl_GetObjType'' will fail when presented with one of their names.

When one of the conversion procedures ''Tcl_GetIntFromObj'',
''Tcl_GetWideIntFromObj'',  ''Tcl_GetBignumFromObj'' (assuming the
eventual approval of [237]), or ''Tcl_GetDoubleFromObj'' is called,
it will cast any pre-existing numeric internal representation that
it finds to the appropriate return type (throwing an error if the
number is too large to represent, or a double is used in an integer
context).  If the procedure finds no pre-existing numeric internal
representation, it will extract the string representation, determine
its canonical representation as a number, and store that.

The easiest way to visualize the specific sets of strings that are
recognized as numbers is with a diagram of the state machine that
implements them.

#image:249statemachine State machine that recognizes numbers.

In the diagram, "Start" represents the start state of the machine.
The leading and trailing whitespace that is allowed for all numbers
is not diagrammed, for clarity.

Intermediate states of the machine are represented by small ovals.
Large rectangles represent final states, and are labeled with
the type of number that will result.  Note that any number can
optionally begin with a '+' or '-' character, which will not
be mentioned further.  Each of the accepting states, however,
merits further discussion.

 1. The string "0" shall always represent an integer of the smallest
    type available ('''tclIntType'''). It shall never represent a
    floating point value.

 2. A leading zero followed by a string of octal digits shall be
    interpreted as an octal integer.  The integer shall be stored in
    the smallest of '''tclIntType''', '''tclWideIntType''' and
    '''tclBignumType''' that will hold it.  (Note that storing
    '''tclBignumType''' is possible without accepting [237], provided
    that the ''Tcl_Get*FromObj'' routines recognize it and convert its
    value as needed.)  The interpretation as an octal integer shall
    hold even if the string is presented to ''Tcl_GetDoubleFromObj'',
    which today interprets it as decimal.

 3. A leading zero, followed by the letter 'X' (case insensitive) and a
    string of hexadecimal digits shall be interpreted as a hexadecimal
    integer.  Again, the smallest representation needed is chosen.

 4. A string of decimal digits beginning with a nonzero digit is
    interpreted as a decimal integer and stored in the smallest
    suitable internal representation.

 5. A string of digits beginning with a zero but containing the digits
    '''8''' or '''9''' is an error; it appears to be bad octal.  It
    would be possible to allow this case in ''Tcl_GetDoubleFromObj'',
    but it seems unwise, since the consequence would be that '''string
    is double''' would accept "double" strings that will fail in
    '''expr'''.

 6. A string consisting of a nonempty sequence of decimal digits and
    a single period (which may appear anywhere within the string) is a
    valid floating point constant in 'F' format, even if it begins
    with '0'.  It is interpreted in decimal and stored in a
    '''tclDoubleType'''.  If the input number is too small to
    represent, an appropriately signed zero is stored.  If the input
    number is too large to represent, an appropriately signed infinity
    is stored.

 7. Floating point numbers in the usual 'E' format are accepted and
    interpreted in decimal. Once again, they are stored in
    '''tclDoubleType''' and are replaced with zero or infinity if they
    are too small or large.

 8. The constants, "Inf", and "Infinity" (perhaps with a leading
    signum) are interpreted as infinities.  Infinity is represented as
    '''tclDoubleType.'''

 9. The constant "NaN" is the IEEE "Not a Number" value.  It is
    specifically permitted in the parser so that '''binary format q
    NaN''' and similar calls can produce NaN on an external medium.
    The presence of NaN in expressions, or in
    ''Tcl_GetDoubleFromObj'', signals an error.  NaN is represented as
    '''tclDoubleType'''.

 10. IEEE floating point does not have a single unique NaN value, so a
     NaN may be augmented by a parenthesized string of hexadecimal
     digits, which will be stored in its least significant bits.  It
     shall not be possible to construct signalling NaN by this route;
     only quiet NaN will be supported.  NaN is represented as
     '''tclDoubleType.'''

~ Additions

In addition to the base state machine detailed above,
the state machine of the reference implementation
contains additional states to parse integer values
beginning with the '''0b''' or '''0o''' prefixes as
originally proposed in [114].  Getting these prefixes
recognized in Tcl 8.5 is an important migration step
to support migration to whatever version of Tcl drops
the "leading '''0''' implies octal format" rule.

Also in addition, the parsing routine will accept a
''flags'' value containing the flag bits below that
exert finer control on the parsing.  These extra
controls were found to be required to permit the
[[scan]] command to use the same parser.

   * '''TCL_PARSE_INTEGER_ONLY''' -- accept only integer values;
     reject strings that denote floating point values (or
     accept only the leading portion of them that are integer
     values).

   * '''TCL_PARSE_SCAN_PREFIXES''' -- ignore the prefixes '''0b'''
     and '''0o''' that are not part of the [[scan]] command's
     vocabulary.  Use only in combination with
     '''TCL_PARSE_INTEGER_ONLY'''.

   * '''TCL_PARSE_OCTAL_ONLY''' - parse only in the octal format,
     whether or not a prefix is present that would lead to octal
     parsing.  Use only in combination with
     '''TCL_PARSE_INTEGER_ONLY'''.

   * '''TCL_PARSE_HEXADECIMAL_ONLY''' - parse only in the
     hexadecimal format,
     whether or not a prefix is present that would lead to hexadecimal
     parsing.  Use only in combination with
     '''TCL_PARSE_INTEGER_ONLY'''.

   * '''TCL_PARSE_DECIMAL_ONLY''' - parse only in the decimal format,
     no
     matter whether a '''0''' prefix would normally force a different
     base.

~ Incompatibilities

The change described is sufficient to run the Tcl and Tk test suites with
unwanted test results only in the detailed format of error messages
for integer overflow and in the types returned by using the
'''testobj''' command (not part of the usual distribution) to
introspect them.  Despite this reassurance, several potential
incompatibilities are identified.

First, as mentioned above, C extensions will no longer have fine
control over Tcl's built-in numeric types, because the types
will not be registered and hence will be unavailable for use
with ''Tcl_ConvertToType.'' This is actually a
good thing, since it means that the rest of Tcl can assume that
they are well-behaved, resulting in a considerable simplification.
Most of the Tcl Core Team believes that ''Tcl_ConvertToType''
has no legitimate use in any case.

Second, it will no longer be correct to assume that
''Tcl_Get*FromObj'' will leave an internal representation of
precisely the requested type.  It is, in any case, a highly
questionable practice for callers to assume a specific internal
representation (with the possible exception of Tcl_Set*Obj and
Tcl_New*Obj).  There will no doubt be a few extensions that run
afoul of this change, but they can be fixed easily in such a way
that they will continue to compile and run on earlier versions
of Tcl.

Third, ''Tcl_GetDoubleFromObj'' will be both more and less permissive
than before.  It will no longer accept constants with a leading zero
and no decimal point or 'E' that are invalid octal numbers.
On the other hand, it will accept
constants that are too large to fit in a '''Tcl_WideInt'''; somewhat
surprisingly, '''string repeat 9 50''' cannot today be interpreted as
a double.  '''string is double''' will follow ''Tcl_GetDoubleFromObj''
in what it considers acceptable.  Any string that is accepted as
either an integer or a double by '''expr''' will be accepted in
''Tcl_GetDoubleFromObj'', and only those strings will be accepted.

Fourth, the recognition of '''0b''' and '''0o''' as valid
prefixes for integer values is a type of incompatibility.

~ Reference Implementation

See [237] for more implementation details.

~ Copyright

Copyright (c) 2005 by Kevin B. Kenny.  All rights reserved.  

This document may be distributed subject to the terms and conditions
set forth in the Open Publication License, version 1.0
[http://www.opencontent.org/openpub/].

<
|
<
|
|
|
|
|
|
|
|
>

|




|
|


|


|







|
|


|




|
|

|







|

|



|


|
|

|
|
|

|

|







|








|




|




|
|
|
|
|
|


|








|
|
|
|
|


|


|






|


|
|
|


|
|

|
|






|

|




|
|


|


|


|

|
|

|

|
|

|

|


|

|



|

|

|


|




|






|


|



|


|
|




|



|
|
|

|
|

|


|

|

|

|



|
>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248

# TIP 249: Unification of Tcl's Parsing of Numbers

	Author:         Kevin B. Kenny <[email protected]>
	Author:         David S. Cargo <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           No voting
	Created:        13-Jun-2005
	Post-History:   
-----

# Abstract

This TIP proposes to unify the recognition of all of Tcl's "numeric"
objects into a single parser.  The intended effect is to improve
performance by eliminating a number of cases where a cached numeric
representation may be discarded, and to restore \(more accurately,
to establish\) the "everything is a string" principle in dealing with
numbers.

# Rationale

Tcl's handling of numbers has always been problematic and ambiguous.
Even in the earliest releases of the **expr** command, there were
issues with the unexpected demotion of floating point numbers to
integers, causing subsequent divisions to be interpreted as integer
division with incorrect results.

Another trouble spot has been the interpretation of constants with
leading zeroes.  When these are interpreted as integers, they are
octal numbers.  They can also be interpreted as floating point
constants \(at least with _Tcl\_GetDoubleFromObj_\), in which case they
are decimal.  Because of this ambiguity, the **expr** system cannot
make effective use of the internal representation of a floating point
number; it needs to refer back to the string to make sure that the
number is not an octal integer to which _Tcl\_GetDoubleFromObj_ has
been applied.

Even more confusing is the treatment of numbers that have leading
zeroes but contain the digits 8 or 9.  These are rejected by the
**expr** parser as invalid octal but are accepted by
_Tcl\_GetDoubleFromObj_.

# Proposal

This TIP proposes a strict "everything is a string" interpretation
for strings as numeric values.  The set of strings that can be
interpreted as numbers shall be partitioned into disjoint subsets,
with a single "canonical" representation for each.

This change will imply that a few C calls will break compatibility.
In particular, _Tcl\_GetDoubleFromObj_ may leave an integer internal
representation in the object, despite the documentation's assertion
that the object will shimmer.  Similarly, _Tcl\_GetDoubleFromObj_
will no longer interpret octal integers as decimal; this feature
causes only surprise and consternation.

The _Tcl\_ConvertToType_ call will also no longer force conversion
to a specific numeric type.  Since it does not do so, it is not
reasonable for extensions to use it on the numeric types.  For this
reason, the numeric types _shall not be registered;_
_Tcl\_GetObjType_ will fail when presented with one of their names.

When one of the conversion procedures _Tcl\_GetIntFromObj_,
_Tcl\_GetWideIntFromObj_,  _Tcl\_GetBignumFromObj_ \(assuming the
eventual approval of [[237]](237.md)\), or _Tcl\_GetDoubleFromObj_ is called,
it will cast any pre-existing numeric internal representation that
it finds to the appropriate return type \(throwing an error if the
number is too large to represent, or a double is used in an integer
context\).  If the procedure finds no pre-existing numeric internal
representation, it will extract the string representation, determine
its canonical representation as a number, and store that.

The easiest way to visualize the specific sets of strings that are
recognized as numbers is with a diagram of the state machine that
implements them.

![State machine that recognizes numbers.](../assets/249statemachine.png)

In the diagram, "Start" represents the start state of the machine.
The leading and trailing whitespace that is allowed for all numbers
is not diagrammed, for clarity.

Intermediate states of the machine are represented by small ovals.
Large rectangles represent final states, and are labeled with
the type of number that will result.  Note that any number can
optionally begin with a '\+' or '-' character, which will not
be mentioned further.  Each of the accepting states, however,
merits further discussion.

 1. The string "0" shall always represent an integer of the smallest
    type available \(**tclIntType**\). It shall never represent a
    floating point value.

 2. A leading zero followed by a string of octal digits shall be
    interpreted as an octal integer.  The integer shall be stored in
    the smallest of **tclIntType**, **tclWideIntType** and
    **tclBignumType** that will hold it.  \(Note that storing
    **tclBignumType** is possible without accepting [[237]](237.md), provided
    that the _Tcl\_Get\*FromObj_ routines recognize it and convert its
    value as needed.\)  The interpretation as an octal integer shall
    hold even if the string is presented to _Tcl\_GetDoubleFromObj_,
    which today interprets it as decimal.

 3. A leading zero, followed by the letter 'X' \(case insensitive\) and a
    string of hexadecimal digits shall be interpreted as a hexadecimal
    integer.  Again, the smallest representation needed is chosen.

 4. A string of decimal digits beginning with a nonzero digit is
    interpreted as a decimal integer and stored in the smallest
    suitable internal representation.

 5. A string of digits beginning with a zero but containing the digits
    **8** or **9** is an error; it appears to be bad octal.  It
    would be possible to allow this case in _Tcl\_GetDoubleFromObj_,
    but it seems unwise, since the consequence would be that **string
    is double** would accept "double" strings that will fail in
    **expr**.

 6. A string consisting of a nonempty sequence of decimal digits and
    a single period \(which may appear anywhere within the string\) is a
    valid floating point constant in 'F' format, even if it begins
    with '0'.  It is interpreted in decimal and stored in a
    **tclDoubleType**.  If the input number is too small to
    represent, an appropriately signed zero is stored.  If the input
    number is too large to represent, an appropriately signed infinity
    is stored.

 7. Floating point numbers in the usual 'E' format are accepted and
    interpreted in decimal. Once again, they are stored in
    **tclDoubleType** and are replaced with zero or infinity if they
    are too small or large.

 8. The constants, "Inf", and "Infinity" \(perhaps with a leading
    signum\) are interpreted as infinities.  Infinity is represented as
    **tclDoubleType.**

 9. The constant "NaN" is the IEEE "Not a Number" value.  It is
    specifically permitted in the parser so that **binary format q
    NaN** and similar calls can produce NaN on an external medium.
    The presence of NaN in expressions, or in
    _Tcl\_GetDoubleFromObj_, signals an error.  NaN is represented as
    **tclDoubleType**.

 10. IEEE floating point does not have a single unique NaN value, so a
     NaN may be augmented by a parenthesized string of hexadecimal
     digits, which will be stored in its least significant bits.  It
     shall not be possible to construct signalling NaN by this route;
     only quiet NaN will be supported.  NaN is represented as
     **tclDoubleType.**

# Additions

In addition to the base state machine detailed above,
the state machine of the reference implementation
contains additional states to parse integer values
beginning with the **0b** or **0o** prefixes as
originally proposed in [[114]](114.md).  Getting these prefixes
recognized in Tcl 8.5 is an important migration step
to support migration to whatever version of Tcl drops
the "leading **0** implies octal format" rule.

Also in addition, the parsing routine will accept a
_flags_ value containing the flag bits below that
exert finer control on the parsing.  These extra
controls were found to be required to permit the
[scan] command to use the same parser.

   * **TCL\_PARSE\_INTEGER\_ONLY** -- accept only integer values;
     reject strings that denote floating point values \(or
     accept only the leading portion of them that are integer
     values\).

   * **TCL\_PARSE\_SCAN\_PREFIXES** -- ignore the prefixes **0b**
     and **0o** that are not part of the [scan] command's
     vocabulary.  Use only in combination with
     **TCL\_PARSE\_INTEGER\_ONLY**.

   * **TCL\_PARSE\_OCTAL\_ONLY** - parse only in the octal format,
     whether or not a prefix is present that would lead to octal
     parsing.  Use only in combination with
     **TCL\_PARSE\_INTEGER\_ONLY**.

   * **TCL\_PARSE\_HEXADECIMAL\_ONLY** - parse only in the
     hexadecimal format,
     whether or not a prefix is present that would lead to hexadecimal
     parsing.  Use only in combination with
     **TCL\_PARSE\_INTEGER\_ONLY**.

   * **TCL\_PARSE\_DECIMAL\_ONLY** - parse only in the decimal format,
     no
     matter whether a **0** prefix would normally force a different
     base.

# Incompatibilities

The change described is sufficient to run the Tcl and Tk test suites with
unwanted test results only in the detailed format of error messages
for integer overflow and in the types returned by using the
**testobj** command \(not part of the usual distribution\) to
introspect them.  Despite this reassurance, several potential
incompatibilities are identified.

First, as mentioned above, C extensions will no longer have fine
control over Tcl's built-in numeric types, because the types
will not be registered and hence will be unavailable for use
with _Tcl\_ConvertToType._ This is actually a
good thing, since it means that the rest of Tcl can assume that
they are well-behaved, resulting in a considerable simplification.
Most of the Tcl Core Team believes that _Tcl\_ConvertToType_
has no legitimate use in any case.

Second, it will no longer be correct to assume that
_Tcl\_Get\*FromObj_ will leave an internal representation of
precisely the requested type.  It is, in any case, a highly
questionable practice for callers to assume a specific internal
representation \(with the possible exception of Tcl\_Set\*Obj and
Tcl\_New\*Obj\).  There will no doubt be a few extensions that run
afoul of this change, but they can be fixed easily in such a way
that they will continue to compile and run on earlier versions
of Tcl.

Third, _Tcl\_GetDoubleFromObj_ will be both more and less permissive
than before.  It will no longer accept constants with a leading zero
and no decimal point or 'E' that are invalid octal numbers.
On the other hand, it will accept
constants that are too large to fit in a **Tcl\_WideInt**; somewhat
surprisingly, **string repeat 9 50** cannot today be interpreted as
a double.  **string is double** will follow _Tcl\_GetDoubleFromObj_
in what it considers acceptable.  Any string that is accepted as
either an integer or a double by **expr** will be accepted in
_Tcl\_GetDoubleFromObj_, and only those strings will be accepted.

Fourth, the recognition of **0b** and **0o** as valid
prefixes for integer values is a type of incompatibility.

# Reference Implementation

See [[237]](237.md) for more implementation details.

# Copyright

Copyright \(c\) 2005 by Kevin B. Kenny.  All rights reserved.  

This document may be distributed subject to the terms and conditions
set forth in the Open Publication License, version 1.0
<http://www.opencontent.org/openpub/> .

Name change from tip/25.tip to tip/25.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

TIP:		25
Title:		Native tk_messageBox  on Macintosh
Version:	$Revision: 1.3 $
Author:		Mats Bengtsson <[email protected]>
State:		Withdrawn
Type:		Project
Tcl-Version:	8.5
Vote:		Pending
Created: 	07-Feb-2001
Obsoleted-By:	152
Post-History:


~ Abstract

This is a replacement for the ''tk_messageBox'' on the Macintosh with
a native implementation which is compliant with the Appearance Manager
in Mac OS 8 and later.

~ Rationale

The present (in 8.3.2p1 and earlier) ''tk_messageBox'' on the Macintosh 
is non-movable, and lacks many features that are required to be compliant 
with Mac OS 8 and later. Non-movable dialogs should be abandoned in a 
multitasking environment. This TIP presents a step to extend the native
appearance on the Macintosh.

#image:25original This is the present tk_messageBox.
 
#image:25native   This is the native tk_messageBox.


~ Reference Implementation

The proposed change is now implemented as a loadable extension (in C)
on Macintosh, and can be downloaded at
http://hem.fyristorg.com/matben/download/MovableAlerts.sit .
This extension requires Tk 8.3.2p1 or later due to the changed stub
loading mechanism.  The core of the code should go in the
''tkMacDialog.c'' file. Some additional changes are necessary in order
to load the new ''tk_messageBox'' and not the old, script based
''tk_messageBox''. Also, need to check for the presence of the
Appearance manager:

|if (Appearance Manager)
|    use native (new) messageBox
|else
|    use present script based messageBox

All functionality from the documentation that are applicable are
implemented, with some exceptions:

    *   There is a ''-finemessage'' option to support the native
        text message set in a smaller font below the main message.
        
    *   Both ''-message'' and ''-finemessage'' option are truncated at
        255 characters.
        
    *   Buttons appear from right to left instead of vice versa.
    
    *   There is always a default button.        

All these deviations are consistent with the look-and-feel of
Mac OS 8.0 and on. Existing scripts using ''tk_messageBox'' are
compatible with the new ''tk_messageBox''.

Open questions: 

    * 	Name of extra option ''-finemessage''

    *	Name of the two C functions in the implementation

    *	How to make the core code call the new code instead of
	the original, script implemented


~ Copyright

This document has been placed in the public domain

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|

|





|

|


|

|

|


|
|
|


|
|
|
|




|


|







|
|



|







|


>

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

# TIP 25: Native tk_messageBox  on Macintosh

	Author:		Mats Bengtsson <[email protected]>
	State:		Withdrawn
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Pending
	Created: 	07-Feb-2001
	Obsoleted-By:	152
	Post-History:
-----

# Abstract

This is a replacement for the _tk\_messageBox_ on the Macintosh with
a native implementation which is compliant with the Appearance Manager
in Mac OS 8 and later.

# Rationale

The present \(in 8.3.2p1 and earlier\) _tk\_messageBox_ on the Macintosh 
is non-movable, and lacks many features that are required to be compliant 
with Mac OS 8 and later. Non-movable dialogs should be abandoned in a 
multitasking environment. This TIP presents a step to extend the native
appearance on the Macintosh.

![This is the present tk_messageBox.](../assets/25original.gif)
 
![{} {} This is the native tk_messageBox.](../assets/25native.gif)


# Reference Implementation

The proposed change is now implemented as a loadable extension \(in C\)
on Macintosh, and can be downloaded at
<http://hem.fyristorg.com/matben/download/MovableAlerts.sit> .
This extension requires Tk 8.3.2p1 or later due to the changed stub
loading mechanism.  The core of the code should go in the
_tkMacDialog.c_ file. Some additional changes are necessary in order
to load the new _tk\_messageBox_ and not the old, script based
_tk\_messageBox_. Also, need to check for the presence of the
Appearance manager:

	if (Appearance Manager)
	    use native (new) messageBox
	else
	    use present script based messageBox

All functionality from the documentation that are applicable are
implemented, with some exceptions:

    *   There is a _-finemessage_ option to support the native
        text message set in a smaller font below the main message.
        
    *   Both _-message_ and _-finemessage_ option are truncated at
        255 characters.
        
    *   Buttons appear from right to left instead of vice versa.
    
    *   There is always a default button.        

All these deviations are consistent with the look-and-feel of
Mac OS 8.0 and on. Existing scripts using _tk\_messageBox_ are
compatible with the new _tk\_messageBox_.

Open questions: 

    * 	Name of extra option _-finemessage_

    *	Name of the two C functions in the implementation

    *	How to make the core code call the new code instead of
	the original, script implemented


# Copyright

This document has been placed in the public domain

Name change from tip/250.tip to tip/250.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

TIP:            250
Title:          Efficient Access to Namespace Variables
Version:        $Revision: 1.7 $
Author:         Will Duquette <[email protected]>
Author:         miguel sofer <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        19-Jun-2005
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes a new '''namespace''' subcommand, '''namespace
upvar''', to efficiently alias namespace variables into the current
scope.

~ Rationale

A pure-Tcl object system which defines a namespace to contain the
variables for each object instance must either duplicate the object's
method code in each instance namespace, or define the method code such
that it exists in one namespace but accesses data from another.  The
Snit package [http://www.wjduquette.com/snit] does the latter.
Instance variables are declared automatically within each method body
using code like this, where "selfns" is a variable containing the name
of the instance namespace:

| upvar ${selfns}::myvar myvar

The fully-qualified variable name "${selfns}::myvar" must be
recomputed each time the method is called, which is a significant
source of method-call overhead.  This TIP proposes a mechanism for
avoiding many of these costs while also allowing people to write
clearer code.

With '''namespace upvar''', the code would look like this:

| namespace upvar $selfns myvar myvar

The speed gains come from:

   * it avoids building and then destroying a Tcl_Obj for the fully qualified name

   * it avoids parsing the fully qualified name into its namespace/tail components, creating and then destroying the corresponding Tcl_Objs

   * it may reuse a cached namespace in the internal representation of ${selfns}

In addition, the programmer's intention is easier to see in a command

| namespace upvar $selfns var1 var1 var2 var2 var3 var3

than in the currently necessary

| upvar 0 ${selfns}::var1 var1 ${selfns}::var2 var2 ${selfns}::var3 var3

where the fact that all variables come from the same namespace is not so obvious.

~ Specification

The syntax of the new subcommand is as follows:

 > '''namespace upvar''' ''ns otherVar myVar'' ?''otherVar myVar'' ...?

The semantics are identical to the following '''upvar''' call:

 > '''upvar 0''' ''ns''::''otherVar'' ''myVar'' ?''ns''::''otherVar''
   ''myVar''...?

That is, the variable ''otherVar'' in namespace ''ns'' (as resolved from the local scope) is aliased to variable ''myVar'' in the local scope.

~ Reference Implementation

A reference implementation of '''namespace upvar''' is being developed at SF patch #1275435 [https://sourceforge.net/tracker/index.php?func=detail&aid=1275435&group_id=10894&atid=310894].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|


|





|




|

|





|

|



|

|

|



|



|



|



|

|

|
|

|

|

|

|


>

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

# TIP 250: Efficient Access to Namespace Variables

	Author:         Will Duquette <[email protected]>
	Author:         miguel sofer <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        19-Jun-2005
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes a new **namespace** subcommand, **namespace
upvar**, to efficiently alias namespace variables into the current
scope.

# Rationale

A pure-Tcl object system which defines a namespace to contain the
variables for each object instance must either duplicate the object's
method code in each instance namespace, or define the method code such
that it exists in one namespace but accesses data from another.  The
Snit package <http://www.wjduquette.com/snit>  does the latter.
Instance variables are declared automatically within each method body
using code like this, where "selfns" is a variable containing the name
of the instance namespace:

	 upvar ${selfns}::myvar myvar

The fully-qualified variable name "$\{selfns\}::myvar" must be
recomputed each time the method is called, which is a significant
source of method-call overhead.  This TIP proposes a mechanism for
avoiding many of these costs while also allowing people to write
clearer code.

With **namespace upvar**, the code would look like this:

	 namespace upvar $selfns myvar myvar

The speed gains come from:

   * it avoids building and then destroying a Tcl\_Obj for the fully qualified name

   * it avoids parsing the fully qualified name into its namespace/tail components, creating and then destroying the corresponding Tcl\_Objs

   * it may reuse a cached namespace in the internal representation of $\{selfns\}

In addition, the programmer's intention is easier to see in a command

	 namespace upvar $selfns var1 var1 var2 var2 var3 var3

than in the currently necessary

	 upvar 0 ${selfns}::var1 var1 ${selfns}::var2 var2 ${selfns}::var3 var3

where the fact that all variables come from the same namespace is not so obvious.

# Specification

The syntax of the new subcommand is as follows:

 > **namespace upvar** _ns otherVar myVar_ ?_otherVar myVar_ ...?

The semantics are identical to the following **upvar** call:

 > **upvar 0** _ns_::_otherVar_ _myVar_ ?_ns_::_otherVar_
   _myVar_...?

That is, the variable _otherVar_ in namespace _ns_ \(as resolved from the local scope\) is aliased to variable _myVar_ in the local scope.

# Reference Implementation

A reference implementation of **namespace upvar** is being developed at SF patch \#1275435 <https://sourceforge.net/tracker/index.php?func=detail&aid=1275435&group_id=10894&atid=310894> .

# Copyright

This document has been placed in the public domain.

Name change from tip/251.tip to tip/251.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

TIP:            251
Title:          Enhance the 'list' Command
Version:        $Revision: 1.14 $
Author:         Brian Schmidt <[email protected]>
Author:         S�rgio Loureiro <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        28-Jun-2005
Post-History:   
Tcl-Version:    8.6


~ Abstract

This TIP proposes enhancing the existing '''list''' command to serve as a
top-level command ensemble for all the related list commands that have
proliferated over time, as well as making it easier to add future new
list-based commands.

~Rationale

There are numerous top-level commands for lists already. This command would
centralize them, making it easier for new developers of Tcl scripts to learn
all the related list commands, to simplify and reduce the number of top-level
commands to learn, etc. The enhanced '''list''' would be consistent with the
new top-level commands '''chan''' [208] and '''dict''' [111], as well as the
existing '''string''' and '''file''' commands.

~Specification

A new command '''list''' will be added with the following syntax:

 list append:     equivalent to '''lappend'''

 list create:     equivalent to '''list'''

 list index:      equivalent to '''lindex'''

 list insert:     equivalent to '''linsert'''

 list join:       equivalent to '''join'''

 list length:     equivalent to '''llength'''

 list range:      equivalent to '''lrange'''

 list repeat:     equivalent to '''lrepeat''' (see [136])

 list replace:    equivalent to '''lreplace'''

 list search:     equivalent to '''lsearch'''

 list set:        equivalent to '''lset'''

 list sort:       equivalent to '''lsort'''

Each represents the existing command that is commented. The arguments to each
would remain what the current command takes.

Note that '''split''' is not included as it operates on a string and returns a
list, and '''concat''' is not included because it can operate on both normal
strings and lists.

The old commands could then potentially be deprecated:

 * '''join'''

 * '''lappend'''

 * '''lindex'''

 * '''linsert'''

 * '''llength'''

 * '''lrange'''

 * '''lrepeat'''

 * '''lreplace'''

 * '''lsearch'''

 * '''lset'''

 * '''lsort'''

~Incompatabilities

Incompatability with the existing list command could potentially be solved by
allowing the list command ''without'' one of the defined options to be
shorthand for the new '''list create''' command option. If the first argument
to the new list command is not one of the new known options then '''list
create''' is assumed by default.

For example,

|list {my list}

would be equivalent to:

|list set {my list} {}

It appears the only existing scripts that would break would be those that
actually utilize the '''list''' command, has at least 2 arguments, and have as
their first argument one of the new list command's ensemble options. This
would likely result in a small minority of scripts being impacted. Only Tcl
code with lists defined ''exactly'' as follows would break:

|list append ?arg...
|list create ?arg...
|list index ?arg...
|list insert ?arg...
|list join ?arg... 
|list length ?arg...
|list range ?arg...
|list repeat ?arg...
|list replace ?arg...
|list search ?arg...
|list set ?arg...
|list sort ?arg...

~Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|




|




|
|
|

|

|

|

|

|

|

|

|

|

|

|

|

|

|




|
|




|

|

|

|

|

|

|

|

|

|

|

|


|
|
|
|



|



|


|


|

|
|
|
|
|
|
|
|
|
|
|
|

|


>

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

# TIP 251: Enhance the 'list' Command

	Author:         Brian Schmidt <[email protected]>
	Author:         Sérgio Loureiro <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        28-Jun-2005
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes enhancing the existing **list** command to serve as a
top-level command ensemble for all the related list commands that have
proliferated over time, as well as making it easier to add future new
list-based commands.

# Rationale

There are numerous top-level commands for lists already. This command would
centralize them, making it easier for new developers of Tcl scripts to learn
all the related list commands, to simplify and reduce the number of top-level
commands to learn, etc. The enhanced **list** would be consistent with the
new top-level commands **chan** [[208]](208.md) and **dict** [[111]](111.md), as well as the
existing **string** and **file** commands.

# Specification

A new command **list** will be added with the following syntax:

 list append:     equivalent to **lappend**

 list create:     equivalent to **list**

 list index:      equivalent to **lindex**

 list insert:     equivalent to **linsert**

 list join:       equivalent to **join**

 list length:     equivalent to **llength**

 list range:      equivalent to **lrange**

 list repeat:     equivalent to **lrepeat** \(see [[136]](136.md)\)

 list replace:    equivalent to **lreplace**

 list search:     equivalent to **lsearch**

 list set:        equivalent to **lset**

 list sort:       equivalent to **lsort**

Each represents the existing command that is commented. The arguments to each
would remain what the current command takes.

Note that **split** is not included as it operates on a string and returns a
list, and **concat** is not included because it can operate on both normal
strings and lists.

The old commands could then potentially be deprecated:

 * **join**

 * **lappend**

 * **lindex**

 * **linsert**

 * **llength**

 * **lrange**

 * **lrepeat**

 * **lreplace**

 * **lsearch**

 * **lset**

 * **lsort**

# Incompatabilities

Incompatability with the existing list command could potentially be solved by
allowing the list command _without_ one of the defined options to be
shorthand for the new **list create** command option. If the first argument
to the new list command is not one of the new known options then **list
create** is assumed by default.

For example,

	list {my list}

would be equivalent to:

	list set {my list} {}

It appears the only existing scripts that would break would be those that
actually utilize the **list** command, has at least 2 arguments, and have as
their first argument one of the new list command's ensemble options. This
would likely result in a small minority of scripts being impacted. Only Tcl
code with lists defined _exactly_ as follows would break:

	list append ?arg...
	list create ?arg...
	list index ?arg...
	list insert ?arg...
	list join ?arg... 
	list length ?arg...
	list range ?arg...
	list repeat ?arg...
	list replace ?arg...
	list search ?arg...
	list set ?arg...
	list sort ?arg...

# Copyright

This document has been placed in the public domain.

Name change from tip/252.tip to tip/252.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

TIP:		252
Title:		Add New 'string' Command Options
Author:		Brian Schmidt <[email protected]>
Version:	$Revision: 1.4 $
Type:		Project
State:		Rejected
Vote:		Done
Created:	28-Jun-2005
Tcl-Version:	8.6
Post-History:	


~Abstract

This TIP proposes moving several existing string-related commands to be
options in the existing top-level '''string''' command.

~Rationale

There is an existing top-level '''string''' command already.  However, there
are other existing top-level string-related commands that for consistency
should be options in the existing '''string''' command.

These additional string command options would further centralize all
string-related commands, making it easier for new users to see all the related
string commands.

~Specification

Additional '''string''' command options would be added utilizing existing
top-level commands, using the following syntax:

|string split         ;equivalent to split
|string format        ;equivalent to format
|string scan          ;equivalent to scan
|string subst         ;equivalent to subst

Each represents the existing command that is commented. The arguments to each
would remain what the current command takes.

The old commands could then potentially be eventually deprecated:

|split
|format
|scan
|subst

~Copyright

This document has been placed in the public domain.

<
|
|
<
|
|
|
|
|
|
>

|


|

|

|

|





|

|


|
|
|
|






|
|
|
|

|


>

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

# TIP 252: Add New 'string' Command Options
	Author:		Brian Schmidt <[email protected]>

	Type:		Project
	State:		Rejected
	Vote:		Done
	Created:	28-Jun-2005
	Tcl-Version:	8.6
	Post-History:	
-----

# Abstract

This TIP proposes moving several existing string-related commands to be
options in the existing top-level **string** command.

# Rationale

There is an existing top-level **string** command already.  However, there
are other existing top-level string-related commands that for consistency
should be options in the existing **string** command.

These additional string command options would further centralize all
string-related commands, making it easier for new users to see all the related
string commands.

# Specification

Additional **string** command options would be added utilizing existing
top-level commands, using the following syntax:

	string split         ;equivalent to split
	string format        ;equivalent to format
	string scan          ;equivalent to scan
	string subst         ;equivalent to subst

Each represents the existing command that is commented. The arguments to each
would remain what the current command takes.

The old commands could then potentially be eventually deprecated:

	split
	format
	scan
	subst

# Copyright

This document has been placed in the public domain.

Name change from tip/253.tip to tip/253.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

TIP:		253
Title:		Consolidate Package-Related Commands
Author:		Brian Schmidt <[email protected]>
Version:	$Revision: 1.6 $
Type:		Project
State:		Draft
Vote:		Pending
Created:	05-Jul-2005
Tcl-Version:	8.7
Post-History:	


~Abstract

This TIP proposes enhancing the existing '''package''' command with
additional subcommands to serve as the top-level command container for
the existing '''pkg::create''' and '''pkg_mkIndex''' commands.

~Rationale

The '''pkg::create''' and '''pkg_mkIndex''' commands, while they
relate to packages, are their own separate top-level commands.  For
consistency, clarity and also making it easier for new users to see
all the related options, those commands should become options under
the existing '''package''' command.

~Specification

Additional '''package''' command options will be added with the
following subcommand syntax:

|    package create     ;pkg::create
|    package mkIndex    ;pkg_mkIndex

Each represents the existing command that is commented. The arguments
to each would remain what the current command takes.

The following old commands could then potentially be eventually
deprecated:

|    pkg::create
|    pkg_mkIndex

~Copyright

This document has been placed in the public domain.

<
|
|
<
|
|
|
|
|
|
>

|

|

|

|

|



|

|

|


|
|







|
|

|


>

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

# TIP 253: Consolidate Package-Related Commands
	Author:		Brian Schmidt <[email protected]>

	Type:		Project
	State:		Draft
	Vote:		Pending
	Created:	05-Jul-2005
	Tcl-Version:	8.7
	Post-History:	
-----

# Abstract

This TIP proposes enhancing the existing **package** command with
additional subcommands to serve as the top-level command container for
the existing **pkg::create** and **pkg\_mkIndex** commands.

# Rationale

The **pkg::create** and **pkg\_mkIndex** commands, while they
relate to packages, are their own separate top-level commands.  For
consistency, clarity and also making it easier for new users to see
all the related options, those commands should become options under
the existing **package** command.

# Specification

Additional **package** command options will be added with the
following subcommand syntax:

	    package create     ;pkg::create
	    package mkIndex    ;pkg_mkIndex

Each represents the existing command that is commented. The arguments
to each would remain what the current command takes.

The following old commands could then potentially be eventually
deprecated:

	    pkg::create
	    pkg_mkIndex

# Copyright

This document has been placed in the public domain.

Name change from tip/254.tip to tip/254.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

TIP:            254
Title:          New Types for Tcl_LinkVar
Version:        $Revision: 1.6 $
Author:         Rene Meyer <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        21-Jul-2005
Post-History:   
Tcl-Version:    8.5


~ Abstract

Currently only a limited set of types of C variable may be linked to
using Tcl_LinkVar. This TIP proposes extending this to cover all the
basic numeric C types.

~ Rationale

With the current implementation it is not possible to link the
following types directly to a Tcl variable, making it much more
difficult to couple such variables to the Tcl level (compared with
'''int''' or '''double''' variables). This TIP fixes this, making it
easier to link C variables and embedded Tcl code.

 * '''char'''

 * '''unsigned char'''

 * '''short'''

 * '''unsigned short'''

 * '''unsigned int'''

 * '''long'''

 * '''unsigned long'''

 * '''Tcl_WideUInt'''

 * '''float'''

There will be no impact on current applications.

~ Specification

The new types are inserted as new '''#define TCL_LINK_*''' statements
in the ''tcl.h'' header file and in the '''switch''' statements in the
''Tcl_Link'' functions.

The documentation of ''Tcl_*Link*'' should mention the new types.

~ Reference Implementation

A reference implementation is available as Patch #1242844 on
SourceForge[http://sf.net/support/tracker.php?aid=1242844].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|


|



|
|


|

|

|

|

|

|

|

|

|



|

|
|
|

|

|

|
|

|


>

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

# TIP 254: New Types for Tcl_LinkVar

	Author:         Rene Meyer <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        21-Jul-2005
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

Currently only a limited set of types of C variable may be linked to
using Tcl\_LinkVar. This TIP proposes extending this to cover all the
basic numeric C types.

# Rationale

With the current implementation it is not possible to link the
following types directly to a Tcl variable, making it much more
difficult to couple such variables to the Tcl level \(compared with
**int** or **double** variables\). This TIP fixes this, making it
easier to link C variables and embedded Tcl code.

 * **char**

 * **unsigned char**

 * **short**

 * **unsigned short**

 * **unsigned int**

 * **long**

 * **unsigned long**

 * **Tcl\_WideUInt**

 * **float**

There will be no impact on current applications.

# Specification

The new types are inserted as new **\#define TCL\_LINK\_\*** statements
in the _tcl.h_ header file and in the **switch** statements in the
_Tcl\_Link_ functions.

The documentation of _Tcl\_\*Link\*_ should mention the new types.

# Reference Implementation

A reference implementation is available as Patch \#1242844 on
SourceForge<http://sf.net/support/tracker.php?aid=1242844> .

# Copyright

This document has been placed in the public domain.

Name change from tip/255.tip to tip/255.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

TIP:		255
Title:		Add 'min' and 'max' [expr] Functions
Version:	$Revision: 1.6 $
Author:		Jeff Hobbs <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Created:	21-Jul-2005
Post-History:	


~ Abstract 

This TIP proposes enhancing the Tcl '''expr''' command with '''min'''
and '''max''' functions.

~ Rationale 

Many programs need to find the minimum or maximum of a set of numbers,
so having functions to do this will make many script programmers'
lives easier. This will be adopting yet another feature from TclX, but
with the minor enhancement of being able to handle arbitrary numbers
of arguments.

~ Specification 

The '''min''' and '''max''' functions shall be created using Tcl
commands (in a namespace such all namespaces will pick them up by
default) in the new 8.5 '''expr''' function style (see [232]). They
will take one or more numeric arguments (of any valid numeric type)
and return the minimum or maximum value of those numbers (depending on
which function was invoked).

~ Examples

| expr {min(0,3,1)}
| => 0
| expr {max(4.2, 0xF, wide(1))}
| => 15.0
| expr {min(4.2)}
| => 4.2
| expr {min()}
| => too few arguments for math function

~ Reference Implementation 

[[To be uploaded to SourceForge and URL added to this TIP.]]

~ Copyright 

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|

|







|

|
|
|
|
|
|

|

|
|
|
|
|
|
|
|

|

|

|


>

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

# TIP 255: Add 'min' and 'max' [expr] Functions

	Author:		Jeff Hobbs <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Created:	21-Jul-2005
	Post-History:	
-----

# Abstract 

This TIP proposes enhancing the Tcl **expr** command with **min**
and **max** functions.

# Rationale 

Many programs need to find the minimum or maximum of a set of numbers,
so having functions to do this will make many script programmers'
lives easier. This will be adopting yet another feature from TclX, but
with the minor enhancement of being able to handle arbitrary numbers
of arguments.

# Specification 

The **min** and **max** functions shall be created using Tcl
commands \(in a namespace such all namespaces will pick them up by
default\) in the new 8.5 **expr** function style \(see [[232]](232.md)\). They
will take one or more numeric arguments \(of any valid numeric type\)
and return the minimum or maximum value of those numbers \(depending on
which function was invoked\).

# Examples

	 expr {min(0,3,1)}
	 => 0
	 expr {max(4.2, 0xF, wide(1))}
	 => 15.0
	 expr {min(4.2)}
	 => 4.2
	 expr {min()}
	 => too few arguments for math function

# Reference Implementation 

[To be uploaded to SourceForge and URL added to this TIP.]

# Copyright 

This document has been placed in the public domain.

Name change from tip/256.tip to tip/256.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

TIP:            256
Title:          Implement Tabular and Wordprocessor Style Tabbing
Version:        $Revision: 1.15 $
Author:         Vince Darley <[email protected]>
Author:         Vince Darley <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        12-Aug-2005
Post-History:   
Tcl-Version:    8.5


~ Abstract

There are two common style of tabbing in the computer world: that used
for a regular table of information, and that used by a
word-processor/text editor. This TIP proposes to add support for the
latter to Tk's '''text''' widget.

~ Overview

Tk's '''text''' widget has historically only supported a ''tabular''
style of tabbing, where the n'th tab character is associated
explicitly with the n'th tab stop (irrespective of whether that stop
is to the left or right of the current x-position - if that stop is to
the left then a single space is inserted as a fallback). A
''wordprocessor'' (or typewriter) has a different style in which a tab
character is associated with the next tab stop to the right of the
current x-position.

This TIP proposes to add wordprocessor-style tabbing to Tk's
'''text''' widget.

Tk 8.4 only supports tabular tabbing (except for the special ''-tabs
{}'' case, which uses wordprocessor style 8-tabs!), although none of
this is clearly documented at all. Tk 8.5 at present actually only
supports wordprocessor style tabbing (and fixed a bunch of other bugs
present in Tk 8.4's tab handling). This behaviour change was an
inadvertent result of fixing bugs in the code without the correct
behaviour being very clearly specified. Hence this TIP will restore
the old behaviour (minus bugs) as the default, and add the option of
the new wordprocessor style behaviour.

~ Proposal

A new '''-tabstyle''' configuration option will be added to the
'''text''' widget, taking the values '''wordprocessor''' or
'''tabular''' to specify the style of tabbing.  The same option will
also be added to '''tags''' in the text widget (which, as usual, will
also allow an empty value for the configuration option). The default
style of tabbing will be '''tabular''' for compatibility with Tk 8.4.
Neither style name may be abbreviated.

As a result of this change, abbreviations such as '''-ta''' or
'''-tab''' will become ambiguous and trigger an error.  This is
considered a bug in the calling script (and a trivial thing to fix in
such scripts).  Similar ambiguities have been introduced by TIPs in
the past (e.g. with ''grid'').  It may actually be a useful ambiguity,
in that it will alert script writers to the fact that new tabbing
functionality is available, and in particular that a decision on
desired tab style needs to be made.

In addition the strange difference in Tk 8.4 between an empty
'''-tabs''' value and any other value will be changed for Tk 8.5 - it
will use the '''-tabstyle''' option to determine how to interpret tabs
under all circumstances, and use the '''-tabs''' list simply to
determine the location of the tab stops.

Here's an example usage:

|pack [text .t]
|.t configure -tabs {0.5i 1.0i 1.5i 2.0i 2.5i 3.0i 3.5i 4.0i 4.5i}
|.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
|.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
|.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
|.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
|.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
|.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
|.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
|.t tag configure wordprocessor -tabstyle wordprocessor
|.t tag add wordprocessor 3.0 5.0
|.t tag configure tabular -tabstyle tabular
|.t tag add tabular 5.0 7.0

and here's an example showing how Tk 8.4 does ''not'' move you to the
next tab stop to the right each time:

|pack [text .t]
|.t configure -tabs {0.25i}
|.t insert end "[string repeat a 20][string repeat \tb 10]"

The above behaves completely differently in Tk 8.4 and 8.5 at present.

~ Implementation

A full implementation, with documentation and tests is available
at SourceForge
[http://sf.net/tracker/?func=detail&aid=1247835&group_id=12997&atid=112997].
The bug report also contains some further discussion on this issue.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|

|

|

|

|
|




|

|
|

|
|


|


|

|
|
|
|
|
|


|
|
|
|
|





|
|
|




|
|
|
|
|
|
|
|
|
|
|
|
|

|


|
|
|



|



|


|


>

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

# TIP 256: Implement Tabular and Wordprocessor Style Tabbing

	Author:         Vince Darley <[email protected]>
	Author:         Vince Darley <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        12-Aug-2005
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

There are two common style of tabbing in the computer world: that used
for a regular table of information, and that used by a
word-processor/text editor. This TIP proposes to add support for the
latter to Tk's **text** widget.

# Overview

Tk's **text** widget has historically only supported a _tabular_
style of tabbing, where the n'th tab character is associated
explicitly with the n'th tab stop \(irrespective of whether that stop
is to the left or right of the current x-position - if that stop is to
the left then a single space is inserted as a fallback\). A
_wordprocessor_ \(or typewriter\) has a different style in which a tab
character is associated with the next tab stop to the right of the
current x-position.

This TIP proposes to add wordprocessor-style tabbing to Tk's
**text** widget.

Tk 8.4 only supports tabular tabbing \(except for the special _-tabs
\{\}_ case, which uses wordprocessor style 8-tabs!\), although none of
this is clearly documented at all. Tk 8.5 at present actually only
supports wordprocessor style tabbing \(and fixed a bunch of other bugs
present in Tk 8.4's tab handling\). This behaviour change was an
inadvertent result of fixing bugs in the code without the correct
behaviour being very clearly specified. Hence this TIP will restore
the old behaviour \(minus bugs\) as the default, and add the option of
the new wordprocessor style behaviour.

# Proposal

A new **-tabstyle** configuration option will be added to the
**text** widget, taking the values **wordprocessor** or
**tabular** to specify the style of tabbing.  The same option will
also be added to **tags** in the text widget \(which, as usual, will
also allow an empty value for the configuration option\). The default
style of tabbing will be **tabular** for compatibility with Tk 8.4.
Neither style name may be abbreviated.

As a result of this change, abbreviations such as **-ta** or
**-tab** will become ambiguous and trigger an error.  This is
considered a bug in the calling script \(and a trivial thing to fix in
such scripts\).  Similar ambiguities have been introduced by TIPs in
the past \(e.g. with _grid_\).  It may actually be a useful ambiguity,
in that it will alert script writers to the fact that new tabbing
functionality is available, and in particular that a decision on
desired tab style needs to be made.

In addition the strange difference in Tk 8.4 between an empty
**-tabs** value and any other value will be changed for Tk 8.5 - it
will use the **-tabstyle** option to determine how to interpret tabs
under all circumstances, and use the **-tabs** list simply to
determine the location of the tab stops.

Here's an example usage:

	pack [text .t]
	.t configure -tabs {0.5i 1.0i 1.5i 2.0i 2.5i 3.0i 3.5i 4.0i 4.5i}
	.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
	.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
	.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
	.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
	.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
	.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
	.t insert end "a\tb\tc\tasdbcanasdasd\te\tf\tg\n"
	.t tag configure wordprocessor -tabstyle wordprocessor
	.t tag add wordprocessor 3.0 5.0
	.t tag configure tabular -tabstyle tabular
	.t tag add tabular 5.0 7.0

and here's an example showing how Tk 8.4 does _not_ move you to the
next tab stop to the right each time:

	pack [text .t]
	.t configure -tabs {0.25i}
	.t insert end "[string repeat a 20][string repeat \tb 10]"

The above behaves completely differently in Tk 8.4 and 8.5 at present.

# Implementation

A full implementation, with documentation and tests is available
at SourceForge
<http://sf.net/tracker/?func=detail&aid=1247835&group_id=12997&atid=112997> .
The bug report also contains some further discussion on this issue.

# Copyright

This document has been placed in the public domain.

Name change from tip/257.tip to tip/257.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337

338
339
340
341
342
343
344
345

346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445

446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465

466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531


532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007

1008
1009
1010
1011
1012

1013
1014
1015
1016
1017
1018
1019

1020
1021
1022
1023
1024
1025


1026
1027
1028
1029
1030

1031
1032
1033
1034
1035
1036


1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691

TIP:            257
Title:          Object Orientation for Tcl
Version:        $Revision: 1.31 $
Author:         Donal K. Fellows <[email protected]>
Author:         Will Duquette <[email protected]>
Author:         Steve Landers <[email protected]>
Author:         Jeff Hobbs <[email protected]>
Author:         Kevin Kenny <[email protected]>
Author:         Miguel Sofer <[email protected]>
Author:         Richard Suchenwirth <[email protected]>
Author:         Larry W. Virden <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        26-Sep-2005
Post-History:   
Obsoletes:      50
Tcl-Version:    8.6


~ Abstract

This TIP proposes adding OO support to the Tcl core, semantically inspired by
XOTcl. The commands it defines will be in the '''::oo''' namespace, which is
not used by any current mainstream OO system, and it will be designed
specifically to allow other object systems to be built on top.

~ Rationale and Basic Requirements

Tcl has a long history of being comparatively agnostic about object-oriented
programming, not favouring one OO system over another while promoting a wealth
of OO extensions such as [[incr Tcl]][http://incrtcl.sourceforge.net/itcl/],
OTcl[http://bmrc.berkeley.edu/research/cmt/cmtdoc/otcl/],
XOTcl[http://media.wu-wien.ac.at/],
stooop[http://jfontain.free.fr/stooop.html],
Snit[http://www.wjduquette.com/snit/], etc. because in general, one size fits
nobody.

However, many application domains require OO systems and having a common such
base system will help prevent application and library authors from reinventing
the wheel each time through because they cannot rely on an OO framework being
present with each and every Tcl installation. For example, the http package
supplied with Tcl has its own internal object model, and a similar mechanism
is reinvented multiple times within tcllib. Other parts of tcllib do their own
thing (to say nothing of the fact that both stooop and Snit are in tcllib
themselves). This does not promote efficient reuse of each others code, and
ensures that each of these packages has a ''poor'' object system. The request
for an OO system is also one of the biggest feature requests for Tcl, and
would make it far easier to implement megawidgets. It also leaves Tcl open to
the ill-informed criticism that it doesn't support OO, despite being spoilt
for choice in reality through the extensions listed above.

Given all this, the time has come for the core to provide OO support. The aim
of the core OO system shall be that it is simple to get started with, flexible
so that it can take you a long way, fast (we all know that we're going to get
compared on this front!), and suitable for use as a foundation of many other
things, including the re-implementation of various existing OO extensions,
including those that are currently compiled and also those that are pure Tcl
extensions.

Another requirement is that programmers should not have to alter all of their
existing code in order to get started with the new system; rather, they should
be able to adopt it progressively, over time, because it supports better ways
of working (e.g., faster and more flexible libraries).

~ The Foundational OO System

This TIP proposes that the foundation of the OO system should ensure that it
is simple, fast and flexible. Semantically, the OO system should be using the
semantic model pioneered by OTcl and XOTcl, as leveraging their experience on
the complex parts (e.g., the model of multiple inheritance, how to invoke
superclass implementations of a method) allows us to go straight to a solution
that is rich enough for a very large space of applications.

However, some changes relative to XOTcl are necessary. Certain aspects of
XOTcl syntax are peculiar from a conventional OO point-of-view, and it is
deeply unfortunate that a very large number of methods are predefined in the
XOTcl base class. XOTcl's approach to object creation options is also highly
idiosyncratic (though critical to the way XOTcl itself works) and doesn't
really support the typical Tcl idioms. The changes must be made in such a way
that something that works like classic XOTcl for virtually all uses can be
built on the new framework, but the core object framework must also enable
building [[incr Tcl]]-like or Snit-like object systems on top.

Note that by keeping things in the base classes comparatively simple, it is
much easier to build multiple extended OO frameworks on top.

~~ Key Features

~~~ Functional Requirements

 * Class-based object system. This is what most programmers expect from OO,
   and it is very useful for many tasks.

 * Allows per-object customization and dynamic redefinition of classes.

 * Supports advanced OO features, such as:

 > meta-classes: These are subclasses of '''class''', which permit more
   advanced customization of class behaviour.

 > filters: These are constraints (implemented in Tcl code, naturally) on
   whether a method may be called.

 > mixins: These allow functionality to be brought into an object from other
   objects if necessary, enabling better separation of concerns.

 * A system for implementing methods in custom ways, so that package authors
   that want significantly different ways of doing a method implementation may
   do so fairly simply. Note that this will require additional C code to
   perform; this API will not be exposed directly to the script level (since
   it makes little sense there).

~~~ Non-Functional Requirements

Note that these requirements would need to be imposed on any implementation of
an object system in the Tcl core code anyway.

 * The speed of the object system is something on which it is easy to predict
   that Tcl will end up being compared to other languages. Hence, the core OO
   system ''must'' permit efficient implementation.

 * The core OO system must be clear code that it is easy for the Tcl
   maintainers to keep in good order. The Engineering Manual [247] will be
   followed.

~~ Key Alterations Relative to XOTcl

The core OO system can be considered to be a derivative of XOTcl, much as C
can be considered to be a derivative of Algol. However, like the C/Algol
relationship, there are many changes between the core OO system and XOTcl; the
''implementations'' are not common.

 * Object and class names in the core extension to be all lower-case, in line
   with best common practice in general Tcl code.

 * Methods have to be capable of being non-exported, by which we mean that
   they are not (simply) callable from contexts outside the object.

 * The majority of the API for updating an object or class's definition is to
   be moved to a separate utility command, '''oo::define'''.

 * More "conventional" naming of operations is to be used.

 * Many of the more advanced features of XOTcl are not present, especially
   when it is possible to implement them on top of other features. This
   particularly applies to:

 > * Filter- and mixin-guards

 > * Invariants

 > * Pre- and post-conditions

Note that this TIP does ''not'' propose to actually include any XOTcl (or Itcl
or Snit or ...) compatibility packages in the core; it is about forming a
foundation on which they can be built (which happens to also be a
comparatively lightweight OO system in itself). Such compatibility packages
can either remain separate code, or be the subject of future TIPs.

~ Detailed Rationale for Not Using XOTcl

~~ Features of XOTcl that are Retained

Many key semantic features of XOTcl are adopted with little or no change. In
particular, the following critical features of the core object system shall be
semantically the same as in XOTcl as they represent the best-of-breed in
advanced object systems at the moment.

~~~ Multiple Inheritance

We shall support multiple inheritance (MI) because this is very difficult to
add after the fact.

The main problem with MI in languages like C++ was always confusion caused by
the fact that methods were resolved using integer offsets into method tables.
By contrast, single inheritance is far too restrictive. By supporting mixins
and filters, it becomes possible to build not just conventional OO systems in
the C++ or Java mould, but also to make Self-like prototype systems (which
requires mixins and subclassing of the class of classes to work) and
Aspect-like systems (which require filters for efficient implementation). As
these are less well-known terms than those of normal inheritance, we define
them here:

 mixin: An auxiliary ''class'' whose behaviour is "mixed into" the current
   object or class, adding the mixin's methods to the target's methods. Often
   used to support cross-cutting functionality or object roles.

 filter: A nominated ''method'' that is permitted to control whether all calls
   to any other method of a class or object occur. This control is achieved by
   the nominated filter method being chained on the front of the sequence of
   methods in the "implementation list" for the actual target method. Often
   used to support transparent orthogonal functionality, such as access
   control or result caching.

~~~ The Method Dispatch Algorithm

The use of a complex class graph model as described above requires a
sophisticated algorithm to linearize any particular call of a method into a
sequence of method implementations that should be called. This is the method
dispatch algorithm. The algorithm works by scanning the graph of the object
and its associated classes in the order given below, collecting
implementations as they are found in a list, with an implementation coming in
the ''last'' position in the list it can be; if it would be in twice because
of an "inheritance diamond", it comes in the later location.

 1. Filters defined on classes mixed into the object or its class (or
    superclasses), with filters from a particular class processed in the order
    that they are described by that class.

 2. Filters defined on the object, in the order that they are described in the
    object's filter list.

 3. Filters defined on the class of the object (or its superclasses), with
    filters from a particular class processed in the order that they are
    described by that class.

 4. Methods declared by mixins added to the object, with mixins being
    processed in the order that they are described in the object's mixin list
    (the set of methods declared by the mixin are determined by recursively
    applying this algorithm).

 5. Methods declared by mixins added to the object's class or superclasses,
    with mixins to a particular class being processed in the order that they
    are described in the class's mixin list.

 6. Methods declared by the object itself.

 7. Methods declared by the object's class itself.

 8. Methods declared by the object's class's superclasses, with superclasses
    being processed in the order that they are described in the class's
    superclass list.

Given the above ordering, for each method on an object there is an ordered
list of implementations. We dispatch the method by executing the first
implementation on the list, which can then hand off to subsequent methods in
the list in order using the '''next''' command (described below).

Another way to view the ordering is that there are several layers to the
ordering scheme. Firstly, there is the basic ordering which is: object, class,
superclasses to root (with multiple inheritance being processed in the listed
order, and classes appearing in the linearized tree as late as possible). Then
there is the second-order ordering, which adds mixins to the front of the
basic ordering, where the order of the mixins is processed in basic ordering.
Finally, there is the third-order ordering which adds filters to the front of
the second-order ordering, with filter name sources being processed in
second-order ordering and the method chain for a particular filter being
processed in second-order ordering order.

Note that a filter being invoked as a filter is different to a filter being
invoked as a normal method. If a filter method is invoked directly, then it
will actually be invoked twice, once as a filter and once as a conventional
method.

~~ Essential Changes Relative to XOTcl

Unfortunately, not all features of XOTcl are suitable for a core object
system. In particular, many more syntactic features need to be altered. This
section describes these, together with the rationale for each change; the
rationales are marked with the word "'''Therefore'''", in bold.

~~~ Exported vs. Non-exported Methods

In XOTcl, every class and every object has an associated namespace. The
namespace associated with a class ''::myclass'' is
''::xotcl::classes::myclass''; the namespace associated with object
''::myobject'' is simply ''::myobject''. XOTcl "instprocs" are simply procs
defined in a class (or superclass) namespace; XOTcl per-object "procs" are
simply procs defined in an object's namespace. ''Every such proc becomes an
object subcommand.''

This is part of the reason why XOTcl objects have such cluttered interfaces.
Every method which is of use to the object appears in the object's interface -
and there's no way to prevent this.

'''Therefore''', in the new oo system "'''proc'''s" and "'''instproc'''s" can
be exported or non-exported. Exported procs appear as object subcommands;
non-exported procs do not, but remain available as subcommands of the '''my'''
command. In this way, the object itself can still use them, but they need
appear in the object's interface only if desired.

Additionally, the standard introspection system will need to be extended to
allow determining of which methods are exported and which are not.

~~~ The oo::define Command

In XOTcl, the commands to define per-class methods, filters, and so on are
subcommands of the class object; the commands to define per-object methods,
filters, and so on are subcommands of the individual object. This is a
problem, as it confuses the implementation-time interface with the run-time
interface. The design is logical, given XOTcl's extreme dynamism; any
implementation-time activity, such as defining a method or adding a filter can
indeed be done at run-time. But again, this makes it difficult to define clean
run-time interfaces for reusable library code.

The solution described in the previous section, of making some methods private
by declaring them non-exported, does not give us a full solution; having the
'''instproc''' subcommand available only from instance code isn't all that
useful.

'''Therefore''', we add two new commands, '''oo::define''' and
'''oo::objdefine''', which are used to define methods, filters, and so on.
They can be called in two ways, with each command having essentially the same
fundamental syntax. The first calling model is as follows:

 > '''oo::define''' ''class subcommand args...''

 > '''oo::objdefine''' ''object subcommand args...''

For example, the following XOTcl code defines a class with two methods:

|xotcl::Class myclass
|myclass instproc dothis {args} { # body }
|myclass instproc dothat {args} { # body }

In the new oo core, the matching code would be this:

|oo::class create myclass
|oo::define myclass method dothis {args} { # body }
|oo::define myclass method dothat {args} { # body }

The two definition commands will also have a second calling model, in which
they get passed a single definition script whose commands are the subcommands
supported by the command as described above:

 > '''oo::define''' ''class script''

 > '''oo::objdefine''' ''object script''

Thus, the above code could also be written as follows:

|oo::class create myclass
|oo::define myclass {
|    method dothis {args} { # body }
|    method dothat {args} { # body }
|}


Finally, the constructor for the '''oo::class''' class is extended so that
such a script can be used during class creation:

|oo::class create myclass {
|    method dothis {args} { # body }
|    method dothat {args} { # body }
|}


This allows a class to be defined cleanly and concisely, while guaranteeing
that all class details can still be modified later on using '''oo::define'''.

To enable the easy definition of details of the class object at class
definition time, a special subcommand, "'''self'''", will be provided that is
equivalent to using '''oo::objdefine''' on the class.

Note that because of the requirement for a distinction between public and
private interfaces, '''oo::define''' and '''oo::objdefine''' will need two
subcommands XOTcl doesn't currently provide: '''export''' and '''unexport'''.
'''export''' takes as arguments a list of method names; all named methods are
exported and become visible in the object or class's interface. '''unexport'''
does the opposite. Note that by default, all methods that start with a
lower-case letter (specifically, names matching the glob pattern "[[a-z]]*")
will be exported by default and all other methods will be unexported.

~~~ Standard Metaclasses

XOTcl defines two standard Metaclasses, ''xotcl::Object'' and
''xotcl::Class''. ''xotcl::Object'' is the root of the class hierarchy; all
XOTcl classes implicitly inherit from ''xotcl::Object''. XOTcl classes are
themselves objects, and are instances of ''xotcl::Class''. ''xotcl::Class''
can itself be subclassed to produce different families of classes with
different standard behaviours.

The new core object system will use the same basic mechanism, based on the
metaclasses '''oo::object''' and '''oo::class'''. However, one of the problems
with XOTcl is that XOTcl objects have too much standard behavior; the new core
object system must provide a simpler foundation, with the XOTcl behavior
optionally available.

'''Therefore''', we will extract the features of ''xotcl::Object'' and
''xotcl::Class'' that are critical into our classes and leave all other
functionality up to any subclasses or metaclasses that are defined.

Thus '''oo::object''' will be the root of the class hierarchy. However,
instances of '''oo::object''' will have a minimal set of standard methods, so
that clean interfaces can be built on top of it, as can be done with Snit
types and instances.

Core object system classes will be instances of '''oo::class''' or its
subclasses. Likewise, '''oo::class''' will define only minimal behaviour.

~~~ Inheritance

A class may wish to make use of the capabilities of '''oo::class''' internally
without exporting its methods (e.g., for providing a singleton instance).

'''Therefore''', the inheritance mechanism should be extended such that the
newly defined class can declare whether a parent class's methods should be
exported or not, on a case-by-case basis. 

~~~ Object Creation

XOTcl has a unique creation syntax. The object name can be followed by what
look like Tk or Snit options - but aren't. Instead, any token in the argument
list that begins with a hyphen is assumed to be the name of one of the
object's methods; it must be followed by the method's own arguments. For
example, a standard XOTcl class will have a "set" method, which has the same
syntax as the standard Tcl "set" command. Thus, the following code:

|    myclass myobj -set a 1 -set b 2

creates an instance of "myclass" called "myobj" whose instance variables "a"
and "b" and set to 1 and 2 respectively. This is an intriguing and innovative
interface, and it is unlike any other Tcl object system. Additionally, it
makes it difficult to implement standard Tk-like options.

'''Therefore''', standard core object system classes will not use this
mechanism (though it might be available on demand by inheriting from some
other standard metaclass). Instead, standard core object system classes will
have no creation behavior other than that implemented by their designers in
their constructors.

Constructors may have any argument list the user pleases, including default
arguments, the "args" argument (as in the '''proc''' command), and XOTcl-style
non-positional arguments. It is up to the developer to handle the arguments
appropriately.

It is expected that one of the key responsibilities of any XOTcl compatability
package would be to define an object/class construction system that parses the
arguments in the expected way and uses them to invoke methods on the newly
created object.

~~~ Constructor Syntax

In XOTcl, a class's constructor is implemented using its "init" instproc. This
is troubling; constructors are intended to do things just once, and are often
written to take advantage of that, whereas an "init" instproc can
theoretically be called at any time. For any given class, then, one of two
conditions will obtain: either "init" must be written so that it can be called
at any time, or the class will have an inherent logic bug.

'''Therefore''', the class constructor will not be implemented as a standard
instproc. Instead, the '''oo::define''' command will have a new subcommand,
'''constructor''', which will be used as follows:

|oo::define myclass constructor {} {
|    # body
|}


The constructor so defined will act almost exactly like an instproc; it may
call superclass constructors using the "super" command, etc. However, it may
never be called explicitly, but only via the class's "create" and "new"
methods.

~~~ Destructor Syntax

In XOTcl, a class's destructor is defined by overriding the "destroy"
instproc. This is problematic for two reasons: first, a destructor doesn't
need an argument list. An instproc is too powerful for the task. Second,
successful destruction should not depend on the destructor's chaining to its
superclass destructors properly.

'''Therefore''', the class destructor will be defined by a new subcommand of
'''oo::define''', '''destructor''', as follows:

|oo::define myclass destructor {
|    # Body
|}


The destructor has no argument list.

The destructor cannot be called explicitly. Instead, the destructors are
invoked in the proper order by the standard '''destroy''' method (defined in
'''oo::object'''), which need never be overridden.

If an error occurs in a destructor, it will ''not'' prevent the object from
being deleted. There is no guarantee to run destructors when an interpreter or
Tcl-enabled process exits.

~~~ Behavior and Syntax of next

In XOTcl, the '''next''' command is used to invoke the "next" method in the
dispatch chain. It optionally takes arguments to process (if they are omitted,
it passes all arguments that were passed to the current method) and it calls
the appropriate superclass implementation. But it does so without adjusting
the Tcl stack, which forces classes to take extreme care when implementing
code that needs to access variables or evaluate scripts in the scope of the
code that invoked the method in the first place.

'''Therefore''', the '''next''' command will perform Tcl stack management so
that using '''uplevel''' and '''upvar''' in a method will be just like doing
so in a normal procedure, no matter how the class containing that method is
subclassed.

In addition, the adoption of [157] makes explicit handling of arguments
practical as code does not need to perform potentially troublesome operations
with '''eval''', and so '''next''' will always require that all argument be
passed explicitly. This also makes it easier to decide to pass no arguments to
a superclass implementation.

~~ Desirable Changes

The changes described in this section are not absolutely essential to meeting
the goals described earlier. However, they are desirable in that they lead to
cleaner, more maintainable code.

~~~ Class vs. Object Method Naming

XOTcl has many features which can be applied to a class for use by all class
instances, or to a single object. For example, a "filter" can be defined for a
single object, while an "instfilter" can be defined for a class and applied to
all instances of that class.

This is exactly backward. Most behavior will be defined for classes;
additional per-object behavior is the special case, and consequently should
have the less convenient name.

'''Therefore''', all definition subcommands that begin with "inst" will be
defined, in the core OO system without their "inst" prefix; the per-object
subcommands will be manipulated via '''oo::objdefine''' or through the "self"
prefix command (described above), to indicate that it is operating on the
object itself and not the members of the class. Thus, a filter is defined on a
class for its instances using the "filter" subcommand; a filter is defined on
a particular object using the "self filter" subcommand (actually a subcommand
of a subcommand).

| oo::define someCls {
|     method foo {} {...}
|     self {
|         method bar {args} {...}
|         filter bar
|     }
| }



~~~ Procs vs. Methods

The word "proc" conveys a standalone function; an object's subcommands are
more typically described as its "methods".

'''Therefore''', the core OO system will use "method" in place of "proc" for
definitions.

~~~ Public Names

In XOTcl, the main objects are ''xotcl::Class'' and ''xotcl::Object''.
However, the Tcl Style Guide dictates that public command names begin with a
lower-case letter.

'''Therefore''', all public names in the ''oo::'' namespace (i.e. the standard
classes) will begin with a lower case letter, e.g., the standard core object
system equivalents of ''xotcl::Class'' and ''xotcl::Object'' will be
'''oo::class''' and '''oo::object'''.

This does not constrain any code making use of the OO system from naming
objects however it wants.

~ API Specification

This section documents the core object system API in detail, based on the
essential and desirable changes discussed in the previous sections.

~~ Helper Commands

The namespace(s) that define the following three commands are not defined in
this specification unless otherwise stated; all that is defined is that they
will be on the object's '''namespace path''' during the execution of any
method and should always be used without qualification.

~~~ my

The '''my''' command allows methods of the current object to be called during
the execution of a method, just as if they were invoked using the object's
command. Unlike the object's command, the '''my''' command may also invoke
non-exported methods.

 > '''my''' ''methodName'' ?''arg'' ''arg'' ...?

Note that each object has its own '''my''' command; they are all distinct from
each other. This means that it is suitable for use for things like invoking
callbacks (from general Tcl code) that are non-public methods. In particular,
the use of '''namespace code''' for encapsulating the use of '''my''' for
invoking unexported callback methods by non-object code is supported.

Note that the '''my''' command does not represent the name of the object.

~~~ next

The '''next''' command allows methods to invoke the implementation of the
method with the same name in their superclass (as determined by the normal
inheritance rules; if a per-object method overrides a method defined by the
object's class, then the '''next''' command inside the object's method
implementation will invoke the class's implementation of the method). The
arguments to the '''next''' command are the arguments to be passed to the
superclass method. The current stack level is temporarily bypassed for the
duration of the processing of the '''next''' command; this allows a method to
always execute identically with respect to the main calling context without
needing to use some form of introspection to determine where that context is
on the call frame stack (with a side effect of isolating method
implementations from each other).

 > '''next''' ?''arg'' ''arg'' ...?

It is an error to invoke the '''next''' command when there is no superclass
definition of the current method.

~~~ self

The '''self''' command allows executing methods to discover information about
the object which they are currently executing in; it's always an error if not
inside a method. Without arguments, the '''self''' command returns the current
fully-qualified name of the object (to promote backward compatability).
Otherwise, it is a command in the form of an ensemble (though it is not
defined whether it is manipulable with '''namespace ensemble''').

The following subcommands of '''self''' are defined. None of these subcommands
take additional arguments.

 caller: Returns a three-item list describing the class, object and method
   that invoked the current method, respectively. The syntax is as follows:

 > '''self caller'''

 class: Returns the name of the class that defines the currently executing
   method. If the method was declared in the object instead of in the class,
   this returns the class of the object containing the method definition. The
   syntax is as follows:

 > '''self class'''

 filter: When invoked inside a filter, returns a three-item list describing
   the object or class for which the filter has been registered. The first
   element is the name of the class or object, the second element is either
   '''class''' (for a filter defined on a class for its instances) or
   '''object''' (for a filter defined on a single object), and the third
   element is the name of the method. The syntax is as follows:

 > '''self filter'''

 method: Returns the name of the currently executing method. The syntax is as
   follows:

 > '''self method'''

 namespace: Returns the namespace associated with the current object. The
   syntax is as follows:

 > '''self namespace'''

 next: Returns a two-element list describing the method that will be executed
   when the '''next''' command is invoked, or an empty list if there is no
   subsequent definition for the method. The first element of the list is the
   name of the object or class that contains the method, and the second
   element of the list is the name of the method. The syntax is as follows:

 > '''self next'''

 object: Returns the name of the current object, the same as if the '''self'''
   command is invoked with no arguments. The syntax is as follows:

 > '''self object'''

 target: When invoked from a filter, returns a two-item list consisting of the
   name of the class that holds the target method and the name of the target
   method. The syntax is as follows:

 > '''self target'''

For all these commands, when the name of a method is returned, it will be
"''<constructor>''" when the method is a constructor, and "''<destructor>''"
when the method is a destructor. It should be noted that these are not the
actual names of the constructor and destructor (they are unnamed methods);
they are just notational conventions supported by the '''self''' command.

~~ The oo::define Command

 > '''oo::define''' ''class'' ''subcommand'' ?''arg'' ...?

 > '''oo::define''' ''class'' ''script''

 > '''oo::objdefine''' ''object'' ''subcommand'' ?''arg'' ...?

 > '''oo::objdefine''' ''object'' ''script''

The '''oo::define''' command is used to add behavior to classes, and the
'''oo::objdefine''' command is used to add behavior to objects. The first form
of each command is conventional for ensemble-like commands, except that the
''class'' or ''object'' argument precedes the ''subcommand'' argument. In the
second form of each command, ''script'' is a Tcl script whose commands are the
subcommands of '''oo::define''' or '''oo::objdefine'''; this is a notational
convenience, as the two forms are semantically equivalent in what their
capabilities are. (Note that the context in which ''script'' executes is
otherwise not defined.)

~~~ Class-related Subcommands

The subcommands of '''oo::define''' (which may be unambiguously abbreviated
in both the subcommand form and the script form) shall be:

 * '''constructor''' - this takes two arguments (a '''proc'''-style argument
   list, and a body script), and sets the constructor for the instances of the
   class to be executed as defined by the body script after binding the actual
   arguments to the call that creates an instance of the class to the formal
   arguments listed. The constructor is called after the object is created but
   before any instance variables are guaranteed to be set. If no constructor
   is specified, the constructor will accept exactly the same arguments as the
   constructor in the parent class, and will delegate all the arguments to
   that parent-class constructor. The syntax is as follows:

 > '''oo::define''' ''class'' '''constructor''' ''argList'' ''body''

 > Note that constructors of class mixins are also called, but constructors of
   object mixins are never called (as the object must exist before it can have
   an auxiliary class mixed into it).

 * '''destructor''' - this defines the class destructor; a destructor is like
   a method but takes no arguments. Destructors are called on all classes that
   define them when the object is deleted, including classes that have been
   mixed in. The syntax is as follows:

 > '''oo::define''' ''class'' '''destructor''' ''body''

 > Note that destructors ''should always'' use the '''next''' command within
   their implementation so that destructors of parent classes are also
   executed.

 > Note also that destructors are called whenever the object is deleted by
   any mechanism (except when the overall interpreter is deleted, when
   execution of Tcl scripts has ceased to be possible anyway).

 * '''export''' - this specifies that the named methods are exported, i.e.,
   part of the public API of the class's instances. The syntax is as follows:

 > '''oo::define''' ''class'' '''export''' ''name'' ?''name'' ...?

 > An exported method is accessible to clients of the class's instances; an
   unexported method is accessible only to the instances' own code through the
   '''my''' command.

 * '''filter''' - this subcommand controls the list of filter methods for a
   class. Each filter method in the list is called when any method is invoked
   on the class's instances, and it is up to the filter to decide whether to
   invoke the filtered method call (using the '''next''' command) or return a
   suitable replacement value. The syntax is as follows:

 > '''oo::define''' ''class'' '''filter''' ?''filterName filterName'' ...?

 * '''forward''' - this subcommand defines a class method which is
   automatically forwarded (i.e. delegated) to some other command, according
   to a simple pattern. Each ''arg'' is used literally. The syntax is as
   follows:

 > '''oo::define''' ''class'' '''forward''' ''name'' ''targetCmd''
   ?''arg'' ...?

 * '''method''' - this subcommand (only valid for classes) defines a class
   method (i.e. a method supported by every instance of the class). By
   default, methods are exported if they start with a lower-case letter (i.e.,
   any character in \u0061 to \u007a inclusive) and are not exported
   otherwise. The syntax is as follows:

 > '''oo::define''' ''class'' '''method''' ''name'' ''args'' ''body''

 * '''mixin''' - This subcommand defines a mixin for a class which is a way of
   bringing in additional method implementations (which may add to or wrap
   existing methods) on an ''ad hoc'' basis. The list of mixins is traversed
   when searching for methods before the inheritance hierarchy, and mixed-in
   methods may chain to any methods they override using the '''next'''
   command. The syntax is as follows:

 > '''oo::define''' ''class'' '''mixin''' ?''mixinClass mixinClass'' ...?

 * '''self''' - This subcommand, which has the same syntax patterns as
   '''oo::objdefine''', allows the manipulation of the class as an object. See
   '''oo::objdefine''' below for a description of the list of subcommands of
   '''self'''. The syntaxes are as follows:

 > '''oo::define''' ''class'' '''self''' ''subcommand'' ?''arg'' ...?

 > '''oo::define''' ''class'' '''self''' ''script''

 * '''superclass''' - This specifies the superclass (or classes) of a class.
   Note that objects are always either classes or not classes, and cannot be
   changed from one to the other by any mechanism. The syntax is as follows:

 > '''oo::define''' ''class'' '''superclass''' ''classList''

 * '''unexport''' - This specifies that the named methods are unexported,
   i.e., private. The syntax is as follows:

 > '''oo::define''' ''class'' '''unexport''' ''name'' ?''name'' ...?

 > An exported method is accessible to clients of the object; an unexported
   method is accessible only to the object's own code, through the '''my'''
   command.

The following utility subcommands are also supported:

 * '''deletemethod''' - This deletes one or more methods from a class; it
   doesn't modify any definitions of the method in superclasses, subclassses,
   instances or mixins. The method names must be specified exactly. Syntax is
   as follows:

 > '''oo::define''' ''class'' '''deletemethod''' ''name'' ?''name'' ...?

 * '''renamemethod''' - This renames a method in a class from one thing to
   another; it doesn't modify any definitions of the method in superclasses,
   subclassses, instances or mixins. Syntax is as follows:

 > '''oo::define''' ''class'' '''renamemethod''' ''fromName'' ''toName''

~~~ Per-Object Subcommands

The following subcommands are all per-object versions of the class subcommands
listed above. When they are applied to a class, they operate on the class
instance itself as an object, and not on the instances (current and future) of
that class (which is why the distinction is required).

 * '''class''' - This subcommand gets and sets the class of an object.
   Changing the class of an object can result in many methods getting added or
   removed. Objects may not be changed between being class-objects and and
   non-class objects. The syntax is as follows:

 > '''oo::objdefine''' ''object'' '''class''' ''className''

 > Note that when the class is changed of an object, no methods are called on
   that object, or on either the source or target classes, to indicate that
   the change has been carried out. This is up to the caller of the
   '''class''' subcommand.

 * '''deletemethod''' - This is a per-object version of the '''deletemethod'''
   subcommand of '''oo::define''', to which it is syntactically identical.

 * '''export''' - This is a per-object version of the '''export''' subcommand
   of '''oo::define''', to which it is syntactically identical.

 * '''filter''' - This is a per-object version of the '''filter''' subcommand
   of '''oo::define''', to which it is syntactically identical.

 * '''forward''' - This is a per-object version of the '''forward'''
   subcommand of '''oo::define''', to which it is syntactically identical.

 * '''method''' - This is a per-object version of the '''method''' subcommand
   of '''oo::define''', to which it is syntactically identical.

 * '''mixin''' - This is a per-object version of the '''mixin''' subcommand of
   '''oo::define''', to which it is syntactically identical.

 * '''renamemethod''' - This is a per-object version of the '''renamemethod'''
   subcommand of '''oo::define''', to which it is syntactically identical.

 * '''unexport''' - This is a per-object version of the '''unexport'''
   subcommand of '''oo::define''', to which it is syntactically identical.

~~ The oo::copy Command

The '''oo::copy''' command creates an exact copy of an object with the given
name. If ''newName'' is the empty string or unspecified, a new name will be
generated automatically. The syntax is as follows:

 > '''oo::copy''' ''object'' ?''newName''?

Note that this command does ''not'' copy the backing namespace, and nor does
it execute any constructors. It is therefore up to the caller to copy such
internal state of the object in the manner suitable for the object and its
class tree; it is suggested that this be done by wrapping the '''oo::copy'''
command in another command that defines which method is called.

~ Core Objects

The following classes are defined, and are the only pre-constructed objects in
the core system.

~~ oo::object

The root of the class hierarchy is '''oo::object'''. There are two ways to
create a new instance of an object.

 > '''oo::object''' '''create''' ''name''

 > '''set''' ''var'' '''[[''' '''oo::object''' '''new''' ''']]'''

The first constructs a new object called ''name'' of class ''oo::object''; the
object is represented as a command in the current scope. The second constructs
a new object of class '''oo::object''' with a name guaranteed to be different
from every existing command and returns the fully qualified of the command
created (which it is naturally a good idea to save in a variable, perhaps
called ''var'').

The name of an object is also the name of a command in the form of an ensemble
where the subcommands of the ensemble are the ''exported'' method names of the
object. The command is not manipulable with '''namespace ensemble''', but may
be renamed.

The new object has one predefined exported method ('''destroy''') and four
predefined non-exported methods ('''eval''', '''unknown''', '''variable''' and
'''varname'''). Other subcommands and other behaviour can be added using
'''oo::define'''.

The '''oo::object''' class (an instance of '''oo::class''') serves as the base
class for all other core OO system classes.

~~~ Constructor and Destructor

The constructor for the '''oo::object''' class takes no arguments and does
nothing. (The actual construction of an object is special and happens before
any constructors are called.)

The destructor does nothing. (The actual destruction of an object is special
and happens after all destructors have completed.)

~~~ Methods

The instances of '''oo::object''' (i.e. all objects and classes) have the
following methods:

 eval: This non-exported method concatenates its arguments according to the
   rules of '''concat''', and evaluates the resulting script in the namespace
   associated with the object. The result of the script evaluation is the
   result of the ''object'' '''eval''' method. The syntax is as follows:

 > ''object'' '''eval''' ?''arg'' ''arg'' ...?

 destroy: This exported method deletes the object; it takes no additional
   arguments and returns the empty string as its result. The syntax is as
   follows:

 > ''object'' '''destroy'''

 unknown: This non-exported method takes a method name and an arbitrary number
   of extra arguments and handles the absence of a method with the given name.
   The default implementation just generates a suitable error message that
   explains what commands are available given how the caller attempted to
   invoke the method, and ignores all the additional arguments. The syntax is
   as follows:

 > ''object'' '''unknown''' ''methodName'' ?''arg'' ...?

 > Note that this method is not normally invoked directly.

 variable: This non-exported method takes an arbitrary number of
   ''unqualified'' variable names and binds the variable with that name in the
   object's namespace to the same name in the current scope, provided the
   current scope is the body of a procedure, procedure-like method, or lambda
   term (as used with '''apply'''); if executed in a context where the current
   scope does not admit local variables, this method will have no effect. The
   syntax is as follows:

 > ''object'' '''variable''' ?''varName'' ''varName'' ...?

 > However, it will be more commonly used as:

 > '''my variable''' ?''varName'' ''varName'' ...?

 > Each ''varName'' argument is the name of a variable in the namespace
   associated with the object, and must not contain any namespace separators.
   Each named variable will be bound to a local variable in the current scope
   with the same name.

 varname: This non-exported method takes one argument, the name of a variable
   to be resolved in the context of the object's namespace, and returns the
   fully qualified name of the variable such that it can be used with the
   '''vwait''' command or extensions such as Tk (e.g., for the '''label'''
   widget's '''-textvariable''' option). This method does not assign any value
   to the variable. The syntax is as follows:

 > ''object'' '''varname''' ''varName''

 > However, it will be more commonly used as:

 > '''my varname''' ''varName''

~~~ Unknown Method Handling

When an attempt is made to invoke an unknown method on any object, the core
then attempts to pass ''all'' the arguments (including the method name) to
the '''unknown''' method of the object. The default implementation of the
'''unknown''' method is specified by the '''oo::object''' class, and just
generates a suitable "unknown subcommand" error message.

~~ oo::class

This class is the class of all classes (i.e. its instances are objects that
manufacture objects according to a standard pattern). Note that
'''oo::object''' is an instance of '''oo::class''', as is '''oo::class'''
itself.

 > '''oo::class''' '''create''' ''name'' ?''definition''?

This creates a new class called ''name''; the class is an object in its own
right (of class '''oo::class'''), and hence is represented as a command in the
current scope. '''oo::class''' returns the fully qualified command name.

The newly-created class command is used to define objects which belong to the
class, just as '''oo::object''' is. By default, instances of the new class
have no more behaviour than instances of '''oo::object''' do; new class
behavior can be added to the class in two ways. First, a ''definition'' can be
specified when creating the class; second, additional behaviour can be added
to the class using '''oo::define'''.

The definition, if given, consists of a series of statements that map to the
subcommands of '''oo::define'''. The following three code snippets are
equivalent; each defines a class called '''::dog''' whose instances will have
two subcommands: '''bark''' and '''chase'''.

|# Method 1
|oo::class create dog
|
|oo::define dog method bark {} {
|    puts "Woof, woof!"
|}

|
|oo::define dog method chase {thing} {
|    puts "Chase $thing!"
|}


|# Method 2
|oo::class create dog
|
|oo::define dog {
|    method bark {} {
|        puts "Woof, woof!"
|    }

|
|    method chase {thing} {
|        puts "Chase $thing!"
|    }
|}



|# Method 3
|oo::class create dog {
|    method bark {} {
|        puts "Woof, woof!"
|    }

|
|    method chase {thing} {
|        puts "Chase $thing!"
|    }
|}



~~~ Constructor and Destructor

The constructor for '''oo::class''' concatenates its arguments and passes the
resulting script to '''oo::define''' (along with the fully-qualified name of
the created class, of course).

Classes have no destructor by default. (Actual class destruction is special,
and happens after all destructors have been executed.)

~~~ Methods

The instances of '''oo::class''' have the following methods:

 create: Creates a new instance of the class with the given name. All
   subsequent arguments are given to the class's constructor (and so must
   actually match the syntax pattern specified in the constructor definition).
   The result of the '''create''' method is always the fully-qualified name of
   the newly-created object. The syntax is as follows:

 > ''class'' '''create''' ''objName'' ?''arg'' ''arg'' ...?

 new: Creates a new instance of the class with an automatically chosen name.
   All subsequent arguments are given to the class's constructor (and so must
   actually match the syntax pattern specified in the constructor definition).
   The result of the '''new''' method is always the fully-qualified name of
   the newly-created object. The syntax is as follows:

 > ''class'' '''new''' ?''arg'' ''arg'' ...?

 > Note that the ''oo::class'' object itself does not export the '''new'''
   method; it is good practice for all classes to have names.

 createWithNamespace: Creates a new instance of a class with a given name and
   a given name of backing namespace. This method (required to provide proper
   support for putting [[incr Tcl]] on top of the core OO system) is not
   exported by default. Apart from the ''nsName'' parameter, it is the same as
   the '''create''' method.

 > ''class'' '''createWithNamespace''' ''objName nsName'' ?''arg arg'' ...?

~ Introspection Support

The core Tcl '''info''' command shall be extended in the following ways.

~~ An [info object] Subcommand

An '''object''' subcommand that shall provide information about a particular
object. Its first argument shall be the name of an object to get information
about, its second argument shall be a subsubcommand indicating the type of
information to retrieve and all subsequent arguments shall be arguments, as
appropriate. The following types of information shall be available:

 class: Returns the class of an object, or if ''className'' is specified,
   whether the object is (directly or indirectly through inheritance or mixin)
   an instance of the named class.

 > '''info object class''' ''object'' ?''className''?

 definition: Returns the formal argument list and body used to define a
   method.

 > '''info object definition''' ''object method''

 filters: Returns the list of filters defined for an object.

 > '''info object filters''' ''object''

 forward: Returns the list of words that form the command prefix that a
   method is forwarded to.

 > '''info object forward''' ''object method''

 isa: Returns boolean information about how an object relates to the class
   hierarchy. Supports a range of subcommands to allow the specification of
   what sort of test is to be performed:

 > class: Returns whether the named object is a class.

 > > '''info object isa class''' ''object''

 > metaclass: Returns whether the named object is a class that can create
   other classes (i.e. is '''oo::class''' or one of its subclasses).

 > > '''info object isa metaclass''' ''object''

 > mixin: Returns whether the named object has ''mixinClassName'' as one of
     its mixins.

 > > '''info object isa mixin''' ''object mixinClassName''

 > object: Returns whether ''object'' really names an object.

 > > '''info object isa object''' ''object''

 > typeof: Returns whether the object is of type ''class'' (i.e. an instance
     of that class or an instance of a subclass of that class).

 > > '''info object isa typeof''' ''object class''

 methods: Returns the list of methods defined for an object. Supports the
     options '''-all''' to also look at the class hierarchy for the object,
     and '''-private''' to get the list of methods supported by '''my''' for
     the object.

 > '''info object methods''' ''object options''

 mixins: Returns the list of mixins for an object.

 > '''info object mixins''' ''object''

 vars: Returns the list of all variables defined within the object, or
   optionally just those that match ''pattern'' according to the rules of
   '''string match'''.

 > '''info object vars''' ''object'' ?''pattern''?

~~ An [info class] Subcommand

A '''class''' subcommand that shall provide information about a particular
class. Its first argument shall be the name of a class to get information
about, its second argument shall be a subsubcommand indicating the type of
information to retrieve and all subsequent arguments shall be arguments, as
appropriate. The following types of information shall be available:

 constructor: Returns the formal argument list and body used to define the
   constructor, or an empty list if no constructor is present.

 > '''info class constructor''' ''class''

 definition: Returns the formal argument list and body used to define a
   method.

 > '''info class definition''' ''class method''

 destructor: Returns the body of the destructor, or an empty string if no
   destructor is present.

 > '''info class destructor''' ''class''

 filters: Returns the list of filters defined for a class.

 > '''info class filters''' ''class''

 forward: Returns the list of words that form the command prefix that a
   method is forwarded to.

 > '''info class forward''' ''class method''

 instances: Returns a list of all direct instances of the class (but not
   instances of any subclasses of the class), or optionally just those that
   match ''pattern'' according to the rules of '''string match'''.

 > '''info class instances''' ''class'' ?''pattern''?

 methods: Returns the list of methods defined by a class. Supports the options
     '''-all''' to also look at the class hierarchy, and '''-private''' to get
     the list of methods supported by '''my''' for the object's instances.

 > '''info class methods''' ''class options''

 subclasses: Returns a list of all subclasses of the class, or optionally just
   those that match ''pattern'' according to the rules of '''string match'''.

 > '''info class subclasses''' ''class'' ?''pattern''?

 superclasses: Returns a list of all superclasses of the named class in the
   class hierarchy. The list will be ordered in inheritance-precedence order.

 > '''info class superclasses''' ''class''

~~ Extending the Introspection Capabilities

Other forms of introspection subcommands may be added to '''info object''' and
'''info class''' by creating exported commands in the namespaces
'''oo::InfoObject''' and '''oo::InfoClass''' respectively.

~~ Issues with Objects and Namespaces

Every object has a distinct namespace associated with it, the name of which is
outside the scope of this specification. It is the name of this namespace that
is returned by '''self namespace'''.

The namespace does have a path set, as if by calling '''namespace path''';
this is how the '''next''' and '''self''' commands are provided, though since
they are never usable outside the scope of the body of a method, the namespace
which they originate from is out of the scope of this specification.

The '''my''' command is the only command in the object's namespace by default
(i.e., this command is truly per-object). It is not exported from the object's
namespace, nor are any other commands exported from or imported into the
namespace.

Methods are not commands, and so completely ignore the '''namespace export'''
command, nor does '''namespace unknown''' get involved at any point during the
location of a method. (They may run during the processing of a method body; it
is a context very similar to a normal procedure body.) Similarly, a method may
not be '''namespace import'''ed from another namespace.

Each method (including both the constructor and destructor) executed by an
object executes in that object's namespace. Changes made by a method to the
namespace (including both command declaration and uses of '''namespace
import''') will be seen by all other methods invoked on the same object. Note
that methods declared by classes still execute in the instance objects'
namespaces.

~ C API

''Note: This API is probably incomplete. Future TIPs may extend or completely
revise it.''

~~ Datatypes

The following public datatypes shall be declared in tcl.h:

 Tcl_Object: An opaque handle to an object.

 Tcl_Class: An opaque handle to a class.

 Tcl_Method: An opaque handle to a method.

 Tcl_ObjectContext: An opaque handle to an object method call context.

 Tcl_MethodType: A structure describing the type of a method implementation.
   It shall have the following fields:

 > version: The version number of the structure, which should always be
   referred to as TCL_OO_METHOD_VERSION_CURRENT in source code (currently
   ignored, but allows transparent versioning in the future).

 > name: The name of the method type, for debugging.

 > callProc: A pointer to a function that defines how to call method
   implementations of this type. Must not be NULL.

 > deleteProc: A pointer to a function that defines how to delete the
   ''clientData'' associated with a particular method implementation instance.
   If NULL, no deletion of the ''clientData'' is required.

 > cloneProc: A pointer to a function that defines how to copy the
   ''clientData'' associated with a particular method implementation instance
   during the copying of an object or class with '''oo::copy'''. If NULL, the
   method will be cloned by just copying the ''clientData''.

 Tcl_ObjectMetadataType: A structure describing the type of some arbitrary
   non-NULL metadata attached to an object or class. It shall have the
   following fields:

 > version: The version number of the structure, which should always be
   referred to as TCL_OO_METADATA_VERSION_CURRENT in source code (currently
   ignored, but allows for transparent versioning in the future).

 > name: The name of the metadata type, for debugging.

 > deleteProc: A pointer to a function that defines how to delete some
   metadata associated with this type. Must not be NULL.

 > cloneProc: A pointer to a function that defines how to copy some metadata
   associated with this type during the copying of an object or class with
   '''oo::copy'''. If NULL, the metadata will not be copied. (''Open issue:''
   There is a use case for making objects unclonable; consider the
   case where the metadata consists of one or more OS resource handles.
   Simply shallow-copying resource handles is a bad idea, but
   deep-copying them may well be infeasible. Not all objects can
   handle copy-on-write semantics gracefully.)

 Tcl_MethodCallProc: The type of the ''callProc'' field of the Tcl_MethodType
   structure. It is a pointer to a function that is used to implement how a
   method implementation is called. It takes five arguments and returns a
   normal Tcl result code. The arguments are:

 > clientData: Some method implementation instance specific data. Note that
   this is specific to the instance of the method implementation, and not
   (necessarily) the instance of the object.

 > interp: The Tcl interpreter reference.

 > objectContext: The object method call context, through which useful
   information (such as what object this method was invoked upon) can be
   obtained.

 > objc: The number of arguments.

 > objv: The actual list of arguments. Since the number of arguments required
   to indicate the method may vary, the method implementation should look up
   how many to skip over using the object method call context.

 Tcl_MethodDeleteProc: The type of the ''deleteProc'' field of the
   Tcl_MethodType structure. It is a pointer to a function that is used to
   delete ''clientData'' values associated with a method instance. It takes a
   single argument (the ''clientData'' to delete) and has no return value.

 Tcl_MethodCloneProc: The type of the ''cloneProc'' field of the
   Tcl_MethodType structure. It is a pointer to a function that is used to
   make copies of ''clientData'' values associated with a method instance
   suitable for use in another method instance. It takes two arguments (the
   ''clientData'' to clone, and a pointer to a variable into which to write
   the cloned ''clientData'') and returns either TCL_OK or TCL_ERROR, with the
   method only being cloned if the result is TCL_OK (the method is silently
   not cloned otherwise).

 Tcl_ObjectMapMethodNameProc: The type of a callback function used to adjust
   the mapping of objects and method names to implementations, which is
   required to support building [[incr Tcl]] on top of the core OO system. It
   takes four arguments, being the interpreter, the object that the method is
   being invoked upon, a point to a variable to contain the class in the
   hierarchy to start the search for components of the method chain from, and
   an unshared object holding the method name as supplied and which can be
   modified if the method to look for is not the literal name passed in.

 > This is necessary because [[incr Tcl]] allows the invoking of superclass
   implementations of a method using a syntax like
   "''superclassName''::''methodName''" where ''superclassName'' may name any
   superclass of the current class, and ''methodName'' may be any method
   name.

 > Note that the exact definition of this type is subject to change at the
   moment in order to ensure that it can be connected to the method dispatch
   engine efficiently. The type will be finalized before the release of Tcl
   8.6.

 Tcl_ObjectMetadataDeleteProc: The type of the ''deleteProc'' field of the
   Tcl_ObjectMetadataType structure. It is a pointer to a function that is
   used to delete ''metadata'' values attached to an object or a class. It
   takes a single argument (the ''metadata'' to delete) and has no return
   value.

 Tcl_ObjectMetadataCloneProc: The type of the ''cloneProc'' field of the
   Tcl_ObjectMetadataType structure. It is a pointer to a function that is
   used to create a copy of ''metadata'' values attached to an object or a
   class. It takes three argument, (the interpreter, the ''metadata'' to copy,
   and a pointer to a variable into which to write the copy, or NULL if the
   copy is not to be performed) and returns a standard Tcl result code.

~~ Functions

The following functional operations are defined:

 Tcl_NewMethod: This function creates a new method on a class (and hence
   on all instances of that class). It has the following signature:

 > Tcl_Method '''Tcl_NewMethod'''(Tcl_Interp *''interp'', Tcl_Class
   ''cls'', Tcl_Obj *''nameObj'', int ''isPublic'', const Tcl_MethodType
   *''typePtr'', ClientData ''clientData'')

 > If the method is created with a NULL ''nameObj'', it must be installed
   manually into the class as a constructor or destructor (in the latter case,
   it is important that the method be able to execute without additional
   arguments). Note that a NULL ''typePtr'' is reserved for internal use.

 Tcl_ClassSetConstructor: This function installs a method into a class as a
   constructor for instances of that class. The method must have been created
   with '''Tcl_NewMethod''' with a NULL ''nameObj'' argument. It has the
   following signature:

 > void '''Tcl_ClassSetConstructor'''(Tcl_Class ''cls'', Tcl_Method
   ''method'')

 Tcl_ClassSetDestructor: This function installs a method into a class as a
   destructor for instances of that class. The method must have been created
   with '''Tcl_NewMethod''' with a NULL ''nameObj'' argument. It has the
   following signature:

 > void '''Tcl_ClassSetConstructor'''(Tcl_Class ''cls'', Tcl_Method
   ''method'')

 Tcl_NewInstanceMethod: This function creates a new method on an object. It
   has the following signature:

 > Tcl_Method '''Tcl_NewInstanceMethod'''(Tcl_Interp *''interp'', Tcl_Object
   ''object'', Tcl_Obj *''nameObj'', int ''isPublic'', const Tcl_MethodType
   *''typePtr'', ClientData ''clientData'')

 > Note that a NULL ''typePtr'' is reserved for internal use, and ''nameObj''
   must not be NULL.

 Tcl_NewObjectInstance: This function creates a new instance of a class,
   calling any defined constructors. It has the following signature, returning
   NULL (and setting a message in the interpreter) if the object creation
   failed:

 > Tcl_Object '''Tcl_NewObjectInstance'''(Tcl_Interp *''interp'', Tcl_Class
   ''cls'', const char *''name'', const char *''nsName'', int ''objc'',
   Tcl_Obj *const *''objv'', int ''skip'')

 > Both ''name'' and ''nsName'' may be NULL, in which case the constructor
   code picks a default that doesn't clash with any previously existing
   commands or namespaces.

 Tcl_CopyObjectInstance: This function creates a copy of an object (including
   classes) without copying the backing namespace or executing any
   constructors. It has the following signature, returning NULL (and setting a
   message in the interpreter) if the object copying failed:

 > Tcl_Object '''Tcl_CopyObjectInstance'''(Tcl_Interp *''interp'', Tcl_Object
   ''sourceObject'', const char *''targetName'')

 > Note that the copying of an object can fail if the copy code for one of the
   metadata coping functions fails, so those functions can veto copying. Also
   note that if ''targetName'' is NULL, a name will be picked for the object.
   Currently no control over the naming of the target object's namespace is
   provided.

 Tcl_GetObjectFromObj: This function converts from a Tcl_Obj holding the name
   of an object to a Tcl_Object handle. It returns NULL (leaving an error
   message in the interpreter) if the conversion fails.

 > Tcl_Object '''Tcl_GetObjectFromObj'''(Tcl_Interp *''interp'', Tcl_Obj
   *''objPtr'')

 Tcl_ObjectContextInvokeNext: This function invokes the next method
   implementation in a method call chain, and is the internal implementation
   of the '''next''' command. It has the following signature:

 > int '''Tcl_ObjectContextInvokeNext'''(Tcl_Interp *''interp'',
   Tcl_ObjectContext ''context'', int ''objc'', Tcl_Obj *const *''objv'', int
   ''skip'')

 Tcl_ClassGetMetadata: This function retrieves the metadata attached to the
   class ''cls'' that is associated with the type ''typePtr''. It returns NULL
   if no data of that type is attached.

 > ClientData '''Tcl_ClassGetMetadata'''(Tcl_Class ''cls'', const
   Tcl_ObjectMetadataType *''typePtr'')

 Tcl_ClassSetMetadata: This function attaches metadata, ''metadata'', of a
   specific type, ''typePtr'', to the class, ''clazz'', or removes the
   metadata of that type if ''metadata'' is NULL. It is a no-op to remove
   metadata of a type that is not attached in the first place.

 > void '''Tcl_ClassSetMetadata'''(Tcl_Class ''clazz'', const
   Tcl_ObjectMetadataType *''typePtr'', ClientData ''metadata'')

 Tcl_ObjectGetMetadata: This function retrieves the metadata attached to the
   object ''object'' that is associated with the type ''typePtr''. It returns
   NULL if no data of that type is attached.

 > ClientData '''Tcl_ObjectGetMetadata'''(Tcl_Object ''object'', const
   Tcl_ObjectMetadataType *''typePtr'')

 Tcl_ObjectSetMetadata: This function attaches metadata, ''metadata'', of a
   specific type, ''typePtr'', to the object, ''object'', or removes the
   metadata of that type if ''metadata'' is NULL. It is a no-op to remove
   metadata of a type that is not attached in the first place.

 > void '''Tcl_ObjectSetMetadata'''(Tcl_Object ''object'', const
   Tcl_ObjectMetadataType *''typePtr'', ClientData ''metadata'')

 Tcl_ObjectGetMethodNameMapper: This function retrieves the current method
   name mapping function for an object, or NULL if none was set. It has the
   following signature:

 > Tcl_ObjectMapMethodNameProc '''Tcl_ObjectGetMethodNameMapper'''(Tcl_Object
   ''object'')

 Tcl_ObjectSetMethodNameMapper: This functionsets the method name mapping
   function for an object, or removes it if the function is set to NULL. It
   has the following signature:

 > void '''Tcl_ObjectSetMethodNameMapper'''(Tcl_Object ''object'',
   Tcl_ObjectMapMethodNameProc ''methodNameMapper'')

The following pure inspective (i.e., non-state changing) operations are
defined:

 Tcl_GetClassAsObject: This gets the object that represents a class.

 > Tcl_Object '''Tcl_GetClassAsObject'''(Tcl_Class ''clazz'')

 Tcl_GetObjectAsClass: This gets the class that an object represents (or NULL
   if the object does not represent a class).

 > Tcl_Class '''Tcl_GetObjectAsClass'''(Tcl_Object ''object'')

 Tcl_GetObjectCommand: This gets the command for an object. It is the name of
   this command that represents the object at the script level, and as such,
   it may be renamed.

 > Tcl_Command '''Tcl_GetObjectCommand'''(Tcl_Object ''object'')

 Tcl_GetObjectNamespace: This gets the object's private namespace.

 > Tcl_Namespace *'''Tcl_GetObjectNamespace'''(Tcl_Object ''object'')

 Tcl_MethodDeclarerClass: This gets the class that declared a method, or NULL
   if the method is a per-object method.

 > Tcl_Class '''Tcl_MethodDeclarerClass'''(Tcl_Method ''method'')

 Tcl_MethodDeclarerObject: This gets the object that declared a method, or
   NULL if the method is a class method.

 > Tcl_Object '''Tcl_MethodDeclarerObject'''(Tcl_Method ''method'')

 Tcl_MethodIsPublic: This returns whether a method is a public method. This
   status might be overridden in subclasses or objects.

 > int '''Tcl_MethodIsPublic'''(Tcl_Method ''method'')

 Tcl_MethodIsType: This returns whether a method is a specific type of
   method, and if so, also returns the ''clientData'' for the type. No way of
   inspecting method types for which you do not have a pointer to the type
   structure is provided.

 > int '''Tcl_MethodIsType'''(Tcl_Method ''method'', const Tcl_MethodType
   *''typePtr'', ClientData *''clientDataPtr'')

 Tcl_MethodName: This returns the name of a method.

 > Tcl_Obj *'''Tcl_MethodName'''(Tcl_Method ''method'')

 Tcl_ObjectDeleted: This returns whether an object has been deleted (assuming
   deletion has not yet completed, i.e., that the destructor is currently
   being processed).

 > int '''Tcl_ObjectDeleted'''(Tcl_Object ''object'')

 Tcl_ObjectContextIsFiltering: This returns whether the method call context is
   working with a filter or not.

 > int '''Tcl_ObjectContextIsFiltering'''(Tcl_ObjectContext ''context'')

 Tcl_ObjectContextMethod: This returns the method call context's current
   method instance.

 > Tcl_Method '''Tcl_ObjectContextMethod'''(Tcl_ObjectContext ''context'')

 Tcl_ObjectContextObject: This returns the method call context's object (i.e.,
   the object which was invoked).

 > Tcl_Object '''Tcl_ObjectContextObject'''(Tcl_ObjectContext ''context'')

 Tcl_ObjectContextSkippedArgs: This returns the number of arguments to be
   skipped (this varies because the method instance may be invoked through
   either [[obj method ...]] or through [[next ...]]).

 > int '''Tcl_ObjectContextSkippedArgs'''(Tcl_ObjectContext ''context'')

~ Not Addressed in this Document

This TIP does not address the reqirements for management of variables on a
class level or for "class methods" (in the Java sense). These will need to be
the subject of future TIPs.

~ Copyright

This document has been placed in the public domain.

----

The following sections are non-normative.

~ Appendix: Class Hierarchy for Support of Other OO Systems

When using the OO system as a basis for some other object system, it is useful
for all classes and objects to derive from some other object root for
compatability with existing practice. To see how to do this, consider this
class hierarchy (targetted at XOTcl) outlined below. The XOTcl ''Object''
class would derive from the core '''oo::object''' class, and the XOTcl
''Class'' class would derive from the core '''oo::class''' and the XOTcl
''Object'' classes. This would give the following diagram (core classes are in
lower case with their namespace omitted, XOTcl classes are in upper case, with
namespace omitted).

|                     +--------+
|            ,------->| object |
|            |        +--------+
|            |            ,^.
|    creates |       ______|______
|            |      |             |
|            |  +-------+    +--------+
|            `--| class |    | Object |<-.
|               +-------+    +--------+  |
|                  ,^.           ,^.     |
|                   |______ ______|      | creates
|                          |             |
|                      +-------+         |
|                      | Class |---------'
|                      +-------+

Note that '''class''' instances create '''object'''s (or subclasses thereof),
but ''Class'' instances create ''Object''s (or subclasses thereof).

~ Appendix: XOTcl Features Omitted from the Core OO System

~~ Object Methods

 Object::autoname: This is trivially implemented in a small procedure, and
   core objects can pick names for themselves and are renameable.

 Object::check: Preconditions and postconditions are not supported (they add a
   lot of complexity) and neither are invariants. Hence, there is no need to
   control whether they are executed.

 Object::cleanup: This is not an especially well-defined method (what if the
   object happens to hold handles to complex resources such as network
   sockets; it is not generally possible for the state of the remote server to
   be reset) and can be added in any compatability layer.

 Object::configure: This feature has been deliberately omitted from the core
   object system. This would be value added by any XOTcl extension.

 Object::extractConfigureArg: This feature is part of '''configure'''.

 Object::getExitHandler: This feature is not necessary for this version. If it
   existed, it would not need to be a part of the base object.

 Object::info: The introspection features are moved into the core '''info'''
   command.

 Object::invar: Invariants may be implemented using filters.

 Object::move: This feature is equivalent to the use of the standard
   '''rename''' operation.

 Object::noinit: This feature has been deliberately omitted from the core
   object system because its use is dependent on the use of other
   deliberately-omitted features (i.e., '''configure'''). This would be value
   added by any XOTcl extension.

 Object::parameter and Object::parametercmd: The core object system provides
   tools for doing parameters, but does not provide an implementation on the
   grounds that it is pretty easy to add.

 Object::requireNamespace: Objects always have a namespace.

 Object::setExitHandler: See the comments for '''getExitHandler''' above.

~~ Class Methods

 Class::__unknown: Auto-loading of unknown classes is handled by the standard
   core '''unknown''' mechanism.

 Class::abstract: Abstractness is relatively easy to implement on top of the
   proposed infrastructure and is not critical to getting an implementation.

 Class::allinstances: This feature is trivially implemented in a small
   procedure.

 Class::alloc: The core objects have no default behaviour, so the difference
   with the basic core class behaviour is moot.

 Class::create: Core object creation is a much more sealed process, but the
   lack of '''configure'''-like behaviour means that the complexity of this
   method is not necessary. Instead, constructors are called automatically.

 Class::parameterclass: Core object system parameters are not implemented by
   classes.

 Class::volatile: This feature is omitted as it is believed that it is
   possible to implement automated lifecycle management as a mixin.

~~ Other Commands

 getExitHandler, setExitHandler: Exit handlers are out of scope for the core
   object system.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>

|


|



|



|
|
|
|
|








|
|
|







|
|







|

|




|
|






|



|




|

|








|


|


|





|
|

|






|


|


|




|





|


|







|

|

|

|
|
|
|


|

|






|

|


|



|
|
|



|



|






|







|


|
|





|





|
|
















|



|
|












|




|

|


|
|
|
|
|
|





|

|






|












|


|
|



|

|



|
|
|



|
|
|





|

|



|
|
|
|
<
|
>
|


|
|
|
<
|
>

|


|
|


|
|
|
|

|


|

|
|
|
|




|




|
|


|
|



|
|

|

|
|

|



|








|






|
|
|




|








|








|
|
|

|
|
<
>






|







|
|

|
|
<
>




|
|

|



|

|
|
|





|
|



|

|



|





|










|

|
|


|
|

|
|
|
|
|
<
<
|
>
>
|




|


|

|



|
|
|
|




|




|

|

|


|

|

|


|

|

|
|


|

|

|
|

|
|
|

|


|
|

|

|


|

|

|
|
|
|

|





|






|




|
|


|




|




|


|




|

|


|





|


|

|
|

|

|

|

|

|

|
|

|
|
|

|
|

|

|
|

|
|








|

|
|
|

|




|

|



|
|
|

|


|

|

|

|


|


|

|
|
|


|
|

|
|
|
|


|

|
|
|

|


|

|
|
|
|

|

|

|



|

|


|

|
|




|




|

|



|

|



|
|

|




|

|


|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|

|
|


|

|


|


|




|

|


|

|

|

|

|
|


|
|


|
|
|
|

|


|

|
|
|

|
|

|

|



|

|

|





|








|




|


|



|



|

|







|
|


|



|

|


|
|
|


|

|
|
|


|

|
|
|


|
|
|

|


|
|
|

|
|
|
|
|
<
>
|
|
|
<
|
>
|
|
|
|
|
|
<
>
|
|
|
<
<
|
>
>
|
|
|
|
<
>
|
|
|
<
<
|
>
>
|

|
|
|

|
|

|

|


|
|
|


|


|
|
|


|

|



|
|
|
|

|

|

|

|

|





|
|


|




|



|




|







|


|

|

|


|

|

|

|
|

|


|
|


|



|


|
|

|

|

|








|




|




|



|




|

|
|
|

|


|
|

|


|

|




|

|

|
|
|

|



|

|
|



|
|



|
|
|
|
|

|

|
|



|

|
|

|



|

|

|

|

|



|
|







|
|


|
|
|

|




|
|








|




|

|






|




|








|
|
|
|

|
|
|
|
|
|
|
|

|

|






|

|
|







|
|
|
|


|
|
|
|

|

|



|
|

|
|
|

|
|

|

|

|


|
|

|

|


|
|

|


|
|
|

|


|

|


|
|
|

|



|
|
|
|

|
|

|

|



|
|
|

|
|

|

|

|
|
|

|
|


|
|

|
|
|


|
|

|
|


|
|

|
|
|


|
|

|



|
|

|



|
|

|


|

|

|
|

|

|



|

|

|

|


|

|


|

|


|

|
|



|
|

|

|

|

|

|

|


|

|


|

|
|

|

|
|
|

|

|


|


|







|




|
|
|
|

|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|

|

|




|
|


|


|




|




|





|



|








|

|

|
|











|








|



>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334

335
336
337
338
339
340
341
342

343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443

444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463

464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527


528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005

1006
1007
1008
1009

1010
1011
1012
1013
1014
1015
1016
1017

1018
1019
1020
1021


1022
1023
1024
1025
1026
1027
1028

1029
1030
1031
1032


1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691

# TIP 257: Object Orientation for Tcl

	Author:         Donal K. Fellows <[email protected]>
	Author:         Will Duquette <[email protected]>
	Author:         Steve Landers <[email protected]>
	Author:         Jeff Hobbs <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	Author:         Miguel Sofer <[email protected]>
	Author:         Richard Suchenwirth <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        26-Sep-2005
	Post-History:   
	Obsoletes:      50
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes adding OO support to the Tcl core, semantically inspired by
XOTcl. The commands it defines will be in the **::oo** namespace, which is
not used by any current mainstream OO system, and it will be designed
specifically to allow other object systems to be built on top.

# Rationale and Basic Requirements

Tcl has a long history of being comparatively agnostic about object-oriented
programming, not favouring one OO system over another while promoting a wealth
of OO extensions such as [incr Tcl]<http://incrtcl.sourceforge.net/itcl/> ,
OTcl<http://bmrc.berkeley.edu/research/cmt/cmtdoc/otcl/> ,
XOTcl<http://media.wu-wien.ac.at/> ,
stooop<http://jfontain.free.fr/stooop.html> ,
Snit<http://www.wjduquette.com/snit/> , etc. because in general, one size fits
nobody.

However, many application domains require OO systems and having a common such
base system will help prevent application and library authors from reinventing
the wheel each time through because they cannot rely on an OO framework being
present with each and every Tcl installation. For example, the http package
supplied with Tcl has its own internal object model, and a similar mechanism
is reinvented multiple times within tcllib. Other parts of tcllib do their own
thing \(to say nothing of the fact that both stooop and Snit are in tcllib
themselves\). This does not promote efficient reuse of each others code, and
ensures that each of these packages has a _poor_ object system. The request
for an OO system is also one of the biggest feature requests for Tcl, and
would make it far easier to implement megawidgets. It also leaves Tcl open to
the ill-informed criticism that it doesn't support OO, despite being spoilt
for choice in reality through the extensions listed above.

Given all this, the time has come for the core to provide OO support. The aim
of the core OO system shall be that it is simple to get started with, flexible
so that it can take you a long way, fast \(we all know that we're going to get
compared on this front!\), and suitable for use as a foundation of many other
things, including the re-implementation of various existing OO extensions,
including those that are currently compiled and also those that are pure Tcl
extensions.

Another requirement is that programmers should not have to alter all of their
existing code in order to get started with the new system; rather, they should
be able to adopt it progressively, over time, because it supports better ways
of working \(e.g., faster and more flexible libraries\).

# The Foundational OO System

This TIP proposes that the foundation of the OO system should ensure that it
is simple, fast and flexible. Semantically, the OO system should be using the
semantic model pioneered by OTcl and XOTcl, as leveraging their experience on
the complex parts \(e.g., the model of multiple inheritance, how to invoke
superclass implementations of a method\) allows us to go straight to a solution
that is rich enough for a very large space of applications.

However, some changes relative to XOTcl are necessary. Certain aspects of
XOTcl syntax are peculiar from a conventional OO point-of-view, and it is
deeply unfortunate that a very large number of methods are predefined in the
XOTcl base class. XOTcl's approach to object creation options is also highly
idiosyncratic \(though critical to the way XOTcl itself works\) and doesn't
really support the typical Tcl idioms. The changes must be made in such a way
that something that works like classic XOTcl for virtually all uses can be
built on the new framework, but the core object framework must also enable
building [incr Tcl]-like or Snit-like object systems on top.

Note that by keeping things in the base classes comparatively simple, it is
much easier to build multiple extended OO frameworks on top.

## Key Features

### Functional Requirements

 * Class-based object system. This is what most programmers expect from OO,
   and it is very useful for many tasks.

 * Allows per-object customization and dynamic redefinition of classes.

 * Supports advanced OO features, such as:

	 > meta-classes: These are subclasses of **class**, which permit more
   advanced customization of class behaviour.

	 > filters: These are constraints \(implemented in Tcl code, naturally\) on
   whether a method may be called.

	 > mixins: These allow functionality to be brought into an object from other
   objects if necessary, enabling better separation of concerns.

 * A system for implementing methods in custom ways, so that package authors
   that want significantly different ways of doing a method implementation may
   do so fairly simply. Note that this will require additional C code to
   perform; this API will not be exposed directly to the script level \(since
   it makes little sense there\).

### Non-Functional Requirements

Note that these requirements would need to be imposed on any implementation of
an object system in the Tcl core code anyway.

 * The speed of the object system is something on which it is easy to predict
   that Tcl will end up being compared to other languages. Hence, the core OO
   system _must_ permit efficient implementation.

 * The core OO system must be clear code that it is easy for the Tcl
   maintainers to keep in good order. The Engineering Manual [[247]](247.md) will be
   followed.

## Key Alterations Relative to XOTcl

The core OO system can be considered to be a derivative of XOTcl, much as C
can be considered to be a derivative of Algol. However, like the C/Algol
relationship, there are many changes between the core OO system and XOTcl; the
_implementations_ are not common.

 * Object and class names in the core extension to be all lower-case, in line
   with best common practice in general Tcl code.

 * Methods have to be capable of being non-exported, by which we mean that
   they are not \(simply\) callable from contexts outside the object.

 * The majority of the API for updating an object or class's definition is to
   be moved to a separate utility command, **oo::define**.

 * More "conventional" naming of operations is to be used.

 * Many of the more advanced features of XOTcl are not present, especially
   when it is possible to implement them on top of other features. This
   particularly applies to:

	 > \* Filter- and mixin-guards

	 > \* Invariants

	 > \* Pre- and post-conditions

Note that this TIP does _not_ propose to actually include any XOTcl \(or Itcl
or Snit or ...\) compatibility packages in the core; it is about forming a
foundation on which they can be built \(which happens to also be a
comparatively lightweight OO system in itself\). Such compatibility packages
can either remain separate code, or be the subject of future TIPs.

# Detailed Rationale for Not Using XOTcl

## Features of XOTcl that are Retained

Many key semantic features of XOTcl are adopted with little or no change. In
particular, the following critical features of the core object system shall be
semantically the same as in XOTcl as they represent the best-of-breed in
advanced object systems at the moment.

### Multiple Inheritance

We shall support multiple inheritance \(MI\) because this is very difficult to
add after the fact.

The main problem with MI in languages like C\+\+ was always confusion caused by
the fact that methods were resolved using integer offsets into method tables.
By contrast, single inheritance is far too restrictive. By supporting mixins
and filters, it becomes possible to build not just conventional OO systems in
the C\+\+ or Java mould, but also to make Self-like prototype systems \(which
requires mixins and subclassing of the class of classes to work\) and
Aspect-like systems \(which require filters for efficient implementation\). As
these are less well-known terms than those of normal inheritance, we define
them here:

 mixin: An auxiliary _class_ whose behaviour is "mixed into" the current
   object or class, adding the mixin's methods to the target's methods. Often
   used to support cross-cutting functionality or object roles.

 filter: A nominated _method_ that is permitted to control whether all calls
   to any other method of a class or object occur. This control is achieved by
   the nominated filter method being chained on the front of the sequence of
   methods in the "implementation list" for the actual target method. Often
   used to support transparent orthogonal functionality, such as access
   control or result caching.

### The Method Dispatch Algorithm

The use of a complex class graph model as described above requires a
sophisticated algorithm to linearize any particular call of a method into a
sequence of method implementations that should be called. This is the method
dispatch algorithm. The algorithm works by scanning the graph of the object
and its associated classes in the order given below, collecting
implementations as they are found in a list, with an implementation coming in
the _last_ position in the list it can be; if it would be in twice because
of an "inheritance diamond", it comes in the later location.

 1. Filters defined on classes mixed into the object or its class \(or
    superclasses\), with filters from a particular class processed in the order
    that they are described by that class.

 2. Filters defined on the object, in the order that they are described in the
    object's filter list.

 3. Filters defined on the class of the object \(or its superclasses\), with
    filters from a particular class processed in the order that they are
    described by that class.

 4. Methods declared by mixins added to the object, with mixins being
    processed in the order that they are described in the object's mixin list
    \(the set of methods declared by the mixin are determined by recursively
    applying this algorithm\).

 5. Methods declared by mixins added to the object's class or superclasses,
    with mixins to a particular class being processed in the order that they
    are described in the class's mixin list.

 6. Methods declared by the object itself.

 7. Methods declared by the object's class itself.

 8. Methods declared by the object's class's superclasses, with superclasses
    being processed in the order that they are described in the class's
    superclass list.

Given the above ordering, for each method on an object there is an ordered
list of implementations. We dispatch the method by executing the first
implementation on the list, which can then hand off to subsequent methods in
the list in order using the **next** command \(described below\).

Another way to view the ordering is that there are several layers to the
ordering scheme. Firstly, there is the basic ordering which is: object, class,
superclasses to root \(with multiple inheritance being processed in the listed
order, and classes appearing in the linearized tree as late as possible\). Then
there is the second-order ordering, which adds mixins to the front of the
basic ordering, where the order of the mixins is processed in basic ordering.
Finally, there is the third-order ordering which adds filters to the front of
the second-order ordering, with filter name sources being processed in
second-order ordering and the method chain for a particular filter being
processed in second-order ordering order.

Note that a filter being invoked as a filter is different to a filter being
invoked as a normal method. If a filter method is invoked directly, then it
will actually be invoked twice, once as a filter and once as a conventional
method.

## Essential Changes Relative to XOTcl

Unfortunately, not all features of XOTcl are suitable for a core object
system. In particular, many more syntactic features need to be altered. This
section describes these, together with the rationale for each change; the
rationales are marked with the word "**Therefore**", in bold.

### Exported vs. Non-exported Methods

In XOTcl, every class and every object has an associated namespace. The
namespace associated with a class _::myclass_ is
_::xotcl::classes::myclass_; the namespace associated with object
_::myobject_ is simply _::myobject_. XOTcl "instprocs" are simply procs
defined in a class \(or superclass\) namespace; XOTcl per-object "procs" are
simply procs defined in an object's namespace. _Every such proc becomes an
object subcommand._

This is part of the reason why XOTcl objects have such cluttered interfaces.
Every method which is of use to the object appears in the object's interface -
and there's no way to prevent this.

**Therefore**, in the new oo system "**proc**s" and "**instproc**s" can
be exported or non-exported. Exported procs appear as object subcommands;
non-exported procs do not, but remain available as subcommands of the **my**
command. In this way, the object itself can still use them, but they need
appear in the object's interface only if desired.

Additionally, the standard introspection system will need to be extended to
allow determining of which methods are exported and which are not.

### The oo::define Command

In XOTcl, the commands to define per-class methods, filters, and so on are
subcommands of the class object; the commands to define per-object methods,
filters, and so on are subcommands of the individual object. This is a
problem, as it confuses the implementation-time interface with the run-time
interface. The design is logical, given XOTcl's extreme dynamism; any
implementation-time activity, such as defining a method or adding a filter can
indeed be done at run-time. But again, this makes it difficult to define clean
run-time interfaces for reusable library code.

The solution described in the previous section, of making some methods private
by declaring them non-exported, does not give us a full solution; having the
**instproc** subcommand available only from instance code isn't all that
useful.

**Therefore**, we add two new commands, **oo::define** and
**oo::objdefine**, which are used to define methods, filters, and so on.
They can be called in two ways, with each command having essentially the same
fundamental syntax. The first calling model is as follows:

 > **oo::define** _class subcommand args..._

 > **oo::objdefine** _object subcommand args..._

For example, the following XOTcl code defines a class with two methods:

	xotcl::Class myclass
	myclass instproc dothis {args} { # body }
	myclass instproc dothat {args} { # body }

In the new oo core, the matching code would be this:

	oo::class create myclass
	oo::define myclass method dothis {args} { # body }
	oo::define myclass method dothat {args} { # body }

The two definition commands will also have a second calling model, in which
they get passed a single definition script whose commands are the subcommands
supported by the command as described above:

 > **oo::define** _class script_

 > **oo::objdefine** _object script_

Thus, the above code could also be written as follows:

	oo::class create myclass
	oo::define myclass {
	    method dothis {args} { # body }
	    method dothat {args} { # body }

	}

Finally, the constructor for the **oo::class** class is extended so that
such a script can be used during class creation:

	oo::class create myclass {
	    method dothis {args} { # body }
	    method dothat {args} { # body }

	}

This allows a class to be defined cleanly and concisely, while guaranteeing
that all class details can still be modified later on using **oo::define**.

To enable the easy definition of details of the class object at class
definition time, a special subcommand, "**self**", will be provided that is
equivalent to using **oo::objdefine** on the class.

Note that because of the requirement for a distinction between public and
private interfaces, **oo::define** and **oo::objdefine** will need two
subcommands XOTcl doesn't currently provide: **export** and **unexport**.
**export** takes as arguments a list of method names; all named methods are
exported and become visible in the object or class's interface. **unexport**
does the opposite. Note that by default, all methods that start with a
lower-case letter \(specifically, names matching the glob pattern "[a-z]\*"\)
will be exported by default and all other methods will be unexported.

### Standard Metaclasses

XOTcl defines two standard Metaclasses, _xotcl::Object_ and
_xotcl::Class_. _xotcl::Object_ is the root of the class hierarchy; all
XOTcl classes implicitly inherit from _xotcl::Object_. XOTcl classes are
themselves objects, and are instances of _xotcl::Class_. _xotcl::Class_
can itself be subclassed to produce different families of classes with
different standard behaviours.

The new core object system will use the same basic mechanism, based on the
metaclasses **oo::object** and **oo::class**. However, one of the problems
with XOTcl is that XOTcl objects have too much standard behavior; the new core
object system must provide a simpler foundation, with the XOTcl behavior
optionally available.

**Therefore**, we will extract the features of _xotcl::Object_ and
_xotcl::Class_ that are critical into our classes and leave all other
functionality up to any subclasses or metaclasses that are defined.

Thus **oo::object** will be the root of the class hierarchy. However,
instances of **oo::object** will have a minimal set of standard methods, so
that clean interfaces can be built on top of it, as can be done with Snit
types and instances.

Core object system classes will be instances of **oo::class** or its
subclasses. Likewise, **oo::class** will define only minimal behaviour.

### Inheritance

A class may wish to make use of the capabilities of **oo::class** internally
without exporting its methods \(e.g., for providing a singleton instance\).

**Therefore**, the inheritance mechanism should be extended such that the
newly defined class can declare whether a parent class's methods should be
exported or not, on a case-by-case basis. 

### Object Creation

XOTcl has a unique creation syntax. The object name can be followed by what
look like Tk or Snit options - but aren't. Instead, any token in the argument
list that begins with a hyphen is assumed to be the name of one of the
object's methods; it must be followed by the method's own arguments. For
example, a standard XOTcl class will have a "set" method, which has the same
syntax as the standard Tcl "set" command. Thus, the following code:

	    myclass myobj -set a 1 -set b 2

creates an instance of "myclass" called "myobj" whose instance variables "a"
and "b" and set to 1 and 2 respectively. This is an intriguing and innovative
interface, and it is unlike any other Tcl object system. Additionally, it
makes it difficult to implement standard Tk-like options.

**Therefore**, standard core object system classes will not use this
mechanism \(though it might be available on demand by inheriting from some
other standard metaclass\). Instead, standard core object system classes will
have no creation behavior other than that implemented by their designers in
their constructors.

Constructors may have any argument list the user pleases, including default
arguments, the "args" argument \(as in the **proc** command\), and XOTcl-style
non-positional arguments. It is up to the developer to handle the arguments
appropriately.

It is expected that one of the key responsibilities of any XOTcl compatability
package would be to define an object/class construction system that parses the
arguments in the expected way and uses them to invoke methods on the newly
created object.

### Constructor Syntax

In XOTcl, a class's constructor is implemented using its "init" instproc. This
is troubling; constructors are intended to do things just once, and are often
written to take advantage of that, whereas an "init" instproc can
theoretically be called at any time. For any given class, then, one of two
conditions will obtain: either "init" must be written so that it can be called
at any time, or the class will have an inherent logic bug.

**Therefore**, the class constructor will not be implemented as a standard
instproc. Instead, the **oo::define** command will have a new subcommand,
**constructor**, which will be used as follows:

	oo::define myclass constructor {} {
	    # body

	}

The constructor so defined will act almost exactly like an instproc; it may
call superclass constructors using the "super" command, etc. However, it may
never be called explicitly, but only via the class's "create" and "new"
methods.

### Destructor Syntax

In XOTcl, a class's destructor is defined by overriding the "destroy"
instproc. This is problematic for two reasons: first, a destructor doesn't
need an argument list. An instproc is too powerful for the task. Second,
successful destruction should not depend on the destructor's chaining to its
superclass destructors properly.

**Therefore**, the class destructor will be defined by a new subcommand of
**oo::define**, **destructor**, as follows:

	oo::define myclass destructor {
	    # Body

	}

The destructor has no argument list.

The destructor cannot be called explicitly. Instead, the destructors are
invoked in the proper order by the standard **destroy** method \(defined in
**oo::object**\), which need never be overridden.

If an error occurs in a destructor, it will _not_ prevent the object from
being deleted. There is no guarantee to run destructors when an interpreter or
Tcl-enabled process exits.

### Behavior and Syntax of next

In XOTcl, the **next** command is used to invoke the "next" method in the
dispatch chain. It optionally takes arguments to process \(if they are omitted,
it passes all arguments that were passed to the current method\) and it calls
the appropriate superclass implementation. But it does so without adjusting
the Tcl stack, which forces classes to take extreme care when implementing
code that needs to access variables or evaluate scripts in the scope of the
code that invoked the method in the first place.

**Therefore**, the **next** command will perform Tcl stack management so
that using **uplevel** and **upvar** in a method will be just like doing
so in a normal procedure, no matter how the class containing that method is
subclassed.

In addition, the adoption of [[157]](157.md) makes explicit handling of arguments
practical as code does not need to perform potentially troublesome operations
with **eval**, and so **next** will always require that all argument be
passed explicitly. This also makes it easier to decide to pass no arguments to
a superclass implementation.

## Desirable Changes

The changes described in this section are not absolutely essential to meeting
the goals described earlier. However, they are desirable in that they lead to
cleaner, more maintainable code.

### Class vs. Object Method Naming

XOTcl has many features which can be applied to a class for use by all class
instances, or to a single object. For example, a "filter" can be defined for a
single object, while an "instfilter" can be defined for a class and applied to
all instances of that class.

This is exactly backward. Most behavior will be defined for classes;
additional per-object behavior is the special case, and consequently should
have the less convenient name.

**Therefore**, all definition subcommands that begin with "inst" will be
defined, in the core OO system without their "inst" prefix; the per-object
subcommands will be manipulated via **oo::objdefine** or through the "self"
prefix command \(described above\), to indicate that it is operating on the
object itself and not the members of the class. Thus, a filter is defined on a
class for its instances using the "filter" subcommand; a filter is defined on
a particular object using the "self filter" subcommand \(actually a subcommand
of a subcommand\).

	 oo::define someCls {
	     method foo {} {...}
	     self {
	         method bar {args} {...}
	         filter bar


	     }
	 }

### Procs vs. Methods

The word "proc" conveys a standalone function; an object's subcommands are
more typically described as its "methods".

**Therefore**, the core OO system will use "method" in place of "proc" for
definitions.

### Public Names

In XOTcl, the main objects are _xotcl::Class_ and _xotcl::Object_.
However, the Tcl Style Guide dictates that public command names begin with a
lower-case letter.

**Therefore**, all public names in the _oo::_ namespace \(i.e. the standard
classes\) will begin with a lower case letter, e.g., the standard core object
system equivalents of _xotcl::Class_ and _xotcl::Object_ will be
**oo::class** and **oo::object**.

This does not constrain any code making use of the OO system from naming
objects however it wants.

# API Specification

This section documents the core object system API in detail, based on the
essential and desirable changes discussed in the previous sections.

## Helper Commands

The namespace\(s\) that define the following three commands are not defined in
this specification unless otherwise stated; all that is defined is that they
will be on the object's **namespace path** during the execution of any
method and should always be used without qualification.

### my

The **my** command allows methods of the current object to be called during
the execution of a method, just as if they were invoked using the object's
command. Unlike the object's command, the **my** command may also invoke
non-exported methods.

 > **my** _methodName_ ?_arg_ _arg_ ...?

Note that each object has its own **my** command; they are all distinct from
each other. This means that it is suitable for use for things like invoking
callbacks \(from general Tcl code\) that are non-public methods. In particular,
the use of **namespace code** for encapsulating the use of **my** for
invoking unexported callback methods by non-object code is supported.

Note that the **my** command does not represent the name of the object.

### next

The **next** command allows methods to invoke the implementation of the
method with the same name in their superclass \(as determined by the normal
inheritance rules; if a per-object method overrides a method defined by the
object's class, then the **next** command inside the object's method
implementation will invoke the class's implementation of the method\). The
arguments to the **next** command are the arguments to be passed to the
superclass method. The current stack level is temporarily bypassed for the
duration of the processing of the **next** command; this allows a method to
always execute identically with respect to the main calling context without
needing to use some form of introspection to determine where that context is
on the call frame stack \(with a side effect of isolating method
implementations from each other\).

 > **next** ?_arg_ _arg_ ...?

It is an error to invoke the **next** command when there is no superclass
definition of the current method.

### self

The **self** command allows executing methods to discover information about
the object which they are currently executing in; it's always an error if not
inside a method. Without arguments, the **self** command returns the current
fully-qualified name of the object \(to promote backward compatability\).
Otherwise, it is a command in the form of an ensemble \(though it is not
defined whether it is manipulable with **namespace ensemble**\).

The following subcommands of **self** are defined. None of these subcommands
take additional arguments.

 caller: Returns a three-item list describing the class, object and method
   that invoked the current method, respectively. The syntax is as follows:

 > **self caller**

 class: Returns the name of the class that defines the currently executing
   method. If the method was declared in the object instead of in the class,
   this returns the class of the object containing the method definition. The
   syntax is as follows:

 > **self class**

 filter: When invoked inside a filter, returns a three-item list describing
   the object or class for which the filter has been registered. The first
   element is the name of the class or object, the second element is either
   **class** \(for a filter defined on a class for its instances\) or
   **object** \(for a filter defined on a single object\), and the third
   element is the name of the method. The syntax is as follows:

 > **self filter**

 method: Returns the name of the currently executing method. The syntax is as
   follows:

 > **self method**

 namespace: Returns the namespace associated with the current object. The
   syntax is as follows:

 > **self namespace**

 next: Returns a two-element list describing the method that will be executed
   when the **next** command is invoked, or an empty list if there is no
   subsequent definition for the method. The first element of the list is the
   name of the object or class that contains the method, and the second
   element of the list is the name of the method. The syntax is as follows:

 > **self next**

 object: Returns the name of the current object, the same as if the **self**
   command is invoked with no arguments. The syntax is as follows:

 > **self object**

 target: When invoked from a filter, returns a two-item list consisting of the
   name of the class that holds the target method and the name of the target
   method. The syntax is as follows:

 > **self target**

For all these commands, when the name of a method is returned, it will be
"_<constructor>_" when the method is a constructor, and "_<destructor>_"
when the method is a destructor. It should be noted that these are not the
actual names of the constructor and destructor \(they are unnamed methods\);
they are just notational conventions supported by the **self** command.

## The oo::define Command

 > **oo::define** _class_ _subcommand_ ?_arg_ ...?

 > **oo::define** _class_ _script_

 > **oo::objdefine** _object_ _subcommand_ ?_arg_ ...?

 > **oo::objdefine** _object_ _script_

The **oo::define** command is used to add behavior to classes, and the
**oo::objdefine** command is used to add behavior to objects. The first form
of each command is conventional for ensemble-like commands, except that the
_class_ or _object_ argument precedes the _subcommand_ argument. In the
second form of each command, _script_ is a Tcl script whose commands are the
subcommands of **oo::define** or **oo::objdefine**; this is a notational
convenience, as the two forms are semantically equivalent in what their
capabilities are. \(Note that the context in which _script_ executes is
otherwise not defined.\)

### Class-related Subcommands

The subcommands of **oo::define** \(which may be unambiguously abbreviated
in both the subcommand form and the script form\) shall be:

 * **constructor** - this takes two arguments \(a **proc**-style argument
   list, and a body script\), and sets the constructor for the instances of the
   class to be executed as defined by the body script after binding the actual
   arguments to the call that creates an instance of the class to the formal
   arguments listed. The constructor is called after the object is created but
   before any instance variables are guaranteed to be set. If no constructor
   is specified, the constructor will accept exactly the same arguments as the
   constructor in the parent class, and will delegate all the arguments to
   that parent-class constructor. The syntax is as follows:

	 > **oo::define** _class_ **constructor** _argList_ _body_

	 > Note that constructors of class mixins are also called, but constructors of
   object mixins are never called \(as the object must exist before it can have
   an auxiliary class mixed into it\).

 * **destructor** - this defines the class destructor; a destructor is like
   a method but takes no arguments. Destructors are called on all classes that
   define them when the object is deleted, including classes that have been
   mixed in. The syntax is as follows:

	 > **oo::define** _class_ **destructor** _body_

	 > Note that destructors _should always_ use the **next** command within
   their implementation so that destructors of parent classes are also
   executed.

	 > Note also that destructors are called whenever the object is deleted by
   any mechanism \(except when the overall interpreter is deleted, when
   execution of Tcl scripts has ceased to be possible anyway\).

 * **export** - this specifies that the named methods are exported, i.e.,
   part of the public API of the class's instances. The syntax is as follows:

	 > **oo::define** _class_ **export** _name_ ?_name_ ...?

	 > An exported method is accessible to clients of the class's instances; an
   unexported method is accessible only to the instances' own code through the
   **my** command.

 * **filter** - this subcommand controls the list of filter methods for a
   class. Each filter method in the list is called when any method is invoked
   on the class's instances, and it is up to the filter to decide whether to
   invoke the filtered method call \(using the **next** command\) or return a
   suitable replacement value. The syntax is as follows:

	 > **oo::define** _class_ **filter** ?_filterName filterName_ ...?

 * **forward** - this subcommand defines a class method which is
   automatically forwarded \(i.e. delegated\) to some other command, according
   to a simple pattern. Each _arg_ is used literally. The syntax is as
   follows:

	 > **oo::define** _class_ **forward** _name_ _targetCmd_
   ?_arg_ ...?

 * **method** - this subcommand \(only valid for classes\) defines a class
   method \(i.e. a method supported by every instance of the class\). By
   default, methods are exported if they start with a lower-case letter \(i.e.,
   any character in \\u0061 to \\u007a inclusive\) and are not exported
   otherwise. The syntax is as follows:

	 > **oo::define** _class_ **method** _name_ _args_ _body_

 * **mixin** - This subcommand defines a mixin for a class which is a way of
   bringing in additional method implementations \(which may add to or wrap
   existing methods\) on an _ad hoc_ basis. The list of mixins is traversed
   when searching for methods before the inheritance hierarchy, and mixed-in
   methods may chain to any methods they override using the **next**
   command. The syntax is as follows:

	 > **oo::define** _class_ **mixin** ?_mixinClass mixinClass_ ...?

 * **self** - This subcommand, which has the same syntax patterns as
   **oo::objdefine**, allows the manipulation of the class as an object. See
   **oo::objdefine** below for a description of the list of subcommands of
   **self**. The syntaxes are as follows:

	 > **oo::define** _class_ **self** _subcommand_ ?_arg_ ...?

	 > **oo::define** _class_ **self** _script_

 * **superclass** - This specifies the superclass \(or classes\) of a class.
   Note that objects are always either classes or not classes, and cannot be
   changed from one to the other by any mechanism. The syntax is as follows:

	 > **oo::define** _class_ **superclass** _classList_

 * **unexport** - This specifies that the named methods are unexported,
   i.e., private. The syntax is as follows:

	 > **oo::define** _class_ **unexport** _name_ ?_name_ ...?

	 > An exported method is accessible to clients of the object; an unexported
   method is accessible only to the object's own code, through the **my**
   command.

The following utility subcommands are also supported:

 * **deletemethod** - This deletes one or more methods from a class; it
   doesn't modify any definitions of the method in superclasses, subclassses,
   instances or mixins. The method names must be specified exactly. Syntax is
   as follows:

	 > **oo::define** _class_ **deletemethod** _name_ ?_name_ ...?

 * **renamemethod** - This renames a method in a class from one thing to
   another; it doesn't modify any definitions of the method in superclasses,
   subclassses, instances or mixins. Syntax is as follows:

	 > **oo::define** _class_ **renamemethod** _fromName_ _toName_

### Per-Object Subcommands

The following subcommands are all per-object versions of the class subcommands
listed above. When they are applied to a class, they operate on the class
instance itself as an object, and not on the instances \(current and future\) of
that class \(which is why the distinction is required\).

 * **class** - This subcommand gets and sets the class of an object.
   Changing the class of an object can result in many methods getting added or
   removed. Objects may not be changed between being class-objects and and
   non-class objects. The syntax is as follows:

	 > **oo::objdefine** _object_ **class** _className_

	 > Note that when the class is changed of an object, no methods are called on
   that object, or on either the source or target classes, to indicate that
   the change has been carried out. This is up to the caller of the
   **class** subcommand.

 * **deletemethod** - This is a per-object version of the **deletemethod**
   subcommand of **oo::define**, to which it is syntactically identical.

 * **export** - This is a per-object version of the **export** subcommand
   of **oo::define**, to which it is syntactically identical.

 * **filter** - This is a per-object version of the **filter** subcommand
   of **oo::define**, to which it is syntactically identical.

 * **forward** - This is a per-object version of the **forward**
   subcommand of **oo::define**, to which it is syntactically identical.

 * **method** - This is a per-object version of the **method** subcommand
   of **oo::define**, to which it is syntactically identical.

 * **mixin** - This is a per-object version of the **mixin** subcommand of
   **oo::define**, to which it is syntactically identical.

 * **renamemethod** - This is a per-object version of the **renamemethod**
   subcommand of **oo::define**, to which it is syntactically identical.

 * **unexport** - This is a per-object version of the **unexport**
   subcommand of **oo::define**, to which it is syntactically identical.

## The oo::copy Command

The **oo::copy** command creates an exact copy of an object with the given
name. If _newName_ is the empty string or unspecified, a new name will be
generated automatically. The syntax is as follows:

 > **oo::copy** _object_ ?_newName_?

Note that this command does _not_ copy the backing namespace, and nor does
it execute any constructors. It is therefore up to the caller to copy such
internal state of the object in the manner suitable for the object and its
class tree; it is suggested that this be done by wrapping the **oo::copy**
command in another command that defines which method is called.

# Core Objects

The following classes are defined, and are the only pre-constructed objects in
the core system.

## oo::object

The root of the class hierarchy is **oo::object**. There are two ways to
create a new instance of an object.

 > **oo::object** **create** _name_

 > **set** _var_ **[** **oo::object** **new** **]**

The first constructs a new object called _name_ of class _oo::object_; the
object is represented as a command in the current scope. The second constructs
a new object of class **oo::object** with a name guaranteed to be different
from every existing command and returns the fully qualified of the command
created \(which it is naturally a good idea to save in a variable, perhaps
called _var_\).

The name of an object is also the name of a command in the form of an ensemble
where the subcommands of the ensemble are the _exported_ method names of the
object. The command is not manipulable with **namespace ensemble**, but may
be renamed.

The new object has one predefined exported method \(**destroy**\) and four
predefined non-exported methods \(**eval**, **unknown**, **variable** and
**varname**\). Other subcommands and other behaviour can be added using
**oo::define**.

The **oo::object** class \(an instance of **oo::class**\) serves as the base
class for all other core OO system classes.

### Constructor and Destructor

The constructor for the **oo::object** class takes no arguments and does
nothing. \(The actual construction of an object is special and happens before
any constructors are called.\)

The destructor does nothing. \(The actual destruction of an object is special
and happens after all destructors have completed.\)

### Methods

The instances of **oo::object** \(i.e. all objects and classes\) have the
following methods:

 eval: This non-exported method concatenates its arguments according to the
   rules of **concat**, and evaluates the resulting script in the namespace
   associated with the object. The result of the script evaluation is the
   result of the _object_ **eval** method. The syntax is as follows:

 > _object_ **eval** ?_arg_ _arg_ ...?

 destroy: This exported method deletes the object; it takes no additional
   arguments and returns the empty string as its result. The syntax is as
   follows:

 > _object_ **destroy**

 unknown: This non-exported method takes a method name and an arbitrary number
   of extra arguments and handles the absence of a method with the given name.
   The default implementation just generates a suitable error message that
   explains what commands are available given how the caller attempted to
   invoke the method, and ignores all the additional arguments. The syntax is
   as follows:

 > _object_ **unknown** _methodName_ ?_arg_ ...?

 > Note that this method is not normally invoked directly.

 variable: This non-exported method takes an arbitrary number of
   _unqualified_ variable names and binds the variable with that name in the
   object's namespace to the same name in the current scope, provided the
   current scope is the body of a procedure, procedure-like method, or lambda
   term \(as used with **apply**\); if executed in a context where the current
   scope does not admit local variables, this method will have no effect. The
   syntax is as follows:

 > _object_ **variable** ?_varName_ _varName_ ...?

 > However, it will be more commonly used as:

 > **my variable** ?_varName_ _varName_ ...?

 > Each _varName_ argument is the name of a variable in the namespace
   associated with the object, and must not contain any namespace separators.
   Each named variable will be bound to a local variable in the current scope
   with the same name.

 varname: This non-exported method takes one argument, the name of a variable
   to be resolved in the context of the object's namespace, and returns the
   fully qualified name of the variable such that it can be used with the
   **vwait** command or extensions such as Tk \(e.g., for the **label**
   widget's **-textvariable** option\). This method does not assign any value
   to the variable. The syntax is as follows:

 > _object_ **varname** _varName_

 > However, it will be more commonly used as:

 > **my varname** _varName_

### Unknown Method Handling

When an attempt is made to invoke an unknown method on any object, the core
then attempts to pass _all_ the arguments \(including the method name\) to
the **unknown** method of the object. The default implementation of the
**unknown** method is specified by the **oo::object** class, and just
generates a suitable "unknown subcommand" error message.

## oo::class

This class is the class of all classes \(i.e. its instances are objects that
manufacture objects according to a standard pattern\). Note that
**oo::object** is an instance of **oo::class**, as is **oo::class**
itself.

 > **oo::class** **create** _name_ ?_definition_?

This creates a new class called _name_; the class is an object in its own
right \(of class **oo::class**\), and hence is represented as a command in the
current scope. **oo::class** returns the fully qualified command name.

The newly-created class command is used to define objects which belong to the
class, just as **oo::object** is. By default, instances of the new class
have no more behaviour than instances of **oo::object** do; new class
behavior can be added to the class in two ways. First, a _definition_ can be
specified when creating the class; second, additional behaviour can be added
to the class using **oo::define**.

The definition, if given, consists of a series of statements that map to the
subcommands of **oo::define**. The following three code snippets are
equivalent; each defines a class called **::dog** whose instances will have
two subcommands: **bark** and **chase**.

	# Method 1
	oo::class create dog
	
	oo::define dog method bark {} {
	    puts "Woof, woof!"

	}
	
	oo::define dog method chase {thing} {
	    puts "Chase $thing!"

	}

	# Method 2
	oo::class create dog
	
	oo::define dog {
	    method bark {} {
	        puts "Woof, woof!"

	    }
	
	    method chase {thing} {
	        puts "Chase $thing!"


	    }
	}

	# Method 3
	oo::class create dog {
	    method bark {} {
	        puts "Woof, woof!"

	    }
	
	    method chase {thing} {
	        puts "Chase $thing!"


	    }
	}

### Constructor and Destructor

The constructor for **oo::class** concatenates its arguments and passes the
resulting script to **oo::define** \(along with the fully-qualified name of
the created class, of course\).

Classes have no destructor by default. \(Actual class destruction is special,
and happens after all destructors have been executed.\)

### Methods

The instances of **oo::class** have the following methods:

 create: Creates a new instance of the class with the given name. All
   subsequent arguments are given to the class's constructor \(and so must
   actually match the syntax pattern specified in the constructor definition\).
   The result of the **create** method is always the fully-qualified name of
   the newly-created object. The syntax is as follows:

 > _class_ **create** _objName_ ?_arg_ _arg_ ...?

 new: Creates a new instance of the class with an automatically chosen name.
   All subsequent arguments are given to the class's constructor \(and so must
   actually match the syntax pattern specified in the constructor definition\).
   The result of the **new** method is always the fully-qualified name of
   the newly-created object. The syntax is as follows:

 > _class_ **new** ?_arg_ _arg_ ...?

 > Note that the _oo::class_ object itself does not export the **new**
   method; it is good practice for all classes to have names.

 createWithNamespace: Creates a new instance of a class with a given name and
   a given name of backing namespace. This method \(required to provide proper
   support for putting [incr Tcl] on top of the core OO system\) is not
   exported by default. Apart from the _nsName_ parameter, it is the same as
   the **create** method.

 > _class_ **createWithNamespace** _objName nsName_ ?_arg arg_ ...?

# Introspection Support

The core Tcl **info** command shall be extended in the following ways.

## An [info object] Subcommand

An **object** subcommand that shall provide information about a particular
object. Its first argument shall be the name of an object to get information
about, its second argument shall be a subsubcommand indicating the type of
information to retrieve and all subsequent arguments shall be arguments, as
appropriate. The following types of information shall be available:

 class: Returns the class of an object, or if _className_ is specified,
   whether the object is \(directly or indirectly through inheritance or mixin\)
   an instance of the named class.

 > **info object class** _object_ ?_className_?

 definition: Returns the formal argument list and body used to define a
   method.

 > **info object definition** _object method_

 filters: Returns the list of filters defined for an object.

 > **info object filters** _object_

 forward: Returns the list of words that form the command prefix that a
   method is forwarded to.

 > **info object forward** _object method_

 isa: Returns boolean information about how an object relates to the class
   hierarchy. Supports a range of subcommands to allow the specification of
   what sort of test is to be performed:

 > class: Returns whether the named object is a class.

 > > **info object isa class** _object_

 > metaclass: Returns whether the named object is a class that can create
   other classes \(i.e. is **oo::class** or one of its subclasses\).

 > > **info object isa metaclass** _object_

 > mixin: Returns whether the named object has _mixinClassName_ as one of
     its mixins.

 > > **info object isa mixin** _object mixinClassName_

 > object: Returns whether _object_ really names an object.

 > > **info object isa object** _object_

 > typeof: Returns whether the object is of type _class_ \(i.e. an instance
     of that class or an instance of a subclass of that class\).

 > > **info object isa typeof** _object class_

 methods: Returns the list of methods defined for an object. Supports the
     options **-all** to also look at the class hierarchy for the object,
     and **-private** to get the list of methods supported by **my** for
     the object.

 > **info object methods** _object options_

 mixins: Returns the list of mixins for an object.

 > **info object mixins** _object_

 vars: Returns the list of all variables defined within the object, or
   optionally just those that match _pattern_ according to the rules of
   **string match**.

 > **info object vars** _object_ ?_pattern_?

## An [info class] Subcommand

A **class** subcommand that shall provide information about a particular
class. Its first argument shall be the name of a class to get information
about, its second argument shall be a subsubcommand indicating the type of
information to retrieve and all subsequent arguments shall be arguments, as
appropriate. The following types of information shall be available:

 constructor: Returns the formal argument list and body used to define the
   constructor, or an empty list if no constructor is present.

 > **info class constructor** _class_

 definition: Returns the formal argument list and body used to define a
   method.

 > **info class definition** _class method_

 destructor: Returns the body of the destructor, or an empty string if no
   destructor is present.

 > **info class destructor** _class_

 filters: Returns the list of filters defined for a class.

 > **info class filters** _class_

 forward: Returns the list of words that form the command prefix that a
   method is forwarded to.

 > **info class forward** _class method_

 instances: Returns a list of all direct instances of the class \(but not
   instances of any subclasses of the class\), or optionally just those that
   match _pattern_ according to the rules of **string match**.

 > **info class instances** _class_ ?_pattern_?

 methods: Returns the list of methods defined by a class. Supports the options
     **-all** to also look at the class hierarchy, and **-private** to get
     the list of methods supported by **my** for the object's instances.

 > **info class methods** _class options_

 subclasses: Returns a list of all subclasses of the class, or optionally just
   those that match _pattern_ according to the rules of **string match**.

 > **info class subclasses** _class_ ?_pattern_?

 superclasses: Returns a list of all superclasses of the named class in the
   class hierarchy. The list will be ordered in inheritance-precedence order.

 > **info class superclasses** _class_

## Extending the Introspection Capabilities

Other forms of introspection subcommands may be added to **info object** and
**info class** by creating exported commands in the namespaces
**oo::InfoObject** and **oo::InfoClass** respectively.

## Issues with Objects and Namespaces

Every object has a distinct namespace associated with it, the name of which is
outside the scope of this specification. It is the name of this namespace that
is returned by **self namespace**.

The namespace does have a path set, as if by calling **namespace path**;
this is how the **next** and **self** commands are provided, though since
they are never usable outside the scope of the body of a method, the namespace
which they originate from is out of the scope of this specification.

The **my** command is the only command in the object's namespace by default
\(i.e., this command is truly per-object\). It is not exported from the object's
namespace, nor are any other commands exported from or imported into the
namespace.

Methods are not commands, and so completely ignore the **namespace export**
command, nor does **namespace unknown** get involved at any point during the
location of a method. \(They may run during the processing of a method body; it
is a context very similar to a normal procedure body.\) Similarly, a method may
not be **namespace import**ed from another namespace.

Each method \(including both the constructor and destructor\) executed by an
object executes in that object's namespace. Changes made by a method to the
namespace \(including both command declaration and uses of **namespace
import**\) will be seen by all other methods invoked on the same object. Note
that methods declared by classes still execute in the instance objects'
namespaces.

# C API

_Note: This API is probably incomplete. Future TIPs may extend or completely
revise it._

## Datatypes

The following public datatypes shall be declared in tcl.h:

 Tcl\_Object: An opaque handle to an object.

 Tcl\_Class: An opaque handle to a class.

 Tcl\_Method: An opaque handle to a method.

 Tcl\_ObjectContext: An opaque handle to an object method call context.

 Tcl\_MethodType: A structure describing the type of a method implementation.
   It shall have the following fields:

 > version: The version number of the structure, which should always be
   referred to as TCL\_OO\_METHOD\_VERSION\_CURRENT in source code \(currently
   ignored, but allows transparent versioning in the future\).

 > name: The name of the method type, for debugging.

 > callProc: A pointer to a function that defines how to call method
   implementations of this type. Must not be NULL.

 > deleteProc: A pointer to a function that defines how to delete the
   _clientData_ associated with a particular method implementation instance.
   If NULL, no deletion of the _clientData_ is required.

 > cloneProc: A pointer to a function that defines how to copy the
   _clientData_ associated with a particular method implementation instance
   during the copying of an object or class with **oo::copy**. If NULL, the
   method will be cloned by just copying the _clientData_.

 Tcl\_ObjectMetadataType: A structure describing the type of some arbitrary
   non-NULL metadata attached to an object or class. It shall have the
   following fields:

 > version: The version number of the structure, which should always be
   referred to as TCL\_OO\_METADATA\_VERSION\_CURRENT in source code \(currently
   ignored, but allows for transparent versioning in the future\).

 > name: The name of the metadata type, for debugging.

 > deleteProc: A pointer to a function that defines how to delete some
   metadata associated with this type. Must not be NULL.

 > cloneProc: A pointer to a function that defines how to copy some metadata
   associated with this type during the copying of an object or class with
   **oo::copy**. If NULL, the metadata will not be copied. \(_Open issue:_
   There is a use case for making objects unclonable; consider the
   case where the metadata consists of one or more OS resource handles.
   Simply shallow-copying resource handles is a bad idea, but
   deep-copying them may well be infeasible. Not all objects can
   handle copy-on-write semantics gracefully.\)

 Tcl\_MethodCallProc: The type of the _callProc_ field of the Tcl\_MethodType
   structure. It is a pointer to a function that is used to implement how a
   method implementation is called. It takes five arguments and returns a
   normal Tcl result code. The arguments are:

 > clientData: Some method implementation instance specific data. Note that
   this is specific to the instance of the method implementation, and not
   \(necessarily\) the instance of the object.

 > interp: The Tcl interpreter reference.

 > objectContext: The object method call context, through which useful
   information \(such as what object this method was invoked upon\) can be
   obtained.

 > objc: The number of arguments.

 > objv: The actual list of arguments. Since the number of arguments required
   to indicate the method may vary, the method implementation should look up
   how many to skip over using the object method call context.

 Tcl\_MethodDeleteProc: The type of the _deleteProc_ field of the
   Tcl\_MethodType structure. It is a pointer to a function that is used to
   delete _clientData_ values associated with a method instance. It takes a
   single argument \(the _clientData_ to delete\) and has no return value.

 Tcl\_MethodCloneProc: The type of the _cloneProc_ field of the
   Tcl\_MethodType structure. It is a pointer to a function that is used to
   make copies of _clientData_ values associated with a method instance
   suitable for use in another method instance. It takes two arguments \(the
   _clientData_ to clone, and a pointer to a variable into which to write
   the cloned _clientData_\) and returns either TCL\_OK or TCL\_ERROR, with the
   method only being cloned if the result is TCL\_OK \(the method is silently
   not cloned otherwise\).

 Tcl\_ObjectMapMethodNameProc: The type of a callback function used to adjust
   the mapping of objects and method names to implementations, which is
   required to support building [incr Tcl] on top of the core OO system. It
   takes four arguments, being the interpreter, the object that the method is
   being invoked upon, a point to a variable to contain the class in the
   hierarchy to start the search for components of the method chain from, and
   an unshared object holding the method name as supplied and which can be
   modified if the method to look for is not the literal name passed in.

 > This is necessary because [incr Tcl] allows the invoking of superclass
   implementations of a method using a syntax like
   "_superclassName_::_methodName_" where _superclassName_ may name any
   superclass of the current class, and _methodName_ may be any method
   name.

 > Note that the exact definition of this type is subject to change at the
   moment in order to ensure that it can be connected to the method dispatch
   engine efficiently. The type will be finalized before the release of Tcl
   8.6.

 Tcl\_ObjectMetadataDeleteProc: The type of the _deleteProc_ field of the
   Tcl\_ObjectMetadataType structure. It is a pointer to a function that is
   used to delete _metadata_ values attached to an object or a class. It
   takes a single argument \(the _metadata_ to delete\) and has no return
   value.

 Tcl\_ObjectMetadataCloneProc: The type of the _cloneProc_ field of the
   Tcl\_ObjectMetadataType structure. It is a pointer to a function that is
   used to create a copy of _metadata_ values attached to an object or a
   class. It takes three argument, \(the interpreter, the _metadata_ to copy,
   and a pointer to a variable into which to write the copy, or NULL if the
   copy is not to be performed\) and returns a standard Tcl result code.

## Functions

The following functional operations are defined:

 Tcl\_NewMethod: This function creates a new method on a class \(and hence
   on all instances of that class\). It has the following signature:

 > Tcl\_Method **Tcl\_NewMethod**\(Tcl\_Interp \*_interp_, Tcl\_Class
   _cls_, Tcl\_Obj \*_nameObj_, int _isPublic_, const Tcl\_MethodType
   *_typePtr_, ClientData _clientData_\)

	 > If the method is created with a NULL _nameObj_, it must be installed
   manually into the class as a constructor or destructor \(in the latter case,
   it is important that the method be able to execute without additional
   arguments\). Note that a NULL _typePtr_ is reserved for internal use.

 Tcl\_ClassSetConstructor: This function installs a method into a class as a
   constructor for instances of that class. The method must have been created
   with **Tcl\_NewMethod** with a NULL _nameObj_ argument. It has the
   following signature:

	 > void **Tcl\_ClassSetConstructor**\(Tcl\_Class _cls_, Tcl\_Method
   _method_\)

 Tcl\_ClassSetDestructor: This function installs a method into a class as a
   destructor for instances of that class. The method must have been created
   with **Tcl\_NewMethod** with a NULL _nameObj_ argument. It has the
   following signature:

	 > void **Tcl\_ClassSetConstructor**\(Tcl\_Class _cls_, Tcl\_Method
   _method_\)

 Tcl\_NewInstanceMethod: This function creates a new method on an object. It
   has the following signature:

	 > Tcl\_Method **Tcl\_NewInstanceMethod**\(Tcl\_Interp \*_interp_, Tcl\_Object
   _object_, Tcl\_Obj \*_nameObj_, int _isPublic_, const Tcl\_MethodType
   *_typePtr_, ClientData _clientData_\)

	 > Note that a NULL _typePtr_ is reserved for internal use, and _nameObj_
   must not be NULL.

 Tcl\_NewObjectInstance: This function creates a new instance of a class,
   calling any defined constructors. It has the following signature, returning
   NULL \(and setting a message in the interpreter\) if the object creation
   failed:

	 > Tcl\_Object **Tcl\_NewObjectInstance**\(Tcl\_Interp \*_interp_, Tcl\_Class
   _cls_, const char \*_name_, const char \*_nsName_, int _objc_,
   Tcl\_Obj \*const \*_objv_, int _skip_\)

	 > Both _name_ and _nsName_ may be NULL, in which case the constructor
   code picks a default that doesn't clash with any previously existing
   commands or namespaces.

 Tcl\_CopyObjectInstance: This function creates a copy of an object \(including
   classes\) without copying the backing namespace or executing any
   constructors. It has the following signature, returning NULL \(and setting a
   message in the interpreter\) if the object copying failed:

	 > Tcl\_Object **Tcl\_CopyObjectInstance**\(Tcl\_Interp \*_interp_, Tcl\_Object
   _sourceObject_, const char \*_targetName_\)

	 > Note that the copying of an object can fail if the copy code for one of the
   metadata coping functions fails, so those functions can veto copying. Also
   note that if _targetName_ is NULL, a name will be picked for the object.
   Currently no control over the naming of the target object's namespace is
   provided.

 Tcl\_GetObjectFromObj: This function converts from a Tcl\_Obj holding the name
   of an object to a Tcl\_Object handle. It returns NULL \(leaving an error
   message in the interpreter\) if the conversion fails.

	 > Tcl\_Object **Tcl\_GetObjectFromObj**\(Tcl\_Interp \*_interp_, Tcl\_Obj
   *_objPtr_\)

 Tcl\_ObjectContextInvokeNext: This function invokes the next method
   implementation in a method call chain, and is the internal implementation
   of the **next** command. It has the following signature:

	 > int **Tcl\_ObjectContextInvokeNext**\(Tcl\_Interp \*_interp_,
   Tcl\_ObjectContext _context_, int _objc_, Tcl\_Obj \*const \*_objv_, int
   _skip_\)

 Tcl\_ClassGetMetadata: This function retrieves the metadata attached to the
   class _cls_ that is associated with the type _typePtr_. It returns NULL
   if no data of that type is attached.

	 > ClientData **Tcl\_ClassGetMetadata**\(Tcl\_Class _cls_, const
   Tcl\_ObjectMetadataType \*_typePtr_\)

 Tcl\_ClassSetMetadata: This function attaches metadata, _metadata_, of a
   specific type, _typePtr_, to the class, _clazz_, or removes the
   metadata of that type if _metadata_ is NULL. It is a no-op to remove
   metadata of a type that is not attached in the first place.

	 > void **Tcl\_ClassSetMetadata**\(Tcl\_Class _clazz_, const
   Tcl\_ObjectMetadataType \*_typePtr_, ClientData _metadata_\)

 Tcl\_ObjectGetMetadata: This function retrieves the metadata attached to the
   object _object_ that is associated with the type _typePtr_. It returns
   NULL if no data of that type is attached.

	 > ClientData **Tcl\_ObjectGetMetadata**\(Tcl\_Object _object_, const
   Tcl\_ObjectMetadataType \*_typePtr_\)

 Tcl\_ObjectSetMetadata: This function attaches metadata, _metadata_, of a
   specific type, _typePtr_, to the object, _object_, or removes the
   metadata of that type if _metadata_ is NULL. It is a no-op to remove
   metadata of a type that is not attached in the first place.

	 > void **Tcl\_ObjectSetMetadata**\(Tcl\_Object _object_, const
   Tcl\_ObjectMetadataType \*_typePtr_, ClientData _metadata_\)

 Tcl\_ObjectGetMethodNameMapper: This function retrieves the current method
   name mapping function for an object, or NULL if none was set. It has the
   following signature:

	 > Tcl\_ObjectMapMethodNameProc **Tcl\_ObjectGetMethodNameMapper**\(Tcl\_Object
   _object_\)

 Tcl\_ObjectSetMethodNameMapper: This functionsets the method name mapping
   function for an object, or removes it if the function is set to NULL. It
   has the following signature:

	 > void **Tcl\_ObjectSetMethodNameMapper**\(Tcl\_Object _object_,
   Tcl\_ObjectMapMethodNameProc _methodNameMapper_\)

The following pure inspective \(i.e., non-state changing\) operations are
defined:

 Tcl\_GetClassAsObject: This gets the object that represents a class.

 > Tcl\_Object **Tcl\_GetClassAsObject**\(Tcl\_Class _clazz_\)

 Tcl\_GetObjectAsClass: This gets the class that an object represents \(or NULL
   if the object does not represent a class\).

 > Tcl\_Class **Tcl\_GetObjectAsClass**\(Tcl\_Object _object_\)

 Tcl\_GetObjectCommand: This gets the command for an object. It is the name of
   this command that represents the object at the script level, and as such,
   it may be renamed.

 > Tcl\_Command **Tcl\_GetObjectCommand**\(Tcl\_Object _object_\)

 Tcl\_GetObjectNamespace: This gets the object's private namespace.

 > Tcl\_Namespace \***Tcl\_GetObjectNamespace**\(Tcl\_Object _object_\)

 Tcl\_MethodDeclarerClass: This gets the class that declared a method, or NULL
   if the method is a per-object method.

 > Tcl\_Class **Tcl\_MethodDeclarerClass**\(Tcl\_Method _method_\)

 Tcl\_MethodDeclarerObject: This gets the object that declared a method, or
   NULL if the method is a class method.

 > Tcl\_Object **Tcl\_MethodDeclarerObject**\(Tcl\_Method _method_\)

 Tcl\_MethodIsPublic: This returns whether a method is a public method. This
   status might be overridden in subclasses or objects.

 > int **Tcl\_MethodIsPublic**\(Tcl\_Method _method_\)

 Tcl\_MethodIsType: This returns whether a method is a specific type of
   method, and if so, also returns the _clientData_ for the type. No way of
   inspecting method types for which you do not have a pointer to the type
   structure is provided.

 > int **Tcl\_MethodIsType**\(Tcl\_Method _method_, const Tcl\_MethodType
   *_typePtr_, ClientData \*_clientDataPtr_\)

 Tcl\_MethodName: This returns the name of a method.

	 > Tcl\_Obj \***Tcl\_MethodName**\(Tcl\_Method _method_\)

 Tcl\_ObjectDeleted: This returns whether an object has been deleted \(assuming
   deletion has not yet completed, i.e., that the destructor is currently
   being processed\).

	 > int **Tcl\_ObjectDeleted**\(Tcl\_Object _object_\)

 Tcl\_ObjectContextIsFiltering: This returns whether the method call context is
   working with a filter or not.

	 > int **Tcl\_ObjectContextIsFiltering**\(Tcl\_ObjectContext _context_\)

 Tcl\_ObjectContextMethod: This returns the method call context's current
   method instance.

	 > Tcl\_Method **Tcl\_ObjectContextMethod**\(Tcl\_ObjectContext _context_\)

 Tcl\_ObjectContextObject: This returns the method call context's object \(i.e.,
   the object which was invoked\).

	 > Tcl\_Object **Tcl\_ObjectContextObject**\(Tcl\_ObjectContext _context_\)

 Tcl\_ObjectContextSkippedArgs: This returns the number of arguments to be
   skipped \(this varies because the method instance may be invoked through
   either [obj method ...] or through [next ...]\).

	 > int **Tcl\_ObjectContextSkippedArgs**\(Tcl\_ObjectContext _context_\)

# Not Addressed in this Document

This TIP does not address the reqirements for management of variables on a
class level or for "class methods" \(in the Java sense\). These will need to be
the subject of future TIPs.

# Copyright

This document has been placed in the public domain.

----

The following sections are non-normative.

# Appendix: Class Hierarchy for Support of Other OO Systems

When using the OO system as a basis for some other object system, it is useful
for all classes and objects to derive from some other object root for
compatability with existing practice. To see how to do this, consider this
class hierarchy \(targetted at XOTcl\) outlined below. The XOTcl _Object_
class would derive from the core **oo::object** class, and the XOTcl
_Class_ class would derive from the core **oo::class** and the XOTcl
_Object_ classes. This would give the following diagram \(core classes are in
lower case with their namespace omitted, XOTcl classes are in upper case, with
namespace omitted\).

	                     +--------+
	            ,------->| object |
	            |        +--------+
	            |            ,^.
	    creates |       ______|______
	            |      |             |
	            |  +-------+    +--------+
	            `--| class |    | Object |<-.
	               +-------+    +--------+  |
	                  ,^.           ,^.     |
	                   |______ ______|      | creates
	                          |             |
	                      +-------+         |
	                      | Class |---------'
	                      +-------+

Note that **class** instances create **object**s \(or subclasses thereof\),
but _Class_ instances create _Object_s \(or subclasses thereof\).

# Appendix: XOTcl Features Omitted from the Core OO System

## Object Methods

 Object::autoname: This is trivially implemented in a small procedure, and
   core objects can pick names for themselves and are renameable.

 Object::check: Preconditions and postconditions are not supported \(they add a
   lot of complexity\) and neither are invariants. Hence, there is no need to
   control whether they are executed.

 Object::cleanup: This is not an especially well-defined method \(what if the
   object happens to hold handles to complex resources such as network
   sockets; it is not generally possible for the state of the remote server to
   be reset\) and can be added in any compatability layer.

 Object::configure: This feature has been deliberately omitted from the core
   object system. This would be value added by any XOTcl extension.

 Object::extractConfigureArg: This feature is part of **configure**.

 Object::getExitHandler: This feature is not necessary for this version. If it
   existed, it would not need to be a part of the base object.

 Object::info: The introspection features are moved into the core **info**
   command.

 Object::invar: Invariants may be implemented using filters.

 Object::move: This feature is equivalent to the use of the standard
   **rename** operation.

 Object::noinit: This feature has been deliberately omitted from the core
   object system because its use is dependent on the use of other
   deliberately-omitted features \(i.e., **configure**\). This would be value
   added by any XOTcl extension.

 Object::parameter and Object::parametercmd: The core object system provides
   tools for doing parameters, but does not provide an implementation on the
   grounds that it is pretty easy to add.

 Object::requireNamespace: Objects always have a namespace.

 Object::setExitHandler: See the comments for **getExitHandler** above.

## Class Methods

 Class::\_\_unknown: Auto-loading of unknown classes is handled by the standard
   core **unknown** mechanism.

 Class::abstract: Abstractness is relatively easy to implement on top of the
   proposed infrastructure and is not critical to getting an implementation.

 Class::allinstances: This feature is trivially implemented in a small
   procedure.

 Class::alloc: The core objects have no default behaviour, so the difference
   with the basic core class behaviour is moot.

 Class::create: Core object creation is a much more sealed process, but the
   lack of **configure**-like behaviour means that the complexity of this
   method is not necessary. Instead, constructors are called automatically.

 Class::parameterclass: Core object system parameters are not implemented by
   classes.

 Class::volatile: This feature is omitted as it is believed that it is
   possible to implement automated lifecycle management as a mixin.

## Other Commands

 getExitHandler, setExitHandler: Exit handlers are out of scope for the core
   object system.

Name change from tip/258.tip to tip/258.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
136
137
138
139
140
141
142
143
144
145
146
147

TIP:            258
Title:          Enhanced Interface for Encodings
Version:        $Revision: 1.4 $
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        01-Oct-2005
Post-History:	
Keywords:       encoding
Tcl-Version:    8.5


~ Abstract

This TIP proposes public C routines and a new '''encoding dirs'''
subcommand to improve the interfaces to Tcl's encodings.

~ Background

Several internal improvements have been made to the internals of how
Tcl encodings are initialized, found, stored, and refcounted during
Tcl 8.5 development. This TIP is primarily about making these
improvements available via public interfaces.

The lifetime of '''Tcl_Encoding''' values has been identified as a
problem (Bug 1077262), where premature freeing means repeated
re-loading of encoding data. Since each encoding data load involves
interaction with the filesystem, this can be an expensive mistake.

The Tcl documentation has long claimed that by setting the value of a
global variable '''::tcl_libPath''' a script could influence the
search path of directories where encoding data files are sought. That
documentation has never been correct (Bug 463190).

Tclkit suffers from an initialization dilemma. It stores encoding data
files in a virtual filesystem. In particular the system encoding is
often based on a data file in the virtual filesystem. The Tclkit
virtual filesystem is (largely) script-implemented and cannot exist
until a '''Tcl_Interp''' has been created. However, Tcl wants to
determine the correct value for the system encoding very early in its
initialization, before any '''Tcl_Interp''' gets created. The
consequence is that Tclkit fails to successfully set the system
encoding in Tcl's early initialization, and Tclkit has had to jump
through hoops to get Tcl to repeat those early initialization steps
after the virtual filesystem is in place.

~ Proposed changes

Add the following routines to Tcl's public interface:

 > int '''Tcl_GetEncodingFromObj'''(Tcl_Interp *''interp'',
   Tcl_Obj *''objPtr'', Tcl_Encoding *''encodingPtr'')

Writes to *''encodingPtr'' the '''Tcl_Encoding''' value that
corresponds to the value of ''objPtr'', and returns '''TCL_OK'''. The
'''Tcl_Encoding''' value is also cached as the internal rep of
''objPtr'' so that the lifetime of the '''Tcl_Encoding''' data in the
process will be at least the lifetime of that internal rep of
''objPtr''. The caller is expected to call '''Tcl_FreeEncoding''' on
*''encodingPtr'' when it no longer needs it. If no corresponding
'''Tcl_Encoding''' value for the value of ''objPtr'' can be
determined, '''TCL_ERROR''' is returned, and an error message is
stored in the result of ''interp''.

 > Tcl_Obj *'''Tcl_GetEncodingSearchPath'''()

Returns a list of directory pathnames that Tcl's encoding subsystem
will search for encoding data files when an encoding is requested
that's not already loaded in the process. This will be the value
stored by the last successful call to '''Tcl_SetEncodingSearchPath'''.
If no calls to '''Tcl_SetEncodingSearchPath''' have occurred, Tcl will
compute an initial value based on the environment. There is one
encoding search path for the entire process, shared by all threads in
the process.

 > int '''Tcl_SetEncodingSearchPath'''(Tcl_Obj *''searchPath'')

Stores ''searchPath'' as the list of directory pathnames for Tcl's
encoding subsystem to search for encoding data files, and returns
'''TCL_OK'''. Returns '''TCL_ERROR''' only if ''searchPath'' is not a
valid Tcl list. There is no checking for validity of the directory
pathnames, so for example, one can place a directory on the encoding
search path before mounting the '''Tcl_Filesystem''' that contains
that directory. When searching for encoding data files, Tcl's encoding
subsystem ignores any non-existent directories in the search path as
well.

 > CONST char *'''Tcl_GetEncodingNameFromEnvironment'''(Tcl_DString *''bufPtr'')

This routine exposes Tcl's determination about what the system
encoding should be, based on system calls and examination of the
environment suitable for the platform. It accepts ''bufPtr'', a
pointer to an uninitialized or freed '''Tcl_DString''' and writes to
it the string value of the appropriate system encoding dictated by the
environment. The '''Tcl_DStringValue''' is returned.

In a properly initialized Tcl, the string value returned by
'''Tcl_GetEncodingNameFromEnvironment''' ought to be the same as that
returned by '''Tcl_GetEncodingName'''('''NULL'''); that is, the system
encoding dictated by the environment ought to be the encoding Tcl will
return as the result of '''encoding system'''.

If these two results do not match, it indicates that at the time Tcl
was initialized, the proper sytem encoding was not available. Perhaps
the necessary data file was not on the encoding search path at that
time. With this new routine, the check for this match can be
performed, and if the match does not exist, a call to
'''Tcl_SetSystemEncoding''' can try again to get Tcl's system encoding
to agree with what the environment dictates.

Add a new subcommand, '''encoding dirs''' with syntax:

 > '''encoding dirs''' ?''searchPath''?

This subcommand is the script-level interface to the
'''Tcl_GetEncodingSearchPath''' and '''Tcl_SetEncodingSearchPath'''
routines. When called without an argument, the current list of
directory pathnames to be searched for encoding files is returned.
When called with ''searchPath'' argument, the value ''searchPath'' is
set as the new list of directory pathnames to be searched.

The documentation for existing routines
'''Tcl_GetDefaultEncodingDir''' and '''Tcl_SetDefaultEncodingDir'''
will be updated to discourage their use and to encourage the use of
'''Tcl_GetEncodingSearchPath''' and '''Tcl_SetEncodingSearchPath'''
instead.

~ Compatibility

This proposal includes only new features. It is believed that existing
scripts and C code that operate without errors will continue to do so.

The '''encoding dirs''' command has been available with the name
'''::tcl::unsupported::EncodingDirs''' since the Tcl 8.5a3 release. It
is proposed to remove this unsupported command completely, as it has
only existed in alpha releases. Anyone using it should be able to
migrate to '''encoding dirs''' without difficulty.

~ Reference Implementation

The actual code is already complete as internals corresponding to the
proposed public. Implementation is just an exercise in renaming,
placing in stub tables, documentation, etc.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|






|
|




|

|




|
|

|





|



|
|

|
|
|
|

|
|
|
|
|

|




|
|




|

|

|


|




|



|
|

|


|
|

|






|


|

|


|


|



|

|


|




|
|


|

|





|


>

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
136
137
138
139
140
141
142
143
144
145
146
147

# TIP 258: Enhanced Interface for Encodings

	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        01-Oct-2005
	Post-History:	
	Keywords:       encoding
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes public C routines and a new **encoding dirs**
subcommand to improve the interfaces to Tcl's encodings.

# Background

Several internal improvements have been made to the internals of how
Tcl encodings are initialized, found, stored, and refcounted during
Tcl 8.5 development. This TIP is primarily about making these
improvements available via public interfaces.

The lifetime of **Tcl\_Encoding** values has been identified as a
problem \(Bug 1077262\), where premature freeing means repeated
re-loading of encoding data. Since each encoding data load involves
interaction with the filesystem, this can be an expensive mistake.

The Tcl documentation has long claimed that by setting the value of a
global variable **::tcl\_libPath** a script could influence the
search path of directories where encoding data files are sought. That
documentation has never been correct \(Bug 463190\).

Tclkit suffers from an initialization dilemma. It stores encoding data
files in a virtual filesystem. In particular the system encoding is
often based on a data file in the virtual filesystem. The Tclkit
virtual filesystem is \(largely\) script-implemented and cannot exist
until a **Tcl\_Interp** has been created. However, Tcl wants to
determine the correct value for the system encoding very early in its
initialization, before any **Tcl\_Interp** gets created. The
consequence is that Tclkit fails to successfully set the system
encoding in Tcl's early initialization, and Tclkit has had to jump
through hoops to get Tcl to repeat those early initialization steps
after the virtual filesystem is in place.

# Proposed changes

Add the following routines to Tcl's public interface:

 > int **Tcl\_GetEncodingFromObj**\(Tcl\_Interp \*_interp_,
   Tcl\_Obj \*_objPtr_, Tcl\_Encoding \*_encodingPtr_\)

Writes to \*_encodingPtr_ the **Tcl\_Encoding** value that
corresponds to the value of _objPtr_, and returns **TCL\_OK**. The
**Tcl\_Encoding** value is also cached as the internal rep of
_objPtr_ so that the lifetime of the **Tcl\_Encoding** data in the
process will be at least the lifetime of that internal rep of
_objPtr_. The caller is expected to call **Tcl\_FreeEncoding** on
*_encodingPtr_ when it no longer needs it. If no corresponding
**Tcl\_Encoding** value for the value of _objPtr_ can be
determined, **TCL\_ERROR** is returned, and an error message is
stored in the result of _interp_.

 > Tcl\_Obj \***Tcl\_GetEncodingSearchPath**\(\)

Returns a list of directory pathnames that Tcl's encoding subsystem
will search for encoding data files when an encoding is requested
that's not already loaded in the process. This will be the value
stored by the last successful call to **Tcl\_SetEncodingSearchPath**.
If no calls to **Tcl\_SetEncodingSearchPath** have occurred, Tcl will
compute an initial value based on the environment. There is one
encoding search path for the entire process, shared by all threads in
the process.

 > int **Tcl\_SetEncodingSearchPath**\(Tcl\_Obj \*_searchPath_\)

Stores _searchPath_ as the list of directory pathnames for Tcl's
encoding subsystem to search for encoding data files, and returns
**TCL\_OK**. Returns **TCL\_ERROR** only if _searchPath_ is not a
valid Tcl list. There is no checking for validity of the directory
pathnames, so for example, one can place a directory on the encoding
search path before mounting the **Tcl\_Filesystem** that contains
that directory. When searching for encoding data files, Tcl's encoding
subsystem ignores any non-existent directories in the search path as
well.

 > CONST char \***Tcl\_GetEncodingNameFromEnvironment**\(Tcl\_DString \*_bufPtr_\)

This routine exposes Tcl's determination about what the system
encoding should be, based on system calls and examination of the
environment suitable for the platform. It accepts _bufPtr_, a
pointer to an uninitialized or freed **Tcl\_DString** and writes to
it the string value of the appropriate system encoding dictated by the
environment. The **Tcl\_DStringValue** is returned.

In a properly initialized Tcl, the string value returned by
**Tcl\_GetEncodingNameFromEnvironment** ought to be the same as that
returned by **Tcl\_GetEncodingName**\(**NULL**\); that is, the system
encoding dictated by the environment ought to be the encoding Tcl will
return as the result of **encoding system**.

If these two results do not match, it indicates that at the time Tcl
was initialized, the proper sytem encoding was not available. Perhaps
the necessary data file was not on the encoding search path at that
time. With this new routine, the check for this match can be
performed, and if the match does not exist, a call to
**Tcl\_SetSystemEncoding** can try again to get Tcl's system encoding
to agree with what the environment dictates.

Add a new subcommand, **encoding dirs** with syntax:

 > **encoding dirs** ?_searchPath_?

This subcommand is the script-level interface to the
**Tcl\_GetEncodingSearchPath** and **Tcl\_SetEncodingSearchPath**
routines. When called without an argument, the current list of
directory pathnames to be searched for encoding files is returned.
When called with _searchPath_ argument, the value _searchPath_ is
set as the new list of directory pathnames to be searched.

The documentation for existing routines
**Tcl\_GetDefaultEncodingDir** and **Tcl\_SetDefaultEncodingDir**
will be updated to discourage their use and to encourage the use of
**Tcl\_GetEncodingSearchPath** and **Tcl\_SetEncodingSearchPath**
instead.

# Compatibility

This proposal includes only new features. It is believed that existing
scripts and C code that operate without errors will continue to do so.

The **encoding dirs** command has been available with the name
**::tcl::unsupported::EncodingDirs** since the Tcl 8.5a3 release. It
is proposed to remove this unsupported command completely, as it has
only existed in alpha releases. Anyone using it should be able to
migrate to **encoding dirs** without difficulty.

# Reference Implementation

The actual code is already complete as internals corresponding to the
proposed public. Implementation is just an exercise in renaming,
placing in stub tables, documentation, etc.

# Copyright

This document has been placed in the public domain.

Name change from tip/259.tip to tip/259.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

TIP:            259
Title:          Making 'exec' Optionally Binary Safe
Version:        $Revision: 1.4 $
Author:         Andreas Leitgeb <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        12-Dec-2005
Post-History:   
Tcl-Version:    8.7


~ Abstract

A new option shall be added to the command '''exec''', that allows the user to
specify that input redirected from immediate data (using '''<<''') and/or the
data received from the external command shall not undergo any translation
within Tcl.

~ Motivation

External programs may expect binary data, or write out binary data, or neither
or even both. Whether a program reads/writes binary data or platform-encoded
data is generally specific to the particular program and known by the
programmer who intends to '''exec''' it from a Tcl script.

For example, a hexdump-utility expectably reads binary data and outputs text.

~ Deficiencies of Current State of exec

'''Problem 1:''' For passing string-data to external programs, '''exec''' now
behaves arguably incorrect, because it does not pass through \0-bytes.

'''Problem 2:''' For returning the result of external programs, '''exec'''
applies translations based on system-default encoding, which is OK in most
cases, except, of course, for programs that output binary data.

Problem 1 is actually a bug, but for compatibility reasons some internal
function cannot be changed, because it is believed to be used by some
extensions (although it is not officially exported), thus blocking the fixing
of the bug. This TIP goes beyond that, by not having it fixed to some
particular consistent behaviour, but to let the script-developer decide on
what is the right behaviour for his needs.

Problem 2 prevents the output of binary-outputting programs from being
correctly retrieved.

~ Proposal for a New Option

The '''exec''' command already has an interface for options, and currently
supports one option '''-keepnewline''' and the end-of-options marker '''--'''.
This means that adding a new option will not adversely affect any existing
scripts.

This TIP proposes a new option, '''-binary''' ''arg''. ''arg'' can be either a
single boolean value:

 > if a boolean true then both input (if a '''<<''' redirection is present)
       and return value are passed verbatim between Tcl and the external
       program.

 > if a boolean false (which is the default) then behaviour would be like it
       is now, except for input being \0-safe and system-translation taking
       place as appropriate (e.g. line-endings).

''arg'' can also be one of the keywords '''in''', '''out''', '''both''' (which
is equivalent to 1) or an empty string (equivalent to 0) for more readable
code. The directions are to be seen from external programs perspective.

If ''arg'' is any true boolean value, '''both''' or '''out''', then the option
'''-keepnewline''' is implied.

If some usage of '''exec''' does not use '''<<''' string-redirection, then the
'''in'''-bit has no visible effect.

For now, no binary flag is defined for stderr. This might be subject of a
future TIP or left out due to lack of need.

~ Alternatives

Benjamin Riefenstahl suggested to not make a binary (in the sense of yes/no) decision for each of input and output, but to directly specify the encodings to use (of which "binary" would also be a valid one).

This has some subtle disadvantage for usage.

As proposed, there is *one* option with one argument of effectively 4 different values. From each of these values it is evident, on which channels conversion takes place.

To specify arbitrary encodings independently for two channels, there would need to be a list of encodings. For consistency with other commands, the "stdin"-encoding would have to be first, though it is
used rarelier than output-encoding. So most times one would have to pass -encoding {{} binary} (yuck!) to specify encoding for output only.

Unlike with general channels (as used for open |... or sockets) the data going through exec is always "limited": before actually calling exec it exists completely in memory as argument to exec, and afterwards output is returned as one single returnvalue. Each of these chunks can be handled as binary for exec, and explicitly converted through "encoding convertto" (for input) or encoding convertfrom (for output).

Encoding per system-default is achieved by not adding any -binary option to exec at all, which covers probably >95% of all usages, anyway. (the remaining 5% being the ones for whom this TIP has been written)

~ Implementation

No implementation exists right now, although it is possible that this will
change in near future.

An implementation would have to change these functions: Those functions that
are not modifyable due to them being used elsewhere, need to be replaced by an
extended version, and the old function can be changed to call the new one with
appropriate extra arguments, and eventually be phased out.

 Tcl_ExecObjCmd: Handle the new option and set new bits for the flags argument
   of ''Tcl_OpenCommandChannel'' or add a new bitset argument.

 Tcl_OpenCommandChannel: Deal with the new bits, or with new argument and pass
   them/it on.

 TclCreatePipeline: needs new arguments ''flags'' (for solving bug #768678
   along the way) and pass new arguments to a new variant of
   ''TclpCreateTempFile''.

 TclpCreateTempFile: both Unix and Win version currently get a dumb C-style
   char-pointer with no length-information. They need two extra arguments, a
   length and the appropriate binary-bit. Since ''TclpCreateTempFile'' is in
   the stubs-table, we definitely need a new Version of it, e.g.
   ''TclpCreateTempFileEx'', which will take and use these new arguments.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|



|




|



|

|
|

|





|







|

|
|



|


|



|
|
|

|
|


|
|

|
|




|

|



|


|

|

|

|









|
|

|


|
|
|



|

|

|


>

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

# TIP 259: Making 'exec' Optionally Binary Safe

	Author:         Andreas Leitgeb <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        12-Dec-2005
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

A new option shall be added to the command **exec**, that allows the user to
specify that input redirected from immediate data \(using **<<**\) and/or the
data received from the external command shall not undergo any translation
within Tcl.

# Motivation

External programs may expect binary data, or write out binary data, or neither
or even both. Whether a program reads/writes binary data or platform-encoded
data is generally specific to the particular program and known by the
programmer who intends to **exec** it from a Tcl script.

For example, a hexdump-utility expectably reads binary data and outputs text.

# Deficiencies of Current State of exec

**Problem 1:** For passing string-data to external programs, **exec** now
behaves arguably incorrect, because it does not pass through \\0-bytes.

**Problem 2:** For returning the result of external programs, **exec**
applies translations based on system-default encoding, which is OK in most
cases, except, of course, for programs that output binary data.

Problem 1 is actually a bug, but for compatibility reasons some internal
function cannot be changed, because it is believed to be used by some
extensions \(although it is not officially exported\), thus blocking the fixing
of the bug. This TIP goes beyond that, by not having it fixed to some
particular consistent behaviour, but to let the script-developer decide on
what is the right behaviour for his needs.

Problem 2 prevents the output of binary-outputting programs from being
correctly retrieved.

# Proposal for a New Option

The **exec** command already has an interface for options, and currently
supports one option **-keepnewline** and the end-of-options marker **--**.
This means that adding a new option will not adversely affect any existing
scripts.

This TIP proposes a new option, **-binary** _arg_. _arg_ can be either a
single boolean value:

 > if a boolean true then both input \(if a **<<** redirection is present\)
       and return value are passed verbatim between Tcl and the external
       program.

 > if a boolean false \(which is the default\) then behaviour would be like it
       is now, except for input being \\0-safe and system-translation taking
       place as appropriate \(e.g. line-endings\).

_arg_ can also be one of the keywords **in**, **out**, **both** \(which
is equivalent to 1\) or an empty string \(equivalent to 0\) for more readable
code. The directions are to be seen from external programs perspective.

If _arg_ is any true boolean value, **both** or **out**, then the option
**-keepnewline** is implied.

If some usage of **exec** does not use **<<** string-redirection, then the
**in**-bit has no visible effect.

For now, no binary flag is defined for stderr. This might be subject of a
future TIP or left out due to lack of need.

# Alternatives

Benjamin Riefenstahl suggested to not make a binary \(in the sense of yes/no\) decision for each of input and output, but to directly specify the encodings to use \(of which "binary" would also be a valid one\).

This has some subtle disadvantage for usage.

As proposed, there is \*one\* option with one argument of effectively 4 different values. From each of these values it is evident, on which channels conversion takes place.

To specify arbitrary encodings independently for two channels, there would need to be a list of encodings. For consistency with other commands, the "stdin"-encoding would have to be first, though it is
used rarelier than output-encoding. So most times one would have to pass -encoding \{\{\} binary\} \(yuck!\) to specify encoding for output only.

Unlike with general channels \(as used for open \|... or sockets\) the data going through exec is always "limited": before actually calling exec it exists completely in memory as argument to exec, and afterwards output is returned as one single returnvalue. Each of these chunks can be handled as binary for exec, and explicitly converted through "encoding convertto" \(for input\) or encoding convertfrom \(for output\).

Encoding per system-default is achieved by not adding any -binary option to exec at all, which covers probably >95% of all usages, anyway. \(the remaining 5% being the ones for whom this TIP has been written\)

# Implementation

No implementation exists right now, although it is possible that this will
change in near future.

An implementation would have to change these functions: Those functions that
are not modifyable due to them being used elsewhere, need to be replaced by an
extended version, and the old function can be changed to call the new one with
appropriate extra arguments, and eventually be phased out.

 Tcl\_ExecObjCmd: Handle the new option and set new bits for the flags argument
   of _Tcl\_OpenCommandChannel_ or add a new bitset argument.

 Tcl\_OpenCommandChannel: Deal with the new bits, or with new argument and pass
   them/it on.

 TclCreatePipeline: needs new arguments _flags_ \(for solving bug \#768678
   along the way\) and pass new arguments to a new variant of
   _TclpCreateTempFile_.

 TclpCreateTempFile: both Unix and Win version currently get a dumb C-style
   char-pointer with no length-information. They need two extra arguments, a
   length and the appropriate binary-bit. Since _TclpCreateTempFile_ is in
   the stubs-table, we definitely need a new Version of it, e.g.
   _TclpCreateTempFileEx_, which will take and use these new arguments.

# Copyright

This document has been placed in the public domain.

Name change from tip/26.tip to tip/26.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
TIP:            26
Title:          Enhancements for the Tk Text Widget
Version:        $Revision: 1.9 $
Author:         Ludwig Callewaert <[email protected]>
Author:         Ludwig Callewaert <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        20-Feb-2001
Post-History:   
Discussions-To: news:comp.lang.tcl
Obsoletes:      19
Tcl-Version:    8.4


~ Abstract

This TIP proposes several enhancements for the Tk text widget.  An
unlimited undo/redo mechanism is proposed, with several user available
customisation features.  Related to this, a text modified indication
is proposed.  This means that the user can set, query or receive a virtual
event when the content of the text widget is modified.  And finally a
virtual event is added that is generated whenever the selection
changes in the text widget.

~ Rationale

The text widget provides a lot of features that make it ideally suited
to create a text editor from it.  The vast number of editors that are
based on this widget are a proof of this.  Yet some basic features are
missing from the text widget and need to be re-invented over and over
again by the authors of the various editors.  This TIP adds a number
of the missing features.

A first missing feature is an undo/redo mechanism.  The mechanism
proposed here is simple yet powerful enough to accommodate a very
reasonable undo/redo strategy.  It also provides sufficient user
control, so that the actual strategy can be refined and tailored to
the users need.

A second missing feature is a notification if the text in the widget
has been modified with respect to a reference point.  [19] deals
partly with this.  This implementation takes it some steps further.
First of all, there is a link with the undo/redo mechanism, since
undoing or redoing changes can take you to or away from the reference
point, and as such changes the modified state of the widget.
Secondly, with this implementation, a virtual event is generated
whenever the modified state of the widget changes, allowing the user
to bind to that event and for instance give a visual indication of the
modified state of the widget.

Finally, a virtual event has been added that is triggered whenever the
selection in the widget changes.  At first it may seem not so useful,
but there are a number of situations where this functionality is
needed.  A couple of examples where I ran into the need for this may
clarify this.  On Windows, if the text widget does not have the focus,
the selection tag is not visible.  This is consistent with other
Windows applications.  However, when implementing a search mechanism,
the found string needs to be tagged with the selection tag.  (You want
it to be selected).  The search (and replace) dialog box has the focus
however, so this selection tag is invisible.  To make it visible,
another tag was used to duplicate the selection tag.  This is very
easy when the functionality described here is available.  Otherwise it
is very difficult to do this consistently.  Another occasion was when
I was implementing a rectangular cut and paste for the text widget.
This was based on adding spaces on the fly, while selecting the
rectangle.  If for some reason the selection changes (for instance on
Unix another application gets the selection) these spaces need to be
removed again.  Doing this is virtually impossible without this
functionality.  With it, it becomes trivial.  The functionality itself
adds little or no overhead to the text widget.

~ Specification

The undo/redo mechanism operates by adding two stacks of edit actions
to the text widget.  Every insert or delete operation is added to the
undo stack in normal operation.  At certain times a separator is added 
onto the stack.  All insert and delete actions in between two separators
are considered to be one edit action, and will be undone or redone as one.  
The insertion of the separators is under user control.  There is a 
<
|
<
|
|
|
|
|
|
|
|
|
|
>

|









|















|
















|
|






|
|




|








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

# TIP 26: Enhancements for the Tk Text Widget

	Author:         Ludwig Callewaert <[email protected]>
	Author:         Ludwig Callewaert <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        20-Feb-2001
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Obsoletes:      19
	Tcl-Version:    8.4
-----

# Abstract

This TIP proposes several enhancements for the Tk text widget.  An
unlimited undo/redo mechanism is proposed, with several user available
customisation features.  Related to this, a text modified indication
is proposed.  This means that the user can set, query or receive a virtual
event when the content of the text widget is modified.  And finally a
virtual event is added that is generated whenever the selection
changes in the text widget.

# Rationale

The text widget provides a lot of features that make it ideally suited
to create a text editor from it.  The vast number of editors that are
based on this widget are a proof of this.  Yet some basic features are
missing from the text widget and need to be re-invented over and over
again by the authors of the various editors.  This TIP adds a number
of the missing features.

A first missing feature is an undo/redo mechanism.  The mechanism
proposed here is simple yet powerful enough to accommodate a very
reasonable undo/redo strategy.  It also provides sufficient user
control, so that the actual strategy can be refined and tailored to
the users need.

A second missing feature is a notification if the text in the widget
has been modified with respect to a reference point.  [[19]](19.md) deals
partly with this.  This implementation takes it some steps further.
First of all, there is a link with the undo/redo mechanism, since
undoing or redoing changes can take you to or away from the reference
point, and as such changes the modified state of the widget.
Secondly, with this implementation, a virtual event is generated
whenever the modified state of the widget changes, allowing the user
to bind to that event and for instance give a visual indication of the
modified state of the widget.

Finally, a virtual event has been added that is triggered whenever the
selection in the widget changes.  At first it may seem not so useful,
but there are a number of situations where this functionality is
needed.  A couple of examples where I ran into the need for this may
clarify this.  On Windows, if the text widget does not have the focus,
the selection tag is not visible.  This is consistent with other
Windows applications.  However, when implementing a search mechanism,
the found string needs to be tagged with the selection tag.  \(You want
it to be selected\).  The search \(and replace\) dialog box has the focus
however, so this selection tag is invisible.  To make it visible,
another tag was used to duplicate the selection tag.  This is very
easy when the functionality described here is available.  Otherwise it
is very difficult to do this consistently.  Another occasion was when
I was implementing a rectangular cut and paste for the text widget.
This was based on adding spaces on the fly, while selecting the
rectangle.  If for some reason the selection changes \(for instance on
Unix another application gets the selection\) these spaces need to be
removed again.  Doing this is virtually impossible without this
functionality.  With it, it becomes trivial.  The functionality itself
adds little or no overhead to the text widget.

# Specification

The undo/redo mechanism operates by adding two stacks of edit actions
to the text widget.  Every insert or delete operation is added to the
undo stack in normal operation.  At certain times a separator is added 
onto the stack.  All insert and delete actions in between two separators
are considered to be one edit action, and will be undone or redone as one.  
The insertion of the separators is under user control.  There is a 
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244


245
246
247
248
249
250
251
252
253
254
255
256


257
258
259
260
261
262
263
264
265



266
267
268
269
270
271
272


273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295


296
297
298
299
300
301
302
303
304
305
306

307
308
309
310
311
312
313
314
315
316
317
318
319
320

321
322
323
324
325
326
327
328
329
330

331
332
333
334
335
336
337


338
339
340
341
342
343
344
345
346


347
348
349
350
351
352
353
354
355
356
357
358

Currently only text inserts and deletes can be undone. All other changes
to the widget, such as the adding or deleting of tags, cannot be undone.

The modified state of the widget is implemented using a counter.
Every insert or delete action, and every time such an action is redone,
increments this counter. Every undone insert or delete decrements this 
counter.  The widget is considered to be modified if the counter is not
zero.  A virtual event ''<<Modified>>'' is generated whenever this 
counter changes from zero to non-zero or vice versa.  A mechanism is 
provided to reset the counter to zero. The modified state can also be 
explicitely set by the user. In that case, the counter mechanism is not 
operational until the modified state has been reset again.

   1.  ''pathName configure -undo 0|1'' - this enables or disables the
       undo/redo mechanism.  The default is zero.

   2.  ''pathName configure -autoseparators 0|1'' - when one inserts
       a separator automatically whenever insert changes to delete or
       vice versa. Separators are also inserted when the keyboard or
       the mouse is used to move the insert mark, or when the <Return>
       key is pressed. When off, no separators are inserted, except by
       the user (See 6).  The default is one.

   3.  ''pathName edit undo'' - undoes the last edit action if undo is
       enabled (See 1). The insert mark will be positioned at the last
       undone edit action. When undo deletes text, that is the index
       where the text was. When undo inserts text, the insert mark
       will be positioned at the end of the inserted text. The view will
       be adapted to make the insert mark visible. Raises an exception 
       if there is nothing to undo. Does nothing if undo is disabled.

   4.  ''pathName edit redo'' - redoes the last edit action if undo is
       enabled (See 1). The insert mark and widget view will be updated
       similar to what is done for the edit undo command. Raises an 
       exception if there is nothing to redo.  Does nothing if undo is 
       disabled.

   5.  ''pathName edit reset'' - resets the undo and redo stacks
       (clears them).

   6.  ''pathName edit separator'' - inserts a separator on
       the undo stack, indicating an undo boundary.  If a separator is
       already present, this will do nothing.  This means that it is
       safe to issue the command several times, without any inserts or
       deletes occurring in between.

   7.  ''pathName edit modified ?boolean?'' - If boolean is not 
       specified returns the modified state of the widget 
       (either 1 or zero).
       If boolean is specified, sets the modified state of the widget 
       to that value.

   8.  ''<<Modified>>'' - this virtual event is generated whenever the
       modified state of the widget changes from modified to not
       modified or vice versa.

   9.  ''<<Selection>>'' - this virtual event is generated whenever
       the range tagged with the selection tag changes.

  10. ''<<Undo>>'' - this virtual event calls pathName edit undo.

  11. ''<<Redo>>'' - this virtual event calls pathName edit redo.

  12.  ''<Control-z>'' - is bound to the <<Undo>> virtual event.

  13.  ''<Control-Z>'' - is bound to the <<Redo>> virtual event on all
       platforms except Win32.

  14.  ''<Control-y>'' - is bound to the <<Redo>> virtual event on Win32.

~ Example

  The following code illustrates how the new features are intended to
  be used.

|   global fileName
|   global modState
|   global undoVar
|   
|   set fileName "None"
|   set modState ""
|   set undoVar  0
|   
|   
|   text .t -background white -wrap none
|   # Example 1: The Modified event will update a text label
|   bind .t <<Modified>>  updateState
|   # Example 2: The Selection event will create a tag that
|   #            duplicates the selection
|   bind .t <<Selection>> duplicateSelection
|   
|   frame .l
|   label .l.l -text "File: "
|   label .l.f -textvariable fileName
|   label .l.m -textvariable modState
|   
|   grid .l.l -sticky w   -column 0 -row 0
|   grid .l.f -sticky w   -column 1 -row 0
|   grid .l.m -sticky e   -column 2 -row 0
|   
|   grid columnconfigure .l 1 -weight 1
|   
|   frame .b
|   button .b.l -text "Load"   -width 8 -command loadFile
|   button .b.s -text "Save"   -width 8 -command saveFile
|   button .b.i -text "Indent" -width 8 -command blockIndent
|   
|   checkbutton .b.e -text "Enable Undo" -onvalue 1 -offvalue 0 -|   |   variable undoVar
|   trace variable undoVar w setUndo
|   button .b.u -text "Undo"     -width 8 -command "undo"
|   button .b.r -text "Redo"     -width 8 -command "redo"
|   button .b.m -text "Modified" -width 8 -command ".t edit modified on"
|   
|   grid .b.l -row 0 -column 0
|   grid .b.s -row 0 -column 1
|   grid .b.i -row 0 -column 2
|   grid .b.e -row 0 -column 3
|   grid .b.u -row 0 -column 4
|   grid .b.r -row 0 -column 5
|   grid .b.m -row 0 -column 6
|   
|   grid columnconfigure .b 0 -weight 1
|   grid columnconfigure .b 1 -weight 1
|   grid columnconfigure .b 2 -weight 1
|   grid columnconfigure .b 3 -weight 1
|   grid columnconfigure .b 4 -weight 1
|   grid columnconfigure .b 5 -weight 1
|   
|   
|   grid .l -sticky ew   -column 0 -row 0
|   grid .t -sticky news -column 0 -row 1
|   grid .b -sticky ew   -column 0 -row 2
|   
|   grid rowconfigure    . 1 -weight 1
|   grid columnconfigure . 0 -weight 1
|   
|   
|   
|   proc updateState {args} {
|      global modState
|      
|      # Check the modified state and update the label
|      if { [.t edit modified] } {
|         set modState "Modified"
|      } else {
|         set modState ""
|      }
|   }


|   
|   
|   proc setUndo {args} {
|      global undoVar
|      
|      # Turn undo on or off
|      if { $undoVar } {
|         .t configure -undo 1
|      } else {
|         .t configure -undo 0
|      }
|   }


|   
|   proc undo {} {
|      # edit undo throws an exception when there is nothing to
|      # undo. So catch it.
|      if { [catch {.t edit undo}] } {
|         bell
|      }
|   }
|   



|   proc redo {} {
|      # edit redo throws an exception when there is nothing to
|      # undo. So catch it.
|      if { [catch {.t edit redo}] } {
|         bell
|      }
|   }


|   
|   proc loadFile {} {
|      
|      set file [tk_getOpenFile]
|      if { ![string equal $file ""] } {
|         set fileName $file
|         set f [open $file r]
|         set content [read $f]
|         set oldUndo [.t cget -undo]
|         
|         # Turn off undo. We do not want to be able to undo
|         # the loading of a file
|         .t configure -undo 0
|         .t delete 1.0 end
|         .t insert end $content
|         # Reset the modified state
|         .t edit modified 0
|         # Clear the undo stack
|         .t edit reset
|         # Set undo to the old state
|         .t configure -undo $oldUndo
|      }
|   }


|   
|   proc saveFile {} {
|      # The saving bit is not actually done
|      # So the contents in the file are not updated
|   
|      # Saving clears the modified state
|      .t edit modified 0
|      # Make sure there is a separator on the undo stack
|      # So we can get back to this point with the undo
|      .t edit separator
|   }

|   
|   proc blockIndent {} {
|      set indent "   "
|      
|      # Block indent should be treated as one operation from
|      # the undo point of view
|      
|      # if there is a selection
|      if { ![catch {.t index sel.first} ] } {
|         scan [.t index sel.first] "%d.%d" startline startchar
|         scan [.t index sel.last]  "%d.%d" stopline  stopchar
|         if { $stopchar == 0 } {
|            incr stopline -1
|         }

|         
|         # Get the original autoseparators state
|         set oldSep [.t cget -autoseparators]
|         # Turn of automatic insertion of separators
|         .t configure -autoseparators 0
|         # insert a separator before the edit operation
|         .t edit separator
|         for {set i $startline} { $i <= $stopline} {incr i} {
|            .t insert "$i.0" $indent
|         }

|         .t tag add sel $startline.0 "$stopline.end + 1 char"
|         # insert a separator after the edit operation
|         .t edit separator
|         # put the autoseparators back in their original state
|         .t configure -autoseparators $oldSep
|      }
|   }


|   
|   proc duplicateSelection {args} {
|      .t tag configure dupsel -background tomato
|      .t tag remove dupsel 1.0 end
|      
|      if { ![catch {.t index sel.first} ] } {
|         eval .t tag add dupsel [.t tag ranges sel]
|      }
|   }


|   

~ Reference Implementation

http://www.cs.man.ac.uk/fellowsd-bin/TIP/26.patch

''The patch has received little testing so far, so any testing is
encouraged.''

~ Copyright

This document has been placed in the public domain.








|





|


|




|

|
|






|
|




|
|

|





|

|



|



|


|

|

|

|


|

|




|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
<
<
<
>
>
>
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
<
<
>
>
|

|

|

|
|

|


>
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241


242
243
244
245
246
247
248
249
250
251
252
253


254
255
256
257
258
259
260
261



262
263
264
265
266
267
268
269


270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292


293
294
295
296
297
298
299
300
301
302
303
304

305
306
307
308
309
310
311
312
313
314
315
316
317
318

319
320
321
322
323
324
325
326
327
328

329
330
331
332
333
334


335
336
337
338
339
340
341
342
343


344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
Currently only text inserts and deletes can be undone. All other changes
to the widget, such as the adding or deleting of tags, cannot be undone.

The modified state of the widget is implemented using a counter.
Every insert or delete action, and every time such an action is redone,
increments this counter. Every undone insert or delete decrements this 
counter.  The widget is considered to be modified if the counter is not
zero.  A virtual event _<<Modified>>_ is generated whenever this 
counter changes from zero to non-zero or vice versa.  A mechanism is 
provided to reset the counter to zero. The modified state can also be 
explicitely set by the user. In that case, the counter mechanism is not 
operational until the modified state has been reset again.

   1.  _pathName configure -undo 0\|1_ - this enables or disables the
       undo/redo mechanism.  The default is zero.

   2.  _pathName configure -autoseparators 0\|1_ - when one inserts
       a separator automatically whenever insert changes to delete or
       vice versa. Separators are also inserted when the keyboard or
       the mouse is used to move the insert mark, or when the <Return>
       key is pressed. When off, no separators are inserted, except by
       the user \(See 6\).  The default is one.

   3.  _pathName edit undo_ - undoes the last edit action if undo is
       enabled \(See 1\). The insert mark will be positioned at the last
       undone edit action. When undo deletes text, that is the index
       where the text was. When undo inserts text, the insert mark
       will be positioned at the end of the inserted text. The view will
       be adapted to make the insert mark visible. Raises an exception 
       if there is nothing to undo. Does nothing if undo is disabled.

   4.  _pathName edit redo_ - redoes the last edit action if undo is
       enabled \(See 1\). The insert mark and widget view will be updated
       similar to what is done for the edit undo command. Raises an 
       exception if there is nothing to redo.  Does nothing if undo is 
       disabled.

   5.  _pathName edit reset_ - resets the undo and redo stacks
       \(clears them\).

   6.  _pathName edit separator_ - inserts a separator on
       the undo stack, indicating an undo boundary.  If a separator is
       already present, this will do nothing.  This means that it is
       safe to issue the command several times, without any inserts or
       deletes occurring in between.

   7.  _pathName edit modified ?boolean?_ - If boolean is not 
       specified returns the modified state of the widget 
       \(either 1 or zero\).
       If boolean is specified, sets the modified state of the widget 
       to that value.

   8.  _<<Modified>>_ - this virtual event is generated whenever the
       modified state of the widget changes from modified to not
       modified or vice versa.

   9.  _<<Selection>>_ - this virtual event is generated whenever
       the range tagged with the selection tag changes.

  10. _<<Undo>>_ - this virtual event calls pathName edit undo.

  11. _<<Redo>>_ - this virtual event calls pathName edit redo.

  12.  _<Control-z>_ - is bound to the <<Undo>> virtual event.

  13.  _<Control-Z>_ - is bound to the <<Redo>> virtual event on all
       platforms except Win32.

  14.  _<Control-y>_ - is bound to the <<Redo>> virtual event on Win32.

# Example

  The following code illustrates how the new features are intended to
  be used.

	   global fileName
	   global modState
	   global undoVar
	   
	   set fileName "None"
	   set modState ""
	   set undoVar  0
	   
	   
	   text .t -background white -wrap none
	   # Example 1: The Modified event will update a text label
	   bind .t <<Modified>>  updateState
	   # Example 2: The Selection event will create a tag that
	   #            duplicates the selection
	   bind .t <<Selection>> duplicateSelection
	   
	   frame .l
	   label .l.l -text "File: "
	   label .l.f -textvariable fileName
	   label .l.m -textvariable modState
	   
	   grid .l.l -sticky w   -column 0 -row 0
	   grid .l.f -sticky w   -column 1 -row 0
	   grid .l.m -sticky e   -column 2 -row 0
	   
	   grid columnconfigure .l 1 -weight 1
	   
	   frame .b
	   button .b.l -text "Load"   -width 8 -command loadFile
	   button .b.s -text "Save"   -width 8 -command saveFile
	   button .b.i -text "Indent" -width 8 -command blockIndent
	   
	   checkbutton .b.e -text "Enable Undo" -onvalue 1 -offvalue 0 -|   |   variable undoVar
	   trace variable undoVar w setUndo
	   button .b.u -text "Undo"     -width 8 -command "undo"
	   button .b.r -text "Redo"     -width 8 -command "redo"
	   button .b.m -text "Modified" -width 8 -command ".t edit modified on"
	   
	   grid .b.l -row 0 -column 0
	   grid .b.s -row 0 -column 1
	   grid .b.i -row 0 -column 2
	   grid .b.e -row 0 -column 3
	   grid .b.u -row 0 -column 4
	   grid .b.r -row 0 -column 5
	   grid .b.m -row 0 -column 6
	   
	   grid columnconfigure .b 0 -weight 1
	   grid columnconfigure .b 1 -weight 1
	   grid columnconfigure .b 2 -weight 1
	   grid columnconfigure .b 3 -weight 1
	   grid columnconfigure .b 4 -weight 1
	   grid columnconfigure .b 5 -weight 1
	   
	   
	   grid .l -sticky ew   -column 0 -row 0
	   grid .t -sticky news -column 0 -row 1
	   grid .b -sticky ew   -column 0 -row 2
	   
	   grid rowconfigure    . 1 -weight 1
	   grid columnconfigure . 0 -weight 1
	   
	   
	   
	   proc updateState {args} {
	      global modState
	      
	      # Check the modified state and update the label
	      if { [.t edit modified] } {
	         set modState "Modified"
	      } else {
	         set modState ""


	      }
	   }
	   
	   
	   proc setUndo {args} {
	      global undoVar
	      
	      # Turn undo on or off
	      if { $undoVar } {
	         .t configure -undo 1
	      } else {
	         .t configure -undo 0


	      }
	   }
	   
	   proc undo {} {
	      # edit undo throws an exception when there is nothing to
	      # undo. So catch it.
	      if { [catch {.t edit undo}] } {
	         bell



	      }
	   }
	   
	   proc redo {} {
	      # edit redo throws an exception when there is nothing to
	      # undo. So catch it.
	      if { [catch {.t edit redo}] } {
	         bell


	      }
	   }
	   
	   proc loadFile {} {
	      
	      set file [tk_getOpenFile]
	      if { ![string equal $file ""] } {
	         set fileName $file
	         set f [open $file r]
	         set content [read $f]
	         set oldUndo [.t cget -undo]
	         
	         # Turn off undo. We do not want to be able to undo
	         # the loading of a file
	         .t configure -undo 0
	         .t delete 1.0 end
	         .t insert end $content
	         # Reset the modified state
	         .t edit modified 0
	         # Clear the undo stack
	         .t edit reset
	         # Set undo to the old state
	         .t configure -undo $oldUndo


	      }
	   }
	   
	   proc saveFile {} {
	      # The saving bit is not actually done
	      # So the contents in the file are not updated
	   
	      # Saving clears the modified state
	      .t edit modified 0
	      # Make sure there is a separator on the undo stack
	      # So we can get back to this point with the undo
	      .t edit separator

	   }
	   
	   proc blockIndent {} {
	      set indent "   "
	      
	      # Block indent should be treated as one operation from
	      # the undo point of view
	      
	      # if there is a selection
	      if { ![catch {.t index sel.first} ] } {
	         scan [.t index sel.first] "%d.%d" startline startchar
	         scan [.t index sel.last]  "%d.%d" stopline  stopchar
	         if { $stopchar == 0 } {
	            incr stopline -1

	         }
	         
	         # Get the original autoseparators state
	         set oldSep [.t cget -autoseparators]
	         # Turn of automatic insertion of separators
	         .t configure -autoseparators 0
	         # insert a separator before the edit operation
	         .t edit separator
	         for {set i $startline} { $i <= $stopline} {incr i} {
	            .t insert "$i.0" $indent

	         }
	         .t tag add sel $startline.0 "$stopline.end + 1 char"
	         # insert a separator after the edit operation
	         .t edit separator
	         # put the autoseparators back in their original state
	         .t configure -autoseparators $oldSep


	      }
	   }
	   
	   proc duplicateSelection {args} {
	      .t tag configure dupsel -background tomato
	      .t tag remove dupsel 1.0 end
	      
	      if { ![catch {.t index sel.first} ] } {
	         eval .t tag add dupsel [.t tag ranges sel]


	      }
	   }
	   

# Reference Implementation

<http://www.cs.man.ac.uk/fellowsd-bin/TIP/26.patch>

_The patch has received little testing so far, so any testing is
encouraged._

# Copyright

This document has been placed in the public domain.

Name change from tip/260.tip to tip/260.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

TIP:		260
Title:		Add Underline Option to Canvas Text Items
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Post-History:	
Version:	$Revision: 1.4 $
Author:		Donal K. Fellows <[email protected]>
Created:	04-Jan-2006


~ Abstract

This TIP proposes adding an '''-underline''' option to the Tk
'''canvas''' widget's text items.

~ Rationale

If you're simulating a '''label''' (or '''button''' or ...) widget
using a '''canvas''', it is useful to be able to underline a single
character of a piece of text. Although this can be done in various
ways using '''font measure''' to work out where to start drawing, it
would be far easier if we could use Tk's own built-in underlining
engine (which also gets other font-related issues correct too, and
correcting for them is more difficult than it ought to be given that
Tk already knows what to do anyway).

~ Proposed Change

The '''canvas''' widget's text items shall gain an additional option,
'''-underline''' which shall take an integer value (-1 being the
default "no underline" value) describing which character position in
the text to underline, just as with the '''-underline''' option
provided by the '''label''' widget (and elsewhere). As with all canvas
items, no specific support for modification through the option
database shall be provided, but otherwise the option shall be exactly
as described in the '''options''' manual page.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
>

|

|
|

|

|
|

|

|

|

|

|
|
|
|
|


|

|


>

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

# TIP 260: Add Underline Option to Canvas Text Items
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	04-Jan-2006
-----

# Abstract

This TIP proposes adding an **-underline** option to the Tk
**canvas** widget's text items.

# Rationale

If you're simulating a **label** \(or **button** or ...\) widget
using a **canvas**, it is useful to be able to underline a single
character of a piece of text. Although this can be done in various
ways using **font measure** to work out where to start drawing, it
would be far easier if we could use Tk's own built-in underlining
engine \(which also gets other font-related issues correct too, and
correcting for them is more difficult than it ought to be given that
Tk already knows what to do anyway\).

# Proposed Change

The **canvas** widget's text items shall gain an additional option,
**-underline** which shall take an integer value \(-1 being the
default "no underline" value\) describing which character position in
the text to underline, just as with the **-underline** option
provided by the **label** widget \(and elsewhere\). As with all canvas
items, no specific support for modification through the option
database shall be provided, but otherwise the option shall be exactly
as described in the **options** manual page.

# Copyright

This document has been placed in the public domain.

Name change from tip/261.tip to tip/261.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

TIP:            261
Title:          Return Imported Commands from [namespace import]
Version:        $Revision: 1.7 $
Author:         Martin Lemburg <[email protected]>
Author:         <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        20-Dec-2005
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP describes a mechanism for easily finding out the list of
commands in the current namespace that have been imported from other
namespaces.

~ Rationale

While writing a profiling and introspection module for our C++/Tcl
application, I searched for ways to query all the exported and
imported commands of a namespace.

Although I found the introspection functionality for discovering all
exported commands of a namespace using '''namespace export''' in the
exporting namespace, I found no way to query all imported commands
inside the importing namespace.

The documentation of '''namespace import''' said nothing about the
behaviour, if no arguments were given, and testing '''namespace
import''' without arguments resulted in nothing, in a no-op.

Prompted by this, I started a thread in news:comp.lang.tcl which goes
into more detail
[http://groups.google.com/group/comp.lang.tcl/browse_frm/thread/9fb246cf65aba54f?tvc=1].

What seems to be more logical to me would be to change the no-op
behaviour of '''namespace import''' to be comparable to '''namespace
export''', and return all imported commands inside the namespace
'''namespace import''' is executed in.

As an example...

 * to get all exported commands of a namespace ::exportingNspc:

| namespace inscope ::exportingNspc {namespace export}

 * to get all imported commands of the namespace ::importingNspc:

| namespace inscope ::importingNspc {namespace import}

~ Consequences

The only consequence I know is, that old scripts using the no-op
'''namespace import''' suddenly will return a list, probably filled
with names of imported commands. That's all.

Because of the fact, that '''namespace import''' never returned
values, no script should really break, thus no script should require
values from this command.

~ Proposed Change

The result of '''namespace import''' without arguments shall be a list
of all commands that have been imported into the current namespace.
Each command in the list will be the simple name by which the command
is known in the current namespace.  This format for the
returned value is most useful because it composes well
with '''namespace forget'''.  To remove all imported
commands from a namespace, use the command

| namespace forget {*}[namespace import]

~ Implementation

A patch implementing an earlier draft is available,
[http://sf.net/tracker/?func=detail&aid=1437008&group_id=10894&atid=310894],
and updated patches will be attached to the same Tracker report.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|

|




|



|
|
|



|


|
|
|





|



|

|


|


|



|

|




|


|

|


|


|


>

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

# TIP 261: Return Imported Commands from [namespace import]

	Author:         Martin Lemburg <[email protected]>
	Author:         <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        20-Dec-2005
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP describes a mechanism for easily finding out the list of
commands in the current namespace that have been imported from other
namespaces.

# Rationale

While writing a profiling and introspection module for our C\+\+/Tcl
application, I searched for ways to query all the exported and
imported commands of a namespace.

Although I found the introspection functionality for discovering all
exported commands of a namespace using **namespace export** in the
exporting namespace, I found no way to query all imported commands
inside the importing namespace.

The documentation of **namespace import** said nothing about the
behaviour, if no arguments were given, and testing **namespace
import** without arguments resulted in nothing, in a no-op.

Prompted by this, I started a thread in news:comp.lang.tcl which goes
into more detail
<http://groups.google.com/group/comp.lang.tcl/browse_frm/thread/9fb246cf65aba54f?tvc=1> .

What seems to be more logical to me would be to change the no-op
behaviour of **namespace import** to be comparable to **namespace
export**, and return all imported commands inside the namespace
**namespace import** is executed in.

As an example...

 * to get all exported commands of a namespace ::exportingNspc:

		 namespace inscope ::exportingNspc {namespace export}

 * to get all imported commands of the namespace ::importingNspc:

		 namespace inscope ::importingNspc {namespace import}

# Consequences

The only consequence I know is, that old scripts using the no-op
**namespace import** suddenly will return a list, probably filled
with names of imported commands. That's all.

Because of the fact, that **namespace import** never returned
values, no script should really break, thus no script should require
values from this command.

# Proposed Change

The result of **namespace import** without arguments shall be a list
of all commands that have been imported into the current namespace.
Each command in the list will be the simple name by which the command
is known in the current namespace.  This format for the
returned value is most useful because it composes well
with **namespace forget**.  To remove all imported
commands from a namespace, use the command

	 namespace forget {*}[namespace import]

# Implementation

A patch implementing an earlier draft is available,
<http://sf.net/tracker/?func=detail&aid=1437008&group_id=10894&atid=310894> ,
and updated patches will be attached to the same Tracker report.

# Copyright

This document has been placed in the public domain.

Name change from tip/262.tip to tip/262.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

TIP:            262
Title:          Background Images for Frames
Version:        $Revision: 1.5 $
Author:         Eric Taylor <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        18-Mar-2006
Post-History:   
Keywords:       Tk,option
Tcl-Version:    8.7


~ Abstract

This TIP proposes an option for frames that allows users to set the
background of the window to be an image.

~ Rationale

Just a there is an '''-image''' option for '''button''' widgets, this
TIP suggests that a '''-backgroundimage''' option for frames be
implemented. The image should be either an entire single image, or a
smaller image that would be tiled, with a '''-tile''' option. Tiling
would repeat, as needed, a smaller image to fit the visible area of
the frame.

If the image was tiled, then it should be re-tiled as needed during a
resize. The image would reside behind any other decoration or other
widgets that resided in the frame. The image should be re-configurable
to replace the image and/or remove it, as with a button image.

This TIP should allow some rather classy looking tcl/tk programs to be
created with much ease.

~ Proposed Change

Two new options are proposed for '''frame''' widgets, to be
manipulated using the normal '''configure''' and '''cget''' methods:

 * '''-backgroundimage''' ''imageName'' - This gives the name of an
   image (as created by '''image create''') that is to be painted onto
   the widget immediately after the painting of the solid background
   colour. If ''imageName'' is the empty string (the default) no image
   will be painted. The painting of the image will be controlled by
   the '''-tile''' option.

 * '''-tile''' ''boolean'' - If this option gives ''boolean'' as true,
   the image will be painted such that the top-left corner corresponds
   to the top-left corner of the frame, and then subsequently
   repeatedly painted (with no gaps between the areas painted) to the
   right and below that initial painting until such time as the entire
   widget is covered by copies of the image. If this option gives
   ''boolean'' as false, the image will only be painted once, such
   that the center of the image painted is coincident with the center
   of the frame widget.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|




|

|
|

|











|

|
|

|
|

|

|

|


|


|



|


>

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

# TIP 262: Background Images for Frames

	Author:         Eric Taylor <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        18-Mar-2006
	Post-History:   
	Keywords:       Tk,option
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes an option for frames that allows users to set the
background of the window to be an image.

# Rationale

Just a there is an **-image** option for **button** widgets, this
TIP suggests that a **-backgroundimage** option for frames be
implemented. The image should be either an entire single image, or a
smaller image that would be tiled, with a **-tile** option. Tiling
would repeat, as needed, a smaller image to fit the visible area of
the frame.

If the image was tiled, then it should be re-tiled as needed during a
resize. The image would reside behind any other decoration or other
widgets that resided in the frame. The image should be re-configurable
to replace the image and/or remove it, as with a button image.

This TIP should allow some rather classy looking tcl/tk programs to be
created with much ease.

# Proposed Change

Two new options are proposed for **frame** widgets, to be
manipulated using the normal **configure** and **cget** methods:

 * **-backgroundimage** _imageName_ - This gives the name of an
   image \(as created by **image create**\) that is to be painted onto
   the widget immediately after the painting of the solid background
   colour. If _imageName_ is the empty string \(the default\) no image
   will be painted. The painting of the image will be controlled by
   the **-tile** option.

 * **-tile** _boolean_ - If this option gives _boolean_ as true,
   the image will be painted such that the top-left corner corresponds
   to the top-left corner of the frame, and then subsequently
   repeatedly painted \(with no gaps between the areas painted\) to the
   right and below that initial painting until such time as the entire
   widget is covered by copies of the image. If this option gives
   _boolean_ as false, the image will only be painted once, such
   that the center of the image painted is coincident with the center
   of the frame widget.

# Copyright

This document has been placed in the public domain.

Name change from tip/263.tip to tip/263.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

187
188
189
190
191
192
193
194
195
196
197
198
199
200

201
202
203
204
205
206
207
208
209
210
211

212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346

347
348
349
350
351
352
353
354
355
356
357
358
359
360

361
362
363
364
365

366
367
368
369
370
371
372
373
374
375
376
377
378

379
380
381
382
383
384
385
386
387

388
389
390
391
392
393
394
395
396
397

398
399
400
401
402
403
404
405
406

407
408
409
410
411

412
413
414
415
416

417
418
419
420
421
422
423
424
425
426

427
428
429
430
431
432
433

TIP:		263
Title:		Quantum Tcl
Version:	$Revision: 1.2 $
Author:		Lars Hellstr�m <[email protected]>
State:		Draft
Type:		Project
Vote:		Pending
Tcl-Version:	9.2
Created:	01-Apr-2006
Post-History:	


~ Abstract

A new Tcl command '''qubit''' is proposed. This command makes it possible to
handle quantum information in the form of qubits.

~ Rationale

As stated in [131], what Tcl needs in order to succeed in the marketplace is a
feature that no other programming language provides, a "killer app" as it
were. The Tk toolkit, Expect, cross-platform portability, starkits, tkcon, and
excellent embed/extend-ability with respect to other languages are all well
and good, but they have clearly failed to push Tcl usage to the point of
having critical mass.  The '''qubit''' command makes it possible to achieve an
exponential speedup for important problems and should therefore provide a
powerful enough incentive that even Perl programmers would be compelled to
switch languages.

~ Background

Quantum computing makes use of phenomena in quantum mechanics to, at each time
step, carry out an exponential amount of work using only a linear amount of
hardware. The way this maps onto physical reality is pretty mind-boggling, but
for the programmer it is sufficient to think of the Quantum Processing Unit
(QPU) as an extremely powerful but somewhat specialised coprocessor and leave
it at that. (Chances are anyway that the QPU isn't physically located in your
desktop computer, as they tend to involve lots of lasers, magnets, vacuum
chambers, liquid nitrogen cooling, etc.)

Quantum information display an interesting duality in that it is analog during
a computation, but becomes digital as soon as one measures it. (Wave/particle
duality, in case anyone came to think of that, is the kind of "mapping onto
physical reality" issue that will not be treated here.) This makes the design
of quantum algorithms somewhat different from the design of classical
algorithms, in a manner similar to that in which the design of analog
electronic circuits is different from the design of digital electronic
circuits, as one must often work out the numbers rather than rely on a
discrete case-by-case analysis. Another curious feature is that all fully
quantum operations must be reversible, which in particular has the effect that
quantum information can neither be duplicated nor (in the absence of
measurements) destroyed, only rearranged. There is in particular no quantum
analogue to assignments such as [[set a $b]], since not only need this copy
the value of b, it also irrecoverably destroys the old value of a; the closest
one gets to such an assignment is exchanging the values of a and b.

For more information on quantum computing in general, see e.g.:

   * Wikipedia article "Quantum computer"
     [http://en.wikipedia.org/wiki/Quantum_computer].

   * J. Gruska: Quantum Computing (1999), ISBN 0-07-709503-0,
     [http://www.fi.muni.cz/usr/gruska/quantum/].

~ Specification

The quantum computing model supported by the '''qubit''' command is that of
''quantum bits'' (more commonly called ''qubits'') and ''quantum boolean
circuits''. While other more fancy models such as "Quantum Turing Machines"
exist, this is generally considered to be the most realistic model, and it is
also the one most closely related to the number-of-gates complexity measure
for classical computing. Should it in the future prove desirable to support
also some other model, then one may do so through a separate command.

In this model, a quantum state of N qubits is completely specified by a set of
2**N complex numbers, usually known as ''probability amplitudes'' (they are
not probabilities as such, but they do completely determine the probabilities
for various events). Many different bases are possible, but in the standard
(also known as the computational) basis each of these amplitudes corresponds
to a particular assignment of 0s and 1s to the qubits. Operations on a quantum
state can be understood as operations on the vector of amplitudes.

The '''qubit''' command has the five subcommands.

~~ The 'new' Subcommand

 > '''qubit new''' ?''-option value'' ?...??

Allocate/create a new qubit, and return a handle for the new qubit that
identifies it in subsequent operations, or throw an error if
allocation/creation failed (possible causes include, but are not limited to,
lack of resources on the hardware side and user having insufficient
permissions). New qubits are not entangled with any of the old ones, but their
state is otherwise unspecified.

The options are meant as a means for supplying extra information about the new
qubit, such as for example whether it is being protected from decoherence by a
scheme of quantum error correction codes (the Tcl core can easily implement
such features on platforms where the C level APIs only provide raw qubits);
however at present no options are defined.

~~ The 'operate' Subcommand

 > '''qubit operate''' ''gate id0'' ?''id1'' ?...??

Perform a quantum operation (the ''gate'') on one or more qubits (specified
using the handles ''id0'', ''id1'', etc.). Returns the operation actually
applied.

In the interest of generality, gates are specified as unitary matrices (this
is a universal representation for quantum gates), or more concretely as lists
of lists of lists of doubles. The innermost lists must have length 2 and
encode the real (index 0) and imaginary (index 1) parts of an element of the
matrix. Indices in the middle list level select a column and indices in the
outer list level consequently a row. Put another way,

| lindex $gate $i $j 0 ; # Returns Re gate(i,j)
| lindex $gate $i $j 1 ; # Returns Im gate(i,j)

The row/column index corresponding to the ''id0'' qubit having value $r0, the
''id1'' qubit having value $r1, etc. is $r0*(2**0) + $r1*(2**1) + ... A
''gate'' for operating on ''n'' qubits must thus have side 2**''n''. Columns
correspond to qubit states before the operation and rows correspond to qubit
states after the operation.

An error is thrown if the number of qubit arguments does not match the side of
the ''gate'' matrix, if not all ''idN'' arguments are qubit handles, if some
qubit occurs twice in the list, and if ''gate'' is not a proper matrix (too
many or too few elements in some list, elements not recognised as doubles,
etc.).

An error is ''not'' thrown if the ''gate'' is not unitary. In general the
operation actually applied has to be supported by the available hardware, so
the '''qubit operate''' command (or some lower level interface) should
determine which supported operation most closely approximates the specified
''gate'' and apply that instead. The user can check what was done (up to
numeric precision) by inspecting the return value. Using a return value from
'''qubit operate''' as the ''gate'' for another call should result in the
exact same operation being carried out.

~~ The 'measure' Subcommand

 > '''qubit measure''' ''id''

Measures a qubit with respect to the standard basis. Returns 0 or 1 depending
on the resulting state.

''Note'' that measuring a qubit changes the quantum state to one in which that
qubit has a pure value. If other qubits are initially entangled with the one
being measured, then these will also be affected by this operation. Measuring
a qubit causes it to be disentangled from all other qubits (or perhaps
entangles the state of the entire universe with the qubit, depending on your
philosophical point of view).

~~ The 'dispose' Subcommand

 > '''qubit dispose''' ''id''

Frees/deallocates a qubit, returning it to whatever pool of resources '''qubit
new''' got it from, but before doing that the qubit is measured to safely
disentangle it from any remaining qubits. The return value is 0 or 1 as for
the corresponding '''qubit measure'''.

~~ The 'names' Subcommand

 > '''qubit names'''

This is an instrospection command. It returns a list of all qubit handles
currently available in this interpreter.

~~ Future Expansion

Other subcommands may be added in the future, but this set is complete for
single interpreter algorithms.

~ Examples

The syntax of '''qubit operate''' was chosen to facilitate the creation of
aliases for common gates, as this should make programs more readable. An alias
for the CNOT (conditional not) gate can be created as

| interp alias {} CNOT {} qubit operate {
|    { {1 0} {0 0} {0 0} {0 0} }
|    { {0 0} {0 0} {0 0} {1 0} }
|    { {0 0} {0 0} {1 0} {0 0} }
|    { {0 0} {1 0} {0 0} {0 0} }
| }


after which one can use the command

| CNOT $control $target

The more significant $target qubit is negated if the $control qubit is 1 but
left alone otherwise.

Another standard gate is the Hadamard gate, which can be defined as follows.

| set rsqrt2 [list [expr {1/sqrt(2)}] 0] ; # Reciprocal square root of  2.
| interp alias {} Hadamard {} qubit operate [
|   list [list $rsqrt2 $rsqrt2] [list $rsqrt2 [list [expr -sqrt(0.5)]  0]]
| ]


The Hadamard gate is used to create states that are uniform superpositions of
0s and 1s. A simple application of that is the following random bit generator.

| proc randombit {} {
|     set id [qubit new]        ; # Allocate qubit
|     qubit measure $id         ; # Make pure 0 or pure 1
|     Hadamard $id              ; # Make an equal mix of 0 and 1
|     return [qubit dispose $id]; # Measure and clean up
| }


Note that this (provided, of course, that one believes in the standard
interpretation of quantum mechanics) is not a psuedo-random bit generator, but
a truly random bit generator. Even if the Hadamard gate would be slightly off
(unlikely, as this is a very standard gate, but possible) this would not
affect the essential randomness of the bits produced, but only the exact
probability.

A third type of elementary gate is the phase shift gate, which changes the
phase (but not the size) of some probability amplitude. To change the phase of
the 1 amplitude of a qubit $id by the angle $phi, one would use the command

| qubit operate [list {{1.0 0.0} {0.0 0.0}} [list {0.0 0.0} [
|     list [expr {cos($phi)}] [expr {sin($phi)}]
| ]]] $id

Phase changes do not change the probability distribution for any qubit
measurement, but they do affect the state in ways that can lead to different
probabilities further on, and thus illustrate the fact that there is more to a
quantum state than the probability distribution it gives rise to here and
now. As a concrete example of this, assuming $id is a qubit, and with aliases
as above, the script:

| set before [qubit measure $id]
| Hadamard $id
| Hadamard $id
| set after [qubit measure $id]
| expr {$before == $after}

will with probability 1 produce the result 1, whereas the script:

| set before [qubit measure $id]
| Hadamard $id
| qubit operate {{{1 0} {0 0}} {{0 0} {-1 0}}} $id
| Hadamard $id
| set after [qubit measure $id]
| expr {$before == $after}

will with probability 1 produce the result 0. The only difference is the 180
degrees phase shift of the 1 amplitude in the explicit '''qubit operate'''
command, which transforms one state with equal probabilities for 0 and 1 to
another state with equal probabilities for 0 and 1!

~ Rejected Alternatives

One might expect that a truly Quantum Tcl would keep quantum information as
"first class data", i.e., in Tcl_Objs to be passed around by value rather than
as qubits that can only be passed around by name, but that is impossible
(unless one goes to such lengths as to run the entire Tcl process in a QPU,
which again will probably never be possible) due to a fundamental
incompatibility between the laws of quantum mechanics and Tcl's Everything Is
A String principle.

Beginning with the EIAS side, one may observe that for a quantum state to be
encodable into a Tcl_Obj, it must be serializable - there must be a way of
generating a string that completely encodes the state. Since quantum mechanics
does not permit extracting that much information about a quantum state, there
are only two options: either everything is kept within the QPU (not
realistic), or nothing is kept in the QPU. In the latter case, one loses
entirely the advantage of quantum computation, so it is rather pointless.

On the quantum side, one may observe that most of the things that are
routinely done to Tcl_Objs are simply impossible to do to quantum information.
The fundamental problem here is that Tcl_Objs must be duplicatable, whereas it
is a theorem in quantum mechanics that quantum states cannot be duplicated
(the "No cloning" theorem). Somewhat related is the problem that quantum
information can only be read (used as input to some operation) once, whereas a
Tcl_Obj can be written once but read an unlimited number of times.

~ Security Implications

As the '''qubit''' command only manipulates data and cannot be used for any
form of communication, it may in principle be made available also in safe
interpreters. However since '''qubit new''' seizes a global resource that can
be expected to be in limited supply on a system, it is probably better to be
safe than sorry, and therefore the '''qubit''' command shall initially be
hidden in a safe interpreter.

Omitting the command entirely and instead alias all qubit operations to the
'''qubit''' command of the parent interpreter is ''not'' a good idea, as the
quick (but sloppy) implementation of this would allow untrusted code evaluated
in the safe interpreter access also to the qubits of the parent.

It should be noted that the easy access to quantum computing that this command
provides would have significant implications for the security of many external
systems. Such issues are outside the scope of this TIP.

~ Future Extensions

Besides quantum algorithms, many interesting applications of quantum
information processing involves communication through the means of a quantum
state shared by different parties. While fast long distance qubit
transportation is physically made possible by means of quantum teleportation
(which really isn't as fancy as it sounds - basically it amounts to a
combination of the old TV chef trick of having prepared something in advance,
in this case physically transferring a qubit, and the patchfile trick of only
transmitting a diff against what was physically distributed), there are
currently no standardised protocols for this, and until the time that there is
there probably isn't much point in specifying some '''qubit socket''' command
for Tcl either. It may however be observed that ''non-open'' commercial
systems [http://www.magiqtech.com/] transmitting quantum information over long
distances are available today.

While transferring qubits between different machines obviously present some
technical problems, it may seem that transferring qubits between different
interpreters in the same process should at least be straightforward, but the
presence of multiple threads in the process introduce complications also for
this case. Concretely, transferring a qubit from one thread to another will in
general cause these threads to become entangled! In order to not make thread
maintenance even more complicated by introducing the concept of quantum
deadlock due to thread tangles, this TIP does not treat the subject of a
mechanism for transferring qubits between interpreters.

~ Reference Implementation

A Tcl level emulation of the '''qubit''' command (minus some error checking,
but also not requiring a QPU) is available as SF patch no 1462755
[http://sf.net/tracker/?func=detail&aid=1462755&group_id=10894&atid=310894].
This emulation uses the standard Tcl rand() function for generating random
numbers, so it is not cryptographically safe. Also note that it internally
uses of some tcllib packages, which must therefore be available.

No C implementation exists at present, but creating one is a simple matter of
programming (SMOP). In particular, since the details of the command
implementations for the foreseeable future almost surely will have some
dependence on the particular hardware present, it seems appropriate to assign
to each subcommand an entry in the internal stubs table and then simply have
the main ''Tcl_QubitObjCmd'' call each as appropriate.

|   int
|   Tcl_QubitObjCmd(
|       ClientData clientData,      /* Might be used. */
|       Tcl_Interp *interp,         /* Current interpreter. */
|       int objc,                   /* Number of arguments. */
|       Tcl_Obj *CONST objv[])      /* Argument objects. */
|   {

|       int index;
|       static CONST char *options[] = {
|           "dispose",     "measure",     "names",
|           "new",         "operate",     (char *) NULL
|       };
|       enum options {
|           QUBIT_DISPOSE, QUBIT_MEASURE, QUBIT_NAMES,
|           QUBIT_NEW,     QUBIT_OPERATE
|       };
|
|       if (objc < 2) {
|           Tcl_WrongNumArgs(interp, 1, objv, "subcmd ?arg ...?");
|           return TCL_ERROR;
|       }

|
|       if (Tcl_GetIndexFromObj(interp, objv[1], options, "subcommand",  0,
|               &index) != TCL_OK) {
|           return TCL_ERROR;
|       }

|
|       switch ((enum options) index) {
|       case QUBIT_DISPOSE:
|           return TclQubitDisposeObjCmd(clientData, interp, objc,  objv);
|       case QUBIT_MEASURE:
|           return TclQubitMeasureObjCmd(clientData, interp, objc,  objv);
|       case QUBIT_NAMES:
|           return TclQubitNamesObjCmd(clientData, interp, objc, objv);
|       case QUBIT_NEW:
|           return TclQubitNewObjCmd(clientData, interp, objc, objv);
|       case QUBIT_OPERATE:
|           return TclQubitOperateObjCmd(clientData, interp, objc,  objv);
|       }

|
|       /*
|        * We won't get this far.
|        */
|
|       Tcl_Panic("unhandled subcommand");
|       return TCL_ERROR;
|   }


A fallback definition of ''TclQubitNewObjCmd'' that can be used when Tcl is
compiled without hardware QPU support is:

|   int
|   TclQubitNewObjCmd(
|       ClientData dummy,           /* Not used. */
|       Tcl_Interp *interp,         /* Current interpreter. */
|       int objc,                   /* Number of arguments. */
|       Tcl_Obj *CONST objv[])      /* Argument objects. */
|   {

|       int optArgIdx, index;
|       static CONST char *optionStrings[] = {
|           (char *) NULL           /* Currently there are no options.  */
|       };
|
|       if (objc % 2 != 0) {
|           Tcl_WrongNumArgs(interp, 2, objv, "?-option value ...?");
|           return TCL_ERROR;
|       }

|       for (optArgIdx = 2 ; optArgIdx < objc ; optArgIdx += 2) {
|           if (Tcl_GetIndexFromObj(interp, objv[optArgIdx], optionStrings,
|                   "option", TCL_EXACT, &index) != TCL_OK) {
|               return TCL_ERROR;
|           }

|
|           /*
|            * When options are added, handle them here.
|            */
|       }

|
|       /*
|        * Fail gracefully.
|        */
|
|       Tcl_SetErrno(ENXIO);        /* QPU not configured. */
|       Tcl_AppendResult(interp, "couldn't allocate a qubit: ",
|               Tcl_PosixError(interp), NULL);
|       return TCL_ERROR;
|   }


Other fallback definitions obviously follow the same pattern. Filling in the
details should be a cultivating exercise for Robert Abitbol.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|


|

|




|




|





|
|

|


|

|






|
|
|






|

|
|

|

|
|
|






|

|
|



|

|

|



|

|




|
|


|

|

|
|


|
|

|



|
|

|
|
|




|
|

|

|

|

|
|
|


|

|




|


|

|

|

|

|
|

|

|

|




|




|

|

|

|
|
|
|
|
<
>



|






|
|
|
<
>




|
|
|
|
|
<
|
>
|
|

|




|


|
|
|








|
|
|
|
|



|
|
|
|
|
|


|



|


|

|
|




|


|
|



|
|

|
|
|

|

|

|

|



|
|






|





|


|

|
|
|












|

|
|
|
|




|



|

|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
|
>
|


|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
<
>




|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

185
186
187
188
189
190
191
192
193
194
195
196
197
198

199
200
201
202
203
204
205
206
207
208

209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344

345
346
347
348
349
350
351
352
353
354
355
356
357
358

359
360
361
362
363

364
365
366
367
368
369
370
371
372
373
374
375
376

377
378
379
380
381
382
383
384

385
386
387
388
389
390
391
392
393
394
395

396
397
398
399
400
401
402
403
404

405
406
407
408
409

410
411
412
413
414

415
416
417
418
419
420
421
422
423
424

425
426
427
428
429
430
431
432
433

# TIP 263: Quantum Tcl

	Author:		Lars Hellström <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		Pending
	Tcl-Version:	9.2
	Created:	01-Apr-2006
	Post-History:	
-----

# Abstract

A new Tcl command **qubit** is proposed. This command makes it possible to
handle quantum information in the form of qubits.

# Rationale

As stated in [[131]](131.md), what Tcl needs in order to succeed in the marketplace is a
feature that no other programming language provides, a "killer app" as it
were. The Tk toolkit, Expect, cross-platform portability, starkits, tkcon, and
excellent embed/extend-ability with respect to other languages are all well
and good, but they have clearly failed to push Tcl usage to the point of
having critical mass.  The **qubit** command makes it possible to achieve an
exponential speedup for important problems and should therefore provide a
powerful enough incentive that even Perl programmers would be compelled to
switch languages.

# Background

Quantum computing makes use of phenomena in quantum mechanics to, at each time
step, carry out an exponential amount of work using only a linear amount of
hardware. The way this maps onto physical reality is pretty mind-boggling, but
for the programmer it is sufficient to think of the Quantum Processing Unit
\(QPU\) as an extremely powerful but somewhat specialised coprocessor and leave
it at that. \(Chances are anyway that the QPU isn't physically located in your
desktop computer, as they tend to involve lots of lasers, magnets, vacuum
chambers, liquid nitrogen cooling, etc.\)

Quantum information display an interesting duality in that it is analog during
a computation, but becomes digital as soon as one measures it. \(Wave/particle
duality, in case anyone came to think of that, is the kind of "mapping onto
physical reality" issue that will not be treated here.\) This makes the design
of quantum algorithms somewhat different from the design of classical
algorithms, in a manner similar to that in which the design of analog
electronic circuits is different from the design of digital electronic
circuits, as one must often work out the numbers rather than rely on a
discrete case-by-case analysis. Another curious feature is that all fully
quantum operations must be reversible, which in particular has the effect that
quantum information can neither be duplicated nor \(in the absence of
measurements\) destroyed, only rearranged. There is in particular no quantum
analogue to assignments such as [set a $b], since not only need this copy
the value of b, it also irrecoverably destroys the old value of a; the closest
one gets to such an assignment is exchanging the values of a and b.

For more information on quantum computing in general, see e.g.:

   * Wikipedia article "Quantum computer"
     <http://en.wikipedia.org/wiki/Quantum_computer> .

   * J. Gruska: Quantum Computing \(1999\), ISBN 0-07-709503-0,
     <http://www.fi.muni.cz/usr/gruska/quantum/> .

# Specification

The quantum computing model supported by the **qubit** command is that of
_quantum bits_ \(more commonly called _qubits_\) and _quantum boolean
circuits_. While other more fancy models such as "Quantum Turing Machines"
exist, this is generally considered to be the most realistic model, and it is
also the one most closely related to the number-of-gates complexity measure
for classical computing. Should it in the future prove desirable to support
also some other model, then one may do so through a separate command.

In this model, a quantum state of N qubits is completely specified by a set of
2\*\*N complex numbers, usually known as _probability amplitudes_ \(they are
not probabilities as such, but they do completely determine the probabilities
for various events\). Many different bases are possible, but in the standard
\(also known as the computational\) basis each of these amplitudes corresponds
to a particular assignment of 0s and 1s to the qubits. Operations on a quantum
state can be understood as operations on the vector of amplitudes.

The **qubit** command has the five subcommands.

## The 'new' Subcommand

 > **qubit new** ?_-option value_ ?...??

Allocate/create a new qubit, and return a handle for the new qubit that
identifies it in subsequent operations, or throw an error if
allocation/creation failed \(possible causes include, but are not limited to,
lack of resources on the hardware side and user having insufficient
permissions\). New qubits are not entangled with any of the old ones, but their
state is otherwise unspecified.

The options are meant as a means for supplying extra information about the new
qubit, such as for example whether it is being protected from decoherence by a
scheme of quantum error correction codes \(the Tcl core can easily implement
such features on platforms where the C level APIs only provide raw qubits\);
however at present no options are defined.

## The 'operate' Subcommand

 > **qubit operate** _gate id0_ ?_id1_ ?...??

Perform a quantum operation \(the _gate_\) on one or more qubits \(specified
using the handles _id0_, _id1_, etc.\). Returns the operation actually
applied.

In the interest of generality, gates are specified as unitary matrices \(this
is a universal representation for quantum gates\), or more concretely as lists
of lists of lists of doubles. The innermost lists must have length 2 and
encode the real \(index 0\) and imaginary \(index 1\) parts of an element of the
matrix. Indices in the middle list level select a column and indices in the
outer list level consequently a row. Put another way,

	 lindex $gate $i $j 0 ; # Returns Re gate(i,j)
	 lindex $gate $i $j 1 ; # Returns Im gate(i,j)

The row/column index corresponding to the _id0_ qubit having value $r0, the
_id1_ qubit having value $r1, etc. is $r0\*\(2\*\*0\) \+ $r1\*\(2\*\*1\) \+ ... A
_gate_ for operating on _n_ qubits must thus have side 2\*\*_n_. Columns
correspond to qubit states before the operation and rows correspond to qubit
states after the operation.

An error is thrown if the number of qubit arguments does not match the side of
the _gate_ matrix, if not all _idN_ arguments are qubit handles, if some
qubit occurs twice in the list, and if _gate_ is not a proper matrix \(too
many or too few elements in some list, elements not recognised as doubles,
etc.\).

An error is _not_ thrown if the _gate_ is not unitary. In general the
operation actually applied has to be supported by the available hardware, so
the **qubit operate** command \(or some lower level interface\) should
determine which supported operation most closely approximates the specified
_gate_ and apply that instead. The user can check what was done \(up to
numeric precision\) by inspecting the return value. Using a return value from
**qubit operate** as the _gate_ for another call should result in the
exact same operation being carried out.

## The 'measure' Subcommand

 > **qubit measure** _id_

Measures a qubit with respect to the standard basis. Returns 0 or 1 depending
on the resulting state.

_Note_ that measuring a qubit changes the quantum state to one in which that
qubit has a pure value. If other qubits are initially entangled with the one
being measured, then these will also be affected by this operation. Measuring
a qubit causes it to be disentangled from all other qubits \(or perhaps
entangles the state of the entire universe with the qubit, depending on your
philosophical point of view\).

## The 'dispose' Subcommand

 > **qubit dispose** _id_

Frees/deallocates a qubit, returning it to whatever pool of resources **qubit
new** got it from, but before doing that the qubit is measured to safely
disentangle it from any remaining qubits. The return value is 0 or 1 as for
the corresponding **qubit measure**.

## The 'names' Subcommand

 > **qubit names**

This is an instrospection command. It returns a list of all qubit handles
currently available in this interpreter.

## Future Expansion

Other subcommands may be added in the future, but this set is complete for
single interpreter algorithms.

# Examples

The syntax of **qubit operate** was chosen to facilitate the creation of
aliases for common gates, as this should make programs more readable. An alias
for the CNOT \(conditional not\) gate can be created as

	 interp alias {} CNOT {} qubit operate {
	    { {1 0} {0 0} {0 0} {0 0} }
	    { {0 0} {0 0} {0 0} {1 0} }
	    { {0 0} {0 0} {1 0} {0 0} }
	    { {0 0} {1 0} {0 0} {0 0} }

	 }

after which one can use the command

	 CNOT $control $target

The more significant $target qubit is negated if the $control qubit is 1 but
left alone otherwise.

Another standard gate is the Hadamard gate, which can be defined as follows.

	 set rsqrt2 [list [expr {1/sqrt(2)}] 0] ; # Reciprocal square root of  2.
	 interp alias {} Hadamard {} qubit operate [
	   list [list $rsqrt2 $rsqrt2] [list $rsqrt2 [list [expr -sqrt(0.5)]  0]]

	 ]

The Hadamard gate is used to create states that are uniform superpositions of
0s and 1s. A simple application of that is the following random bit generator.

		 proc randombit {} {
		     set id [qubit new]        ; # Allocate qubit
		     qubit measure $id         ; # Make pure 0 or pure 1
		     Hadamard $id              ; # Make an equal mix of 0 and 1
		     return [qubit dispose $id]; # Measure and clean up

		 }

Note that this \(provided, of course, that one believes in the standard
interpretation of quantum mechanics\) is not a psuedo-random bit generator, but
a truly random bit generator. Even if the Hadamard gate would be slightly off
\(unlikely, as this is a very standard gate, but possible\) this would not
affect the essential randomness of the bits produced, but only the exact
probability.

A third type of elementary gate is the phase shift gate, which changes the
phase \(but not the size\) of some probability amplitude. To change the phase of
the 1 amplitude of a qubit $id by the angle $phi, one would use the command

	 qubit operate [list {{1.0 0.0} {0.0 0.0}} [list {0.0 0.0} [
	     list [expr {cos($phi)}] [expr {sin($phi)}]
	 ]]] $id

Phase changes do not change the probability distribution for any qubit
measurement, but they do affect the state in ways that can lead to different
probabilities further on, and thus illustrate the fact that there is more to a
quantum state than the probability distribution it gives rise to here and
now. As a concrete example of this, assuming $id is a qubit, and with aliases
as above, the script:

	 set before [qubit measure $id]
	 Hadamard $id
	 Hadamard $id
	 set after [qubit measure $id]
	 expr {$before == $after}

will with probability 1 produce the result 1, whereas the script:

	 set before [qubit measure $id]
	 Hadamard $id
	 qubit operate {{{1 0} {0 0}} {{0 0} {-1 0}}} $id
	 Hadamard $id
	 set after [qubit measure $id]
	 expr {$before == $after}

will with probability 1 produce the result 0. The only difference is the 180
degrees phase shift of the 1 amplitude in the explicit **qubit operate**
command, which transforms one state with equal probabilities for 0 and 1 to
another state with equal probabilities for 0 and 1!

# Rejected Alternatives

One might expect that a truly Quantum Tcl would keep quantum information as
"first class data", i.e., in Tcl\_Objs to be passed around by value rather than
as qubits that can only be passed around by name, but that is impossible
\(unless one goes to such lengths as to run the entire Tcl process in a QPU,
which again will probably never be possible\) due to a fundamental
incompatibility between the laws of quantum mechanics and Tcl's Everything Is
A String principle.

Beginning with the EIAS side, one may observe that for a quantum state to be
encodable into a Tcl\_Obj, it must be serializable - there must be a way of
generating a string that completely encodes the state. Since quantum mechanics
does not permit extracting that much information about a quantum state, there
are only two options: either everything is kept within the QPU \(not
realistic\), or nothing is kept in the QPU. In the latter case, one loses
entirely the advantage of quantum computation, so it is rather pointless.

On the quantum side, one may observe that most of the things that are
routinely done to Tcl\_Objs are simply impossible to do to quantum information.
The fundamental problem here is that Tcl\_Objs must be duplicatable, whereas it
is a theorem in quantum mechanics that quantum states cannot be duplicated
\(the "No cloning" theorem\). Somewhat related is the problem that quantum
information can only be read \(used as input to some operation\) once, whereas a
Tcl\_Obj can be written once but read an unlimited number of times.

# Security Implications

As the **qubit** command only manipulates data and cannot be used for any
form of communication, it may in principle be made available also in safe
interpreters. However since **qubit new** seizes a global resource that can
be expected to be in limited supply on a system, it is probably better to be
safe than sorry, and therefore the **qubit** command shall initially be
hidden in a safe interpreter.

Omitting the command entirely and instead alias all qubit operations to the
**qubit** command of the parent interpreter is _not_ a good idea, as the
quick \(but sloppy\) implementation of this would allow untrusted code evaluated
in the safe interpreter access also to the qubits of the parent.

It should be noted that the easy access to quantum computing that this command
provides would have significant implications for the security of many external
systems. Such issues are outside the scope of this TIP.

# Future Extensions

Besides quantum algorithms, many interesting applications of quantum
information processing involves communication through the means of a quantum
state shared by different parties. While fast long distance qubit
transportation is physically made possible by means of quantum teleportation
\(which really isn't as fancy as it sounds - basically it amounts to a
combination of the old TV chef trick of having prepared something in advance,
in this case physically transferring a qubit, and the patchfile trick of only
transmitting a diff against what was physically distributed\), there are
currently no standardised protocols for this, and until the time that there is
there probably isn't much point in specifying some **qubit socket** command
for Tcl either. It may however be observed that _non-open_ commercial
systems <http://www.magiqtech.com/>  transmitting quantum information over long
distances are available today.

While transferring qubits between different machines obviously present some
technical problems, it may seem that transferring qubits between different
interpreters in the same process should at least be straightforward, but the
presence of multiple threads in the process introduce complications also for
this case. Concretely, transferring a qubit from one thread to another will in
general cause these threads to become entangled! In order to not make thread
maintenance even more complicated by introducing the concept of quantum
deadlock due to thread tangles, this TIP does not treat the subject of a
mechanism for transferring qubits between interpreters.

# Reference Implementation

A Tcl level emulation of the **qubit** command \(minus some error checking,
but also not requiring a QPU\) is available as SF patch no 1462755
<http://sf.net/tracker/?func=detail&aid=1462755&group_id=10894&atid=310894> .
This emulation uses the standard Tcl rand\(\) function for generating random
numbers, so it is not cryptographically safe. Also note that it internally
uses of some tcllib packages, which must therefore be available.

No C implementation exists at present, but creating one is a simple matter of
programming \(SMOP\). In particular, since the details of the command
implementations for the foreseeable future almost surely will have some
dependence on the particular hardware present, it seems appropriate to assign
to each subcommand an entry in the internal stubs table and then simply have
the main _Tcl\_QubitObjCmd_ call each as appropriate.

	   int
	   Tcl_QubitObjCmd(
	       ClientData clientData,      /* Might be used. */
	       Tcl_Interp *interp,         /* Current interpreter. */
	       int objc,                   /* Number of arguments. */
	       Tcl_Obj *CONST objv[])      /* Argument objects. */

	   {
	       int index;
	       static CONST char *options[] = {
	           "dispose",     "measure",     "names",
	           "new",         "operate",     (char *) NULL
	       };
	       enum options {
	           QUBIT_DISPOSE, QUBIT_MEASURE, QUBIT_NAMES,
	           QUBIT_NEW,     QUBIT_OPERATE
	       };
	
	       if (objc < 2) {
	           Tcl_WrongNumArgs(interp, 1, objv, "subcmd ?arg ...?");
	           return TCL_ERROR;

	       }
	
	       if (Tcl_GetIndexFromObj(interp, objv[1], options, "subcommand",  0,
	               &index) != TCL_OK) {
	           return TCL_ERROR;

	       }
	
	       switch ((enum options) index) {
	       case QUBIT_DISPOSE:
	           return TclQubitDisposeObjCmd(clientData, interp, objc,  objv);
	       case QUBIT_MEASURE:
	           return TclQubitMeasureObjCmd(clientData, interp, objc,  objv);
	       case QUBIT_NAMES:
	           return TclQubitNamesObjCmd(clientData, interp, objc, objv);
	       case QUBIT_NEW:
	           return TclQubitNewObjCmd(clientData, interp, objc, objv);
	       case QUBIT_OPERATE:
	           return TclQubitOperateObjCmd(clientData, interp, objc,  objv);

	       }
	
	       /*
	        * We won't get this far.
	        */
	
	       Tcl_Panic("unhandled subcommand");
	       return TCL_ERROR;

	   }

A fallback definition of _TclQubitNewObjCmd_ that can be used when Tcl is
compiled without hardware QPU support is:

	   int
	   TclQubitNewObjCmd(
	       ClientData dummy,           /* Not used. */
	       Tcl_Interp *interp,         /* Current interpreter. */
	       int objc,                   /* Number of arguments. */
	       Tcl_Obj *CONST objv[])      /* Argument objects. */

	   {
	       int optArgIdx, index;
	       static CONST char *optionStrings[] = {
	           (char *) NULL           /* Currently there are no options.  */
	       };
	
	       if (objc % 2 != 0) {
	           Tcl_WrongNumArgs(interp, 2, objv, "?-option value ...?");
	           return TCL_ERROR;

	       }
	       for (optArgIdx = 2 ; optArgIdx < objc ; optArgIdx += 2) {
	           if (Tcl_GetIndexFromObj(interp, objv[optArgIdx], optionStrings,
	                   "option", TCL_EXACT, &index) != TCL_OK) {
	               return TCL_ERROR;

	           }
	
	           /*
	            * When options are added, handle them here.
	            */

	       }
	
	       /*
	        * Fail gracefully.
	        */
	
	       Tcl_SetErrno(ENXIO);        /* QPU not configured. */
	       Tcl_AppendResult(interp, "couldn't allocate a qubit: ",
	               Tcl_PosixError(interp), NULL);
	       return TCL_ERROR;

	   }

Other fallback definitions obviously follow the same pattern. Filling in the
details should be a cultivating exercise for Robert Abitbol.

# Copyright

This document has been placed in the public domain.

Name change from tip/264.tip to tip/264.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

TIP:		264
Title:		Add Function to Retrieve the Interpreter of a Window
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Post-History:	
Version:	$Revision: 1.8 $
Author:		George Petasis <[email protected]>
Created:	01-Apr-2006
Keywords:	Tk, C API


~ Abstract

This TIP proposes the addition of a new function in the Tk public API, for
retrieving a pointer to the Tcl interpreter that was used for creating a
window.

~ Rationale

During the development of a Tk extension that adds a ClientMessage handler
under unix (tkdnd), I needed to get the pointer of the Tcl interpreter that is
associated with a window. When the ClientMessage handler is called, only a
Tk_Window pointer is passed, for the window the ClientMessage is for. But if
you want to execute Tcl code, you don't have a Tcl interpreter...

Of course, you can try use any (cached) interpreter, but this can lead to
various problems, if it is not the interpreter that was used for creating the
window. Since Tk already has this information, adding a function to return the
associated interpreter for a Tk_Window pointer will be relatively easy.

~ Proposed Change

A new public function (with signature ''Tcl_Interp *''
'''Tk_Interp'''''(Tk_Window tkwin)'') is proposed to be added to the public C
API of Tk. This function can be implemented as follows:

| Tcl_Interp *
| Tk_Interp(Tk_Window tkwin) {
|     if (tkwin != NULL && ((TkWindow *) tkwin)->mainPtr != NULL) {
|         return ((TkWindow *) tkwin)->mainPtr->interp;
|     }

|     return NULL;
| }


~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|





|


|

|


|


|

|

|
|


|
|
|
|
<
>
|
<
|
>
|


>

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

# TIP 264: Add Function to Retrieve the Interpreter of a Window
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Post-History:	

	Author:		George Petasis <[email protected]>
	Created:	01-Apr-2006
	Keywords:	Tk, C API
-----

# Abstract

This TIP proposes the addition of a new function in the Tk public API, for
retrieving a pointer to the Tcl interpreter that was used for creating a
window.

# Rationale

During the development of a Tk extension that adds a ClientMessage handler
under unix \(tkdnd\), I needed to get the pointer of the Tcl interpreter that is
associated with a window. When the ClientMessage handler is called, only a
Tk\_Window pointer is passed, for the window the ClientMessage is for. But if
you want to execute Tcl code, you don't have a Tcl interpreter...

Of course, you can try use any \(cached\) interpreter, but this can lead to
various problems, if it is not the interpreter that was used for creating the
window. Since Tk already has this information, adding a function to return the
associated interpreter for a Tk\_Window pointer will be relatively easy.

# Proposed Change

A new public function \(with signature _Tcl\_Interp \*_
**Tk\_Interp**_\(Tk\_Window tkwin\)_\) is proposed to be added to the public C
API of Tk. This function can be implemented as follows:

	 Tcl_Interp *
	 Tk_Interp(Tk_Window tkwin) {
	     if (tkwin != NULL && ((TkWindow *) tkwin)->mainPtr != NULL) {
	         return ((TkWindow *) tkwin)->mainPtr->interp;

	     }
	     return NULL;

	 }

# Copyright

This document has been placed in the public domain.

Name change from tip/265.tip to tip/265.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

TIP:		265
Title:		A Convenient C-side Command Option Parser for Tcl
Version:	$Revision: 1.7 $
Author:		Sam Bromley <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	03-Apr-2006
Post-History:
Tcl-Version:	8.6
Keywords:	Command line parsing, C implementation


~Abstract

The Tk C library provides developers with a ''Tk_ParseArgv''() function that
allows command line parsing of options of the "-option" form. Archived
discussions on news:comp.lang.tcl and on the Wiki indicate that a desire for
similar functionality without Tk has arisen several times in the past. This
TIP presents a Tk-free implementation of ''Tk_ParseArgv()'' named
'''Tcl_ParseArgvObj''', that developers can use to parse "-option" style
command options in C implementations of Tcl commands using the Tcl_Obj
interface.

~Rationale

While the parsing of command options can be readily accomplished on the Tcl
side, a uniform method for parsing "-option" formed options does not exist on
the C side. Many developers are familiar with the ease of use of libpopt-style
command line parsing, but a similarly clean method does not currently exist in
Tcl. The common approach is to use ''Tcl_GetIndexFromObj''(), yet this method
alone does not allow the flexibilty and ease of use of libpopt-style parsing.

One drawback of the classical ''Tcl_GetIndexFromObj''()-only approach is the
need to handle the specifies of your command option parsing for each unique
command. This leads to significant code duplication. A libpopt-style approach
is to bundle all of your parsing specifics into a single array of structures
capturing the details, and then let a specific parsing routine handle the
parsing of every option for you. The '''Tcl_ParseArgvObj'''() routine
introduced in this TIP provides this functionality, thereby allowing the
removal of all parsing specifics from the command implimentation other than
that necessary to describe each optional argument.

Additionally, a function '''Tcl_ParseArgsObjv''' is provided to provide the
functionality of ''Tk_ParseArgs''() to those who desire it. A discussion in
2002 on news:comp.lang.tcl
[http://groups.google.com/group/comp.lang.tcl/browse_thread/thread/c4fea8f0346cf8ae/036961bf476a3b99?q=tcl_parseargv&rnum=2#036961bf476a3b99]
indicated that this is a desired feature. Arguments against a
'''Tcl_ParseArgsObjv''' implementation include that it is better to do all
command line parsing on the Tcl side. However, this implies writing two
wrapper functions: (i) A C implementation of a Tcl command; and (ii) A Tcl
wrapper that pre-parses the options before calling the C command. This can
lead to significant duplication of effort when porting a large project to a
Tcl enabled version. This point is particularly relevent in the context of
'''Tcl_ParseArgvObj'''(), as then one is not assuming that one can simply
replace the main() routine with Tcl, but rather that one is truly embedding
the C side in a larger system.

'''Tcl_ParseArgvObj'''() offers a clean method to enable flexible command line
parsing to C implementations of Tcl commands.

~Specification

This document proposes adding '''Tcl_ParseArgsObjv''', whose arguments shall
be:

 > int '''Tcl_ParseArgsObjv'''(Tcl_Interp *''interp'', const Tcl_ArgvInfo
   *''argTable'', int *''objcPtr'', Tcl_Obj *const *''objv'', Tcl_Obj
   ***''remainingObjv'')

'''Note''' that the count of arguments (referred to by ''objcPtr'') will be
modified, and a modified array will be returned via ''remainingObjv'' (and
need '''ckfree'''ing). The input array of objects will not be modified.

~Reference Implementation

A working implementation has been submitted to the Feature Request Tracker at
SourceForge [https://sourceforge.net/support/tracker.php?&aid=1446696].

~Example of Use

|#include <tcl.h>
|#include <tclArgv.h> /* not needed if subsumed into core */
|
|int g_test_cmd(ClientData clientData, Tcl_Interp *interp,
|    int objc, Tcl_Obj *CONST objv[])
|{

|  char *gname,*filename;
|  int i;
|  int numRepeat;
|  double scalar;
|  int doErase = 0;
|  size_t size;
|
|  /* this table specifies the possible options, all in one place.*/
|  Tcl_ArgvInfo argTable[] = {
|    {"-erase", TCL_ARGV_CONSTANT, (void *) 1, &doErase,
|      "erase image before plotting"},
|    {"-numRepeat", TCL_ARGV_INT, NULL, &numRepeat,
|      "number of times to repeat test"},
|    {"-scalar", TCL_ARGV_FLOAT, NULL, &scalar,
|      "scalar multiple to use for test"},
|    {"-outfile", TCL_ARGV_STRING, NULL, &filename,
|      "name of file to which to dump result"},
|    {NULL, TCL_ARGV_END, NULL, NULL, NULL}
|  };
|
|  /* Call Tcl_ParseArgObjv to do all the parsing! */
|  if (Tcl_ParseArgsObjv(interp,argTable,&objc,objv,&private_objv) != TCL_OK) {
|     return TCL_ERROR;
|  }

|
|  /* Should recheck objc here */
|
|  /* at this point, any unhandled options are repacked in private_objv */
|  gname = Tcl_GetString(private_obj[1]);
|
|  /* all done */
|  ckfree(private_objv);
|
|  /* rest of code continues here...*/
|
|  return TCL_OK;
|}


~Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|
|
|


|





|


|




|




|
|

|

|

|



|
|


|


|

|


|
|
|

|
|
|

|


|

|

|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
<
|
>
|


>

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

# TIP 265: A Convenient C-side Command Option Parser for Tcl

	Author:		Sam Bromley <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	03-Apr-2006
	Post-History:
	Tcl-Version:	8.6
	Keywords:	Command line parsing, C implementation
-----

# Abstract

The Tk C library provides developers with a _Tk\_ParseArgv_\(\) function that
allows command line parsing of options of the "-option" form. Archived
discussions on news:comp.lang.tcl and on the Wiki indicate that a desire for
similar functionality without Tk has arisen several times in the past. This
TIP presents a Tk-free implementation of _Tk\_ParseArgv\(\)_ named
**Tcl\_ParseArgvObj**, that developers can use to parse "-option" style
command options in C implementations of Tcl commands using the Tcl\_Obj
interface.

# Rationale

While the parsing of command options can be readily accomplished on the Tcl
side, a uniform method for parsing "-option" formed options does not exist on
the C side. Many developers are familiar with the ease of use of libpopt-style
command line parsing, but a similarly clean method does not currently exist in
Tcl. The common approach is to use _Tcl\_GetIndexFromObj_\(\), yet this method
alone does not allow the flexibilty and ease of use of libpopt-style parsing.

One drawback of the classical _Tcl\_GetIndexFromObj_\(\)-only approach is the
need to handle the specifies of your command option parsing for each unique
command. This leads to significant code duplication. A libpopt-style approach
is to bundle all of your parsing specifics into a single array of structures
capturing the details, and then let a specific parsing routine handle the
parsing of every option for you. The **Tcl\_ParseArgvObj**\(\) routine
introduced in this TIP provides this functionality, thereby allowing the
removal of all parsing specifics from the command implimentation other than
that necessary to describe each optional argument.

Additionally, a function **Tcl\_ParseArgsObjv** is provided to provide the
functionality of _Tk\_ParseArgs_\(\) to those who desire it. A discussion in
2002 on news:comp.lang.tcl
<http://groups.google.com/group/comp.lang.tcl/browse_thread/thread/c4fea8f0346cf8ae/036961bf476a3b99?q=tcl_parseargv&rnum=2#036961bf476a3b99> 
indicated that this is a desired feature. Arguments against a
**Tcl\_ParseArgsObjv** implementation include that it is better to do all
command line parsing on the Tcl side. However, this implies writing two
wrapper functions: \(i\) A C implementation of a Tcl command; and \(ii\) A Tcl
wrapper that pre-parses the options before calling the C command. This can
lead to significant duplication of effort when porting a large project to a
Tcl enabled version. This point is particularly relevent in the context of
**Tcl\_ParseArgvObj**\(\), as then one is not assuming that one can simply
replace the main\(\) routine with Tcl, but rather that one is truly embedding
the C side in a larger system.

**Tcl\_ParseArgvObj**\(\) offers a clean method to enable flexible command line
parsing to C implementations of Tcl commands.

# Specification

This document proposes adding **Tcl\_ParseArgsObjv**, whose arguments shall
be:

 > int **Tcl\_ParseArgsObjv**\(Tcl\_Interp \*_interp_, const Tcl\_ArgvInfo
   *_argTable_, int \*_objcPtr_, Tcl\_Obj \*const \*_objv_, Tcl\_Obj
   *\*\*_remainingObjv_\)

**Note** that the count of arguments \(referred to by _objcPtr_\) will be
modified, and a modified array will be returned via _remainingObjv_ \(and
need **ckfree**ing\). The input array of objects will not be modified.

# Reference Implementation

A working implementation has been submitted to the Feature Request Tracker at
SourceForge <https://sourceforge.net/support/tracker.php?&aid=1446696> .

# Example of Use

	#include <tcl.h>
	#include <tclArgv.h> /* not needed if subsumed into core */
	
	int g_test_cmd(ClientData clientData, Tcl_Interp *interp,
	    int objc, Tcl_Obj *CONST objv[])

	{
	  char *gname,*filename;
	  int i;
	  int numRepeat;
	  double scalar;
	  int doErase = 0;
	  size_t size;
	
	  /* this table specifies the possible options, all in one place.*/
	  Tcl_ArgvInfo argTable[] = {
	    {"-erase", TCL_ARGV_CONSTANT, (void *) 1, &doErase,
	      "erase image before plotting"},
	    {"-numRepeat", TCL_ARGV_INT, NULL, &numRepeat,
	      "number of times to repeat test"},
	    {"-scalar", TCL_ARGV_FLOAT, NULL, &scalar,
	      "scalar multiple to use for test"},
	    {"-outfile", TCL_ARGV_STRING, NULL, &filename,
	      "name of file to which to dump result"},
	    {NULL, TCL_ARGV_END, NULL, NULL, NULL}
	  };
	
	  /* Call Tcl_ParseArgObjv to do all the parsing! */
	  if (Tcl_ParseArgsObjv(interp,argTable,&objc,objv,&private_objv) != TCL_OK) {
	     return TCL_ERROR;

	  }
	
	  /* Should recheck objc here */
	
	  /* at this point, any unhandled options are repacked in private_objv */
	  gname = Tcl_GetString(private_obj[1]);
	
	  /* all done */
	  ckfree(private_objv);
	
	  /* rest of code continues here...*/
	
	  return TCL_OK;

	}

# Copyright

This document has been placed in the public domain.

Name change from tip/266.tip to tip/266.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
136
137
138

TIP:            266
Title:          Numbers are Commands
Version:        $Revision: 1.8 $
Author:         Kristoffer Lawson <[email protected]>
Author:         Michal Malecki <[email protected]>
Author:         Wolf-Dieter Busch <[email protected]>
Author:         Paul Nash <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        11-Apr-2006
Post-History:   
Keywords:       Tcl,unknown,expression
Tcl-Version:    8.5


~ Abstract

This TIP describes a change to Tcl's command dispatch which would allow every number to act as a command.

~ Rationale

Maths in Tcl are continuously a stumbling block. The '''expr''' command is
ugly and cumbersome. It adds a new C-like syntax within Tcl and easily makes
lines less readable, especially with the most common use of simple arithmetic.
In addition it is confusing to the programmer to have to remember there is a
completely separate set of commands, or functions, which are only available to
the '''expr''' command.

This proposal offers a clean solution which could eventually totally replace
'''expr''', yet offers few or no backward compatibility problems and fits in
with the Tcl philosophy of "every piece of executable code is a command".

This addition is easy to build as a separate extension using the mechanisms
provided by Tcl. However, this will not be widely used unless it is stamped as
part of the language and part of its unique philosophy. In addition,
implementations in the core can gain from many forms of optimisation that
would not be possible with a normal extension.

There is an existing proposal for making operands into commands. That proposal
is still a valid one, but the description in this TIP leads to syntax which
will be more familiar to most programmers. It does not have operator
precedence, which is a difference from normal mathematics, but one that should
be easier to grasp than the reversed notation that operator commands offer. In
fact, there are many claims which state operator precedence is a mistake
anyway.

~ Specification

Every number that can be handled by Tcl is a command.

The format for number commands is:

 > ''number'' ''operation'' ?''arg1 arg2 ...''?

For example:

| 8 * 5 + 2

The first argument must be an operator, and can be one of any specified for
the '''expr''' command (+, -, *, /, ...)

Subsequent arguments can be either numbers or operators.

The command evaluates its arguments from left-to-right (no precedence) with
the result of the left used as the operand for the next operation. ''e.g.'' to
get 242 a simple addition can be made:

| 200 + 42

If multiple numbers are given without operators between them, the last
operator is used. ''e.g.'' for the result "42" the following can be used:

| 20 + 10 10 2

To get "23", the following can be used:

| 20 + 10 10 2 / 2 + 2

Normal Tcl brackets can be used for grouping purposes. ''e.g.'' the result
"31337" can be reached with the following:

| 62674 / [1 + 1]

Number commands act just like any other commands in Tcl. They can be nested
with brackets, aliased, replaced and even removed. The only difference is that
they do not appear in the list returned by '''info commands'''. However, any
replacements made on them do.

~~ Compatibility

Because of the ability to replace number-commands, there are no real backwards
compatibility issues. There are very few, if any, extensions that make numbers
into commands and any that do will still work with the only exception being
software that would mix extensions that would depend on the functionality in
this TIP and extensions that create their own commands which are only numbers.
In any case, the author is not aware of any extensions that create commands in
that manner.

The only other area where incompatibilities would arise would be if someone is
using an '''unknown''' mechanism which creates similar functionality to the
one presented here. These extensions do exist, but are mostly presented as
brain-twisters instead of for serious use.

Additionally, Tcl does not and cannot guarantee that new commands will not
appear in the global namespace. Indeed, every new release does this.

For these reasons, this proposal can be implemented with a minor version bump.

~ Implementation Discussion

The first natural step is to add a detection phase before the normal unknown
mechanism. In fact, a prototype implementation can easily and trivially be
built with Tcl's '''unknown''' command. The detection should work by checking
if the unknown command is a number and if so, it will run the number command
functionality. Otherwise, the normal Tcl chain of events is followed.

If the command is replaced, this number mechanism is never reached, as a
normal command exists to handle the situation.

If the command is removed, a special flag should be set to specify that the
number in question cannot be used as a command.

At a later date, further integration with the bytecode engine can be made.
The details of such optimizations are outside the scope of this TIP.

Some may argue that it is not good to disable defining commands with numbers by users. For example, someone would like to "overload" 0 and 1 to use [!file exists $f] && { puts "File not found"; exit }. This also does not look like a good solution for 'expr' command; this will be still not the same as expressions in other languages (required spaces between operators etc.)

~ Alternative Approaches

Instead of allowing multiple number arguments to use the same operator, a requirement could be made that every other argument must be an operator and every other one an operand. This might make the specification somewhat clearer, but would mean a mathematical operation on a list would not be as easy.

~ Comments

This is a change to the "eleven rules", so please do not do it. It takes the possibility that I can do it myself by changing the procedure unknown.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
>

|



|

|




|


|
















|





|



|


|



|
|


|


|

|



|

|


|



|


|










|








|



|












|

|



|



|


>

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
136
137
138

# TIP 266: Numbers are Commands

	Author:         Kristoffer Lawson <[email protected]>
	Author:         Michal Malecki <[email protected]>
	Author:         Wolf-Dieter Busch <[email protected]>
	Author:         Paul Nash <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        11-Apr-2006
	Post-History:   
	Keywords:       Tcl,unknown,expression
	Tcl-Version:    8.5
-----

# Abstract

This TIP describes a change to Tcl's command dispatch which would allow every number to act as a command.

# Rationale

Maths in Tcl are continuously a stumbling block. The **expr** command is
ugly and cumbersome. It adds a new C-like syntax within Tcl and easily makes
lines less readable, especially with the most common use of simple arithmetic.
In addition it is confusing to the programmer to have to remember there is a
completely separate set of commands, or functions, which are only available to
the **expr** command.

This proposal offers a clean solution which could eventually totally replace
**expr**, yet offers few or no backward compatibility problems and fits in
with the Tcl philosophy of "every piece of executable code is a command".

This addition is easy to build as a separate extension using the mechanisms
provided by Tcl. However, this will not be widely used unless it is stamped as
part of the language and part of its unique philosophy. In addition,
implementations in the core can gain from many forms of optimisation that
would not be possible with a normal extension.

There is an existing proposal for making operands into commands. That proposal
is still a valid one, but the description in this TIP leads to syntax which
will be more familiar to most programmers. It does not have operator
precedence, which is a difference from normal mathematics, but one that should
be easier to grasp than the reversed notation that operator commands offer. In
fact, there are many claims which state operator precedence is a mistake
anyway.

# Specification

Every number that can be handled by Tcl is a command.

The format for number commands is:

 > _number_ _operation_ ?_arg1 arg2 ..._?

For example:

	 8 * 5 + 2

The first argument must be an operator, and can be one of any specified for
the **expr** command \(\+, -, \*, /, ...\)

Subsequent arguments can be either numbers or operators.

The command evaluates its arguments from left-to-right \(no precedence\) with
the result of the left used as the operand for the next operation. _e.g._ to
get 242 a simple addition can be made:

	 200 + 42

If multiple numbers are given without operators between them, the last
operator is used. _e.g._ for the result "42" the following can be used:

	 20 + 10 10 2

To get "23", the following can be used:

	 20 + 10 10 2 / 2 + 2

Normal Tcl brackets can be used for grouping purposes. _e.g._ the result
"31337" can be reached with the following:

	 62674 / [1 + 1]

Number commands act just like any other commands in Tcl. They can be nested
with brackets, aliased, replaced and even removed. The only difference is that
they do not appear in the list returned by **info commands**. However, any
replacements made on them do.

## Compatibility

Because of the ability to replace number-commands, there are no real backwards
compatibility issues. There are very few, if any, extensions that make numbers
into commands and any that do will still work with the only exception being
software that would mix extensions that would depend on the functionality in
this TIP and extensions that create their own commands which are only numbers.
In any case, the author is not aware of any extensions that create commands in
that manner.

The only other area where incompatibilities would arise would be if someone is
using an **unknown** mechanism which creates similar functionality to the
one presented here. These extensions do exist, but are mostly presented as
brain-twisters instead of for serious use.

Additionally, Tcl does not and cannot guarantee that new commands will not
appear in the global namespace. Indeed, every new release does this.

For these reasons, this proposal can be implemented with a minor version bump.

# Implementation Discussion

The first natural step is to add a detection phase before the normal unknown
mechanism. In fact, a prototype implementation can easily and trivially be
built with Tcl's **unknown** command. The detection should work by checking
if the unknown command is a number and if so, it will run the number command
functionality. Otherwise, the normal Tcl chain of events is followed.

If the command is replaced, this number mechanism is never reached, as a
normal command exists to handle the situation.

If the command is removed, a special flag should be set to specify that the
number in question cannot be used as a command.

At a later date, further integration with the bytecode engine can be made.
The details of such optimizations are outside the scope of this TIP.

Some may argue that it is not good to disable defining commands with numbers by users. For example, someone would like to "overload" 0 and 1 to use [!file exists $f] && \{ puts "File not found"; exit \}. This also does not look like a good solution for 'expr' command; this will be still not the same as expressions in other languages \(required spaces between operators etc.\)

# Alternative Approaches

Instead of allowing multiple number arguments to use the same operator, a requirement could be made that every other argument must be an operator and every other one an operand. This might make the specification somewhat clearer, but would mean a mathematical operation on a list would not be as easy.

# Comments

This is a change to the "eleven rules", so please do not do it. It takes the possibility that I can do it myself by changing the procedure unknown.

# Copyright

This document has been placed in the public domain.

Name change from tip/267.tip to tip/267.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

TIP:		267
Title:		Allow 'exec' to Ignore Stderr
Version:	$Revision: 1.4 $
Author:		Nathan Bell <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Created:	25-Apr-2006
Post-History:	


~ Abstract

Currently the '''exec''' command will always fail if the process writes to
standard error. Since various applications use stderr for debug output it
would be useful to retain this output without having to resort to redirecting
stderr to stdout (which can cause interleaving).

~ Rationale

Various applications use stderr not just to report errors, but also warnings
and debugging information. Right now, the only way to make such a program
behave sensibly is to redirect stderr to stdout, or to a null device
(''i.e.'', /dev/null). If the program's output is being used elsewhere
(''i.e.'', to generate a document), stderr is the only means of reporting
debugging or progress information to the user. This information is lost if a
redirect is used.

Since standard error can be safely ignored in such circumstances, '''exec'''
is wrong to report such output as an error. Allowing '''exec''' to ignore
stderr in those situations would be both beneficial and more correct. It
should not be enabled by default though, as other applications write to stderr
solely to indicate that an error occurred, and do not generate a non-zero exit
code.

~ Consequences

Many applications use stderr for debugging and error reporting. When a program
fails, it will often return an error code and report the problem to stderr. If
'''exec''' is ignoring stderr such a error report will also be ignored,
leaving the tcl script with just the knowledge that some error occurred. If
the script is being run in a terminal or on the console, the stderr will be
reported directly to the user, but the script will have no way of getting the
information. It is up to the user of '''exec''' to deal with this as
appropriate.

~ Proposed Changes

As '''exec''' already contains the ability to accept options, adding an option
to ignore stderr is the most backward compatible fix.

An option '''-ignorestderr''' would fit with the existing '''-keepnewline'''
and proposed '''-binary''' (see [259]).

~ Implementation

A patch exists in the SourceForge feature request section (Request ID 1476191
[http://sf.net/tracker/?func=detail&aid=1476191&group_id=10894&atid=360894]).

This patch applies to generic/tclIOCmd.c. If the '''-ignorestderr''' option is
given, ''Tcl_OpenCommandChannel''() is not passed the TCL_STDERR flag. This is
the most straightforward method as it allows the existing functionality of
''Tcl_OpenCommandChannel''() to be exposed to '''exec''' command.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|


|

|




|
|



|
|





|



|



|


|

|


|
|

|

|
|

|
|

|

|


>

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

# TIP 267: Allow 'exec' to Ignore Stderr

	Author:		Nathan Bell <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Created:	25-Apr-2006
	Post-History:	
-----

# Abstract

Currently the **exec** command will always fail if the process writes to
standard error. Since various applications use stderr for debug output it
would be useful to retain this output without having to resort to redirecting
stderr to stdout \(which can cause interleaving\).

# Rationale

Various applications use stderr not just to report errors, but also warnings
and debugging information. Right now, the only way to make such a program
behave sensibly is to redirect stderr to stdout, or to a null device
\(_i.e._, /dev/null\). If the program's output is being used elsewhere
\(_i.e._, to generate a document\), stderr is the only means of reporting
debugging or progress information to the user. This information is lost if a
redirect is used.

Since standard error can be safely ignored in such circumstances, **exec**
is wrong to report such output as an error. Allowing **exec** to ignore
stderr in those situations would be both beneficial and more correct. It
should not be enabled by default though, as other applications write to stderr
solely to indicate that an error occurred, and do not generate a non-zero exit
code.

# Consequences

Many applications use stderr for debugging and error reporting. When a program
fails, it will often return an error code and report the problem to stderr. If
**exec** is ignoring stderr such a error report will also be ignored,
leaving the tcl script with just the knowledge that some error occurred. If
the script is being run in a terminal or on the console, the stderr will be
reported directly to the user, but the script will have no way of getting the
information. It is up to the user of **exec** to deal with this as
appropriate.

# Proposed Changes

As **exec** already contains the ability to accept options, adding an option
to ignore stderr is the most backward compatible fix.

An option **-ignorestderr** would fit with the existing **-keepnewline**
and proposed **-binary** \(see [[259]](259.md)\).

# Implementation

A patch exists in the SourceForge feature request section \(Request ID 1476191
<http://sf.net/tracker/?func=detail&aid=1476191&group_id=10894&atid=360894> \).

This patch applies to generic/tclIOCmd.c. If the **-ignorestderr** option is
given, _Tcl\_OpenCommandChannel_\(\) is not passed the TCL\_STDERR flag. This is
the most straightforward method as it allows the existing functionality of
_Tcl\_OpenCommandChannel_\(\) to be exposed to **exec** command.

# Copyright

This document has been placed in the public domain.

Name change from tip/268.tip to tip/268.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274

275
276
277
278

279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294









295
296
297
298
299
300
301
302

303
304
305

306
307
308
309

310
311
312
313
314
315
316

317
318
319

320
321
322
323


324
325
326
327
328
329
330

331
332
333
334

335
336
337
338

339
340
341
342
343
344
345
346

347
348

349
350
351
352
353


354
355
356

357
358
359
360
361
362
363
364

365
366
367

368
369
370
371

372
373
374
375
376
377

378
379

380
381
382
383
384
385
386
387

388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
















410
411
412

TIP:            268
Title:          Enhance 'package' Version Handling
Version:        $Revision: 1.12 $
Author:         Jeff Hobbs <[email protected]>
Author:         Hemang Lavana <[email protected]>
Author:         Andreas Kupries <[email protected]>
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        28-Apr-2006
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes enhancing the Tcl '''package''' command to understand
version numbers containing "a", and "b" and extend the semantics of '''package
require''' to allow multiple requirements and various types of ranges of
versions.

~ Rationale

The current Tcl '''package''' command is limited to understanding package
versioning based strictly on an infinite number of dot-separated positive
integers. Regardless, Tcl extensions and the core itself use version numbers
that have "a" for alpha and "b" for beta. This proposal seeks to make those
identifiers properly understood by Tcl's '''package version''' semantics.  It
also extends the logic to allow ranges.  This allows users to exclude package
versions with known bugs/incompatibilities as well as accepting a range of
major versions, which was previously only possibly through multiple '''package
require''' calls and '''catch'''.  The addition of '''package prefer''' is
created to handle nuances in how the new package requirements mechanism
interprets alpha/beta versions, because sometimes you want the bleeding edge
version of a package, and other times you want something you can depend on.

~ Specification

'''Current version specification:'''

(Summary of http://www.tcl.tk/man/tcl8.4/TclCmd/package.htm#M15)

Version numbers consist of one or more decimal numbers separated by dots, such
as 2 or 1.162 or 3.1.13.1. The first number is called the ''major'' version
number. Larger numbers correspond to later versions of a package, with
leftmost numbers having greater significance. For example, version 2.1 is
later than 1.3 and version 3.4.6 is later than 3.3.5. Missing fields are
equivalent to zeroes: version 1.3 is the same as version 1.3.0 and 1.3.0.0, so
it is earlier than 1.3.1 or 1.3.0.2.

'''Proposed version specification adds:'''

In addition, the letters 'a' (alpha) and/or 'b' (beta) may appear exactly once
to replace a dot for separation. These letters semantically add a negative
specifier into the version, where 'a' is -2, and 'b' is -1. Each may be
specified only once, and 'a' or 'b' are mutually exclusive in a specifier.
Thus 1.3a1 becomes (semantically) 1.3.-2.1, 1.3b1 is 1.3.-1.1. Negative
numbers are not directly allowed in version specifiers.

A version number not containing the letters 'a' or 'b' as specified above is
called a ''stable'' version, whereas presence of the letters causes the
version to be called is ''unstable''.

The syntax of [[package vsatisfies]] is extended to

 > '''package vsatisfies''' ''version requirement'' ?''requirement'' ...?

where each ''requirement'' is is allowed to have any of the forms:

   1. min

   1. min-

   1. min-max

where "min" and "max" are valid version numbers. The current syntax is case 1,
and the addition of cases 2 and 3 does not interfere with keeping backward
compatibility.

These three forms are called, in the order as listed above:

   1. "min-bounded"

   1. "min-unbound"

   1. "bounded"

Given the above the '''package vsatisfies''' functions like this:

 * The version has to pass at least one of the listed requirements to be
   satisfactory.

 * A version satisfies a "bounded" requirement when

 > * For min equal to the max if, and only if the version is equal to the min.

 > * Otherwise if, and only if the version is greater than or equal to the
     min, and less than the max, where both min and max have been extended
     internally with 'a0'. NOTE: min is ''inclusive'', max is ''exclusive''.

 * A "min-bounded" requirement is a "bounded" requirement in disguise, with
   the max part implicitly specified as the next higher major version number
   of the min part. A version satisfies it per the rules above.

 * A version satisfies a "min-unbound" requirement if, and only if it is
   greater than or equal to the min, where the min has been padded internally
   with 'a0'. There is no constraint to a max.

A new subcommand [[package prefer]] is added with syntax:

 > '''package prefer''' ?'''latest'''|'''stable'''?

With no arguments, '''package prefer''' returns either "latest" or "stable",
whichever describes the current mode of selection logic used by '''package
require'''.

When passed the argument "latest", it sets the selection logic mode to
"latest".

When passed the argument "stable", if the mode is already "stable", that value
is kept.  If the mode is already "latest", then the attempt to set it back to
"stable" is ineffective and the mode value remains "latest" [*].

When passed any other value as an argument, raise an invalid argument
error.

When a Tcl_Interp is created, its initial selection mode value is set
to "stable" unless the environment variable ''TCL_PKG_PREFER_LATEST''
is set.  If that environment variable is defined (with any value) then
the initial (and permanent) selection mode value is set to "latest".

The syntax of '''package require''' is changed to:

 > '''package require''' ?'''-exact'''? ''package'' ?''requirement'' ...?

and its package selection logic is modified to both agree with '''package
vsatisfies''' and to additionally support a multi-mode selection logic based
on the result of '''package prefer'''.

The requirements arguments are of the same form as accepted by '''package
vsatisfies'''.

The logic is:

 * In the "'''stable'''" selection mode the command will select the highest
   stable version satisfying the requirements, if any. If no stable version
   satisfies the requirements, the highest unstable version satisfying the
   requirements will be selected. This implements the behaviour that

| package require foo 1.5.3

 > will load version 1.5.4 in preference to version 1.6b2.

 > By default

| package require foo 1.5b3

 > will also load version 1.5.4 in preference to version 1.6b2, while still
   accepting 1.5b3 if it is the best available. It will also accept and load
   version 1.6b2 if no stable version that satisfies the requirement is
   available.

 > This fallback strategy employed for "'''stable'''", i.e. the ability to
   accept things outside of the declared preference makes programs combining
   several packages less fragile. This comes directly from implementing things
   as a preference to apply when possible, and not as a threshold that rejects
   nonpreferred, yet satisfactory solutions.

 * In the "latest" selection mode the command will accept the highest version
   satisfying all the requirements, regardless of its stableness.

All other '''package''' subcommands that accept a version number argument are
also revised to accept the expanded set of legal version numbers.

The calls to ''Tcl_PkgProvide()'' in both Tcl and Tk are revised to pass in
TCL_PATCH_LEVEL and TK_PATCH_LEVEL where they currently pass in TCL_VERSION
and TK_VERSION. '''info tclversion''', '''info patchlevel''',
'''$::tcl_version''', '''$::tcl_patchLevel''', '''$::tk_version''', and
'''$::tk_patchLevel''' are left unchanged.

A new public function ''Tcl_PkgRequireProc'' is provided, which has the
signature:

 > int '''Tcl_PkgRequireProc'''(Tcl_Interp *''interp'', CONST char *''name'',
   int ''objc'', Tcl_Obj *CONST ''objv''[], ClientData *''clientDataPtr'')

This function implements '''package require''' at the C level. The existing
functions ''Tcl_PkgRequire(Ex)'' are re-implemented in terms of this function.
It returns a standard Tcl error code, leaving either an error message
(TCL_ERROR), or the version of the found package (TCL_OK) in the result area
of the ''interp'' argument.

The API between ''Tcl_PkgRequire*'' and the package unknown handler is changed
as well. The unknown handler now has the signature:

 > ''unknown name'' ?''requirement...''?

All existing unknown handlers (init.tcl, tm.tcl) are changed to this API.

~~ Examples

Valid version numbers:

| 1.3a1

Invalid version numbers:

| 1.3a
| 1.3a1b2
| 1.3.a1

~ Discussion

Tcl RFE 219296 proposes similar support with the addition of a '''threshold'''
method to '''package'''. This proposal operates by modelling the '''a''', and
'''b''' specifiers as negative version specifiers.

A disadvantage of this proposal compared to the previous one is for folks
trying to do integration testing of unstable packages. They will be required
to take the additional step of either defining the environment variable
TCL_PKG_PREFER_LATEST or call

| package prefer latest

in an initialization script in order to overcome the default preference that
would otherwise fail to load the code that needs testing. It doesn't seem too
great a burden, but anything that makes testing of untable packages more
difficult means that on the margin there will be less testing of them.  The
impact of that is worth pondering a bit.

An important thing made possible is the sequence:

| package provide Tcl 8.5a5
| package require Tcl 8.5

so existing scripts with [package require Tcl 8.5] aren't broken by a Tcl
8.5a5 release.  This support comes from the rules for interpreting a
requirement's implicit demands beyond the fields it explicitly names.  A
requirement of 8.5 gets interpreted as equivalent to 8.5a0 and not equivalent
to 8.5.0. Note the language about ''internally extended with 'a0' '' in the
rules of '''package vsatisfies'''.

~ Footnotes

[*] Yes, this means '''package prefer stable''' is a verbose no-op. Sometimes
a verbose no-op can help code readability. I also think documenting a
setter/getter that is a no-op for some set values is easier than explaining
why the set of valid returns from the getter differs from the set of
acceptable arguments to the setter. Ability to do things like:

| interp create i
| i eval [list package prefer [package prefer]]

is a factor here as well.

Lots of discussion and rationale ensued on the tcl-core mailing list. Lars
Hellstr�m provided a good interpretive synopsis
[http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/3214264].

~ Reference Implementation

C implementation, see SF Patch
1520767[http://sourceforge.net/support/tracker.php?aid=1520767].

A reference implementation written in Tcl now follows.

| proc intList {version} {
|    # Convert a version number to an equivalent list of integers
|    # Raise error for invalid version number
|
|    if {$version eq {} || [string match *-* $version]} {
| 	# Reject literal negative numbers
| 	return -code error "invalid version number: \"$version\""
|    }

|    # Note only lowercase "a" and "b" accepted and only one
|    if {[llength [split $version ab]] > 2} {
| 	return -code error "invalid version number: \"$version\""
|    }

|    set converted [string map {a .-2. b .-1.} $version]
|    set list {}
|    foreach element [split $converted .] {
| 	if {[scan $element %d%s i trash] != 1} {
| 	    # Require decimal formatted numbers with no suffix
| 	    return -code error "invalid version number: \"$version\""
| 	}
| 	if {[catch {incr i 0}] || $i < -2 } {
|           # Verify each component is integer >= -2
| 	    return -code error "invalid version number: \"$version\""
| 	}
| 	lappend list $i
|    }
|    return $list
| }










| proc compare {l1 l2} {
|     # Compare lists of integers
|     foreach i1 $l1 i2 $l2 {
|         if {$i1 eq {}} {set i1 0}
|         if {$i2 eq {}} {set i2 0}
|         if {$i1 < $i2} {return -1}
|         if {$i1 > $i2} {return 1}
|     }

|     return 0
| }


| proc {package vcompare} {v1 v2} {
|     compare [intList $v1] [intList $v2]
| }


| proc {package vsatisfies} {v args} {
|    set vList [intList $v]	;# verify valid version number
|    foreach requirement $args {  ;# check all valid requirements
| 	if {[llength [lassign [split $requirement -] min max]]} {
| 	    # More than one "-"
| 	    return -code error "invalid requirement: \"$requirement\""
| 	}

| 	if {[catch {intList $min}]} {
| 	    return -code error "invalid requirement: \"$requirement\""
| 	}

| 	if {$max ne "" && [catch {intList $max}]} {
| 	    return -code error "invalid requirement: \"$requirement\""
| 	}
|    }


|    foreach requirement $args {
| 	lassign [split $requirement -] min max
| 	set minList [intList $min]
| 	lappend minList -2
| 	if {[compare $vList $minList] < 0} {
| 	    continue ;# not satisfied; on to the next one
| 	}

| 	if {[string match *- $requirement]} {
| 	    # No max constraint => satisfied!
| 	    return 1
| 	}

| 	if {$max eq ""} {
| 	    set max [lindex $minList 0]
| 	    incr max
| 	}

| 	set maxList [intList $max]
| 	lappend maxList -2
| 	if {[compare $minList $maxList] == 0} {
| 	    # Special case for "-exact" range
| 	    set minList [lreplace $minList end end]
| 	    if {[compare $vList $minList] == 0} {
| 		return 1
| 	    }

| 	    continue
| 	}

| 	if {[compare $vList $maxList] < 0} {
| 	    # Within the range => satisfied!
| 	    return 1
| 	}
|    }


|    return 0
| }


| proc lassign {list args} {
|    foreach v $args {upvar 1 $v x ; set x {}}
|    foreach v $args x $list {upvar 1 $v var ; set var $x}
|    if {[llength $args] < [llength $list]} {
| 	set notassigned [lrange $list [llength $args] end]
|    } else {
| 	set notassigned {}
|    }

|    return $notassigned
| }


| proc {package require} {pkg args} {
|    if {$pkg eq "-exact"} {
| 	# Convert legacy syntax (details omitted)
|    }

|    set present [package provide $pkg]
|    if {$present ne ""} {
| 	# $pkg already provided; check satisfaction
| 	if {[package vsatisfies $present {expand}$args]} {
| 	    return $present
| 	}

| 	return -code error "have $present, need $args"
|    }

|    set pass 2
|    while {$pass} {
| 	set acceptable {}
| 	foreach v [lsort -command {package vcompare} \
| 		       -decreasing [package versions $pkg]] {
| 	    if {![package vatisfies $v {expand}$args]} {
| 		continue
| 	    }

| 	    if {[package prefer] eq "latest"
| 		    || ![string match {*[ab]*} $v]} {
| 		# Error handling omitted here
| 		uplevel #0 [package ifneeded $pkg $v]
| 		return $v
| 	    }
| 	    lappend acceptable $v
| 	}
| 	if {[incr pass -1]} {
| 	    # use [package unknown] to find more versions
| 	}
|    }
|    if {[llength $acceptable]} {
| 	# Accept best satisfactory alpha/beta even
| 	# though our preference mode is "stable"
| 	set v [lindex $acceptable 0]
| 	uplevel #0 [package ifneeded $pkg $v]
| 	return $v
|    }
|    return -code error "can't find $pkg $args"
| }

















~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|
|
|


|

|



|


|
|




|

|

|


|






|

|



|



|
|

|

|

|



















|






|

|

|









|

|

|
|
|











|
|
|
|

|

|

|
|
|

|
|



|




|

|

|

|

|




|








|


|
|
|
|
|

|


|
|

|
|

|
|

|


|

|

|



|



|
|
|

|

|
|
|




|

|









|
|





|
|

|

|





|
|




|
|

|


|



|
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
|
|
<
<
<
<
<
<
<
<
<
|
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
<
>
|
<
|
>
|
|
<
|
>
|
|
|
|
|
|
<
>
|
|
<
>
|
|
<
<
>
>
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
<
>
|
|
|
<
<
>
>
|
<
|
>
|
|
|
|
|
|
|
<
>
|
<
|
>
|
|
|
<
>
|
|
|
|
|
<
>
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
<
<
<
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272

273
274
275
276

277
278
279
280
281
282
283









284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300

301
302

303
304
305
306

307
308
309
310
311
312
313
314

315
316
317

318
319
320


321
322
323
324
325
326
327
328

329
330
331
332

333
334
335
336

337
338
339
340
341
342
343
344

345
346

347
348
349
350


351
352
353

354
355
356
357
358
359
360
361
362

363
364

365
366
367
368
369

370
371
372
373
374
375

376
377

378
379
380
381
382
383
384
385

386
387
388
389













390
391



392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412

# TIP 268: Enhance 'package' Version Handling

	Author:         Jeff Hobbs <[email protected]>
	Author:         Hemang Lavana <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        28-Apr-2006
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes enhancing the Tcl **package** command to understand
version numbers containing "a", and "b" and extend the semantics of **package
require** to allow multiple requirements and various types of ranges of
versions.

# Rationale

The current Tcl **package** command is limited to understanding package
versioning based strictly on an infinite number of dot-separated positive
integers. Regardless, Tcl extensions and the core itself use version numbers
that have "a" for alpha and "b" for beta. This proposal seeks to make those
identifiers properly understood by Tcl's **package version** semantics.  It
also extends the logic to allow ranges.  This allows users to exclude package
versions with known bugs/incompatibilities as well as accepting a range of
major versions, which was previously only possibly through multiple **package
require** calls and **catch**.  The addition of **package prefer** is
created to handle nuances in how the new package requirements mechanism
interprets alpha/beta versions, because sometimes you want the bleeding edge
version of a package, and other times you want something you can depend on.

# Specification

**Current version specification:**

\(Summary of <http://www.tcl.tk/man/tcl8.4/TclCmd/package.htm\#M15\)>

Version numbers consist of one or more decimal numbers separated by dots, such
as 2 or 1.162 or 3.1.13.1. The first number is called the _major_ version
number. Larger numbers correspond to later versions of a package, with
leftmost numbers having greater significance. For example, version 2.1 is
later than 1.3 and version 3.4.6 is later than 3.3.5. Missing fields are
equivalent to zeroes: version 1.3 is the same as version 1.3.0 and 1.3.0.0, so
it is earlier than 1.3.1 or 1.3.0.2.

**Proposed version specification adds:**

In addition, the letters 'a' \(alpha\) and/or 'b' \(beta\) may appear exactly once
to replace a dot for separation. These letters semantically add a negative
specifier into the version, where 'a' is -2, and 'b' is -1. Each may be
specified only once, and 'a' or 'b' are mutually exclusive in a specifier.
Thus 1.3a1 becomes \(semantically\) 1.3.-2.1, 1.3b1 is 1.3.-1.1. Negative
numbers are not directly allowed in version specifiers.

A version number not containing the letters 'a' or 'b' as specified above is
called a _stable_ version, whereas presence of the letters causes the
version to be called is _unstable_.

The syntax of [package vsatisfies] is extended to

 > **package vsatisfies** _version requirement_ ?_requirement_ ...?

where each _requirement_ is is allowed to have any of the forms:

   1. min

   1. min-

   1. min-max

where "min" and "max" are valid version numbers. The current syntax is case 1,
and the addition of cases 2 and 3 does not interfere with keeping backward
compatibility.

These three forms are called, in the order as listed above:

   1. "min-bounded"

   1. "min-unbound"

   1. "bounded"

Given the above the **package vsatisfies** functions like this:

 * The version has to pass at least one of the listed requirements to be
   satisfactory.

 * A version satisfies a "bounded" requirement when

	 > \* For min equal to the max if, and only if the version is equal to the min.

	 > \* Otherwise if, and only if the version is greater than or equal to the
     min, and less than the max, where both min and max have been extended
     internally with 'a0'. NOTE: min is _inclusive_, max is _exclusive_.

 * A "min-bounded" requirement is a "bounded" requirement in disguise, with
   the max part implicitly specified as the next higher major version number
   of the min part. A version satisfies it per the rules above.

 * A version satisfies a "min-unbound" requirement if, and only if it is
   greater than or equal to the min, where the min has been padded internally
   with 'a0'. There is no constraint to a max.

A new subcommand [package prefer] is added with syntax:

 > **package prefer** ?**latest**\|**stable**?

With no arguments, **package prefer** returns either "latest" or "stable",
whichever describes the current mode of selection logic used by **package
require**.

When passed the argument "latest", it sets the selection logic mode to
"latest".

When passed the argument "stable", if the mode is already "stable", that value
is kept.  If the mode is already "latest", then the attempt to set it back to
"stable" is ineffective and the mode value remains "latest" [*].

When passed any other value as an argument, raise an invalid argument
error.

When a Tcl\_Interp is created, its initial selection mode value is set
to "stable" unless the environment variable _TCL\_PKG\_PREFER\_LATEST_
is set.  If that environment variable is defined \(with any value\) then
the initial \(and permanent\) selection mode value is set to "latest".

The syntax of **package require** is changed to:

 > **package require** ?**-exact**? _package_ ?_requirement_ ...?

and its package selection logic is modified to both agree with **package
vsatisfies** and to additionally support a multi-mode selection logic based
on the result of **package prefer**.

The requirements arguments are of the same form as accepted by **package
vsatisfies**.

The logic is:

 * In the "**stable**" selection mode the command will select the highest
   stable version satisfying the requirements, if any. If no stable version
   satisfies the requirements, the highest unstable version satisfying the
   requirements will be selected. This implements the behaviour that

		 package require foo 1.5.3

	 > will load version 1.5.4 in preference to version 1.6b2.

	 > By default

		 package require foo 1.5b3

	 > will also load version 1.5.4 in preference to version 1.6b2, while still
   accepting 1.5b3 if it is the best available. It will also accept and load
   version 1.6b2 if no stable version that satisfies the requirement is
   available.

	 > This fallback strategy employed for "**stable**", i.e. the ability to
   accept things outside of the declared preference makes programs combining
   several packages less fragile. This comes directly from implementing things
   as a preference to apply when possible, and not as a threshold that rejects
   nonpreferred, yet satisfactory solutions.

 * In the "latest" selection mode the command will accept the highest version
   satisfying all the requirements, regardless of its stableness.

All other **package** subcommands that accept a version number argument are
also revised to accept the expanded set of legal version numbers.

The calls to _Tcl\_PkgProvide\(\)_ in both Tcl and Tk are revised to pass in
TCL\_PATCH\_LEVEL and TK\_PATCH\_LEVEL where they currently pass in TCL\_VERSION
and TK\_VERSION. **info tclversion**, **info patchlevel**,
**$::tcl\_version**, **$::tcl\_patchLevel**, **$::tk\_version**, and
**$::tk\_patchLevel** are left unchanged.

A new public function _Tcl\_PkgRequireProc_ is provided, which has the
signature:

 > int **Tcl\_PkgRequireProc**\(Tcl\_Interp \*_interp_, CONST char \*_name_,
   int _objc_, Tcl\_Obj \*CONST _objv_[], ClientData \*_clientDataPtr_\)

This function implements **package require** at the C level. The existing
functions _Tcl\_PkgRequire\(Ex\)_ are re-implemented in terms of this function.
It returns a standard Tcl error code, leaving either an error message
\(TCL\_ERROR\), or the version of the found package \(TCL\_OK\) in the result area
of the _interp_ argument.

The API between _Tcl\_PkgRequire\*_ and the package unknown handler is changed
as well. The unknown handler now has the signature:

 > _unknown name_ ?_requirement..._?

All existing unknown handlers \(init.tcl, tm.tcl\) are changed to this API.

## Examples

Valid version numbers:

	 1.3a1

Invalid version numbers:

	 1.3a
	 1.3a1b2
	 1.3.a1

# Discussion

Tcl RFE 219296 proposes similar support with the addition of a **threshold**
method to **package**. This proposal operates by modelling the **a**, and
**b** specifiers as negative version specifiers.

A disadvantage of this proposal compared to the previous one is for folks
trying to do integration testing of unstable packages. They will be required
to take the additional step of either defining the environment variable
TCL\_PKG\_PREFER\_LATEST or call

	 package prefer latest

in an initialization script in order to overcome the default preference that
would otherwise fail to load the code that needs testing. It doesn't seem too
great a burden, but anything that makes testing of untable packages more
difficult means that on the margin there will be less testing of them.  The
impact of that is worth pondering a bit.

An important thing made possible is the sequence:

	 package provide Tcl 8.5a5
	 package require Tcl 8.5

so existing scripts with [package require Tcl 8.5] aren't broken by a Tcl
8.5a5 release.  This support comes from the rules for interpreting a
requirement's implicit demands beyond the fields it explicitly names.  A
requirement of 8.5 gets interpreted as equivalent to 8.5a0 and not equivalent
to 8.5.0. Note the language about _internally extended with 'a0' _ in the
rules of **package vsatisfies**.

# Footnotes

[*] Yes, this means **package prefer stable** is a verbose no-op. Sometimes
a verbose no-op can help code readability. I also think documenting a
setter/getter that is a no-op for some set values is easier than explaining
why the set of valid returns from the getter differs from the set of
acceptable arguments to the setter. Ability to do things like:

	 interp create i
	 i eval [list package prefer [package prefer]]

is a factor here as well.

Lots of discussion and rationale ensued on the tcl-core mailing list. Lars
Hellström provided a good interpretive synopsis
<http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/3214264> .

# Reference Implementation

C implementation, see SF Patch
1520767<http://sourceforge.net/support/tracker.php?aid=1520767> .

A reference implementation written in Tcl now follows.

	 proc intList {version} {
	    # Convert a version number to an equivalent list of integers
	    # Raise error for invalid version number
	
	    if {$version eq {} || [string match *-* $version]} {
	 	# Reject literal negative numbers
	 	return -code error "invalid version number: \"$version\""

	    }
	    # Note only lowercase "a" and "b" accepted and only one
	    if {[llength [split $version ab]] > 2} {
	 	return -code error "invalid version number: \"$version\""

	    }
	    set converted [string map {a .-2. b .-1.} $version]
	    set list {}
	    foreach element [split $converted .] {
	 	if {[scan $element %d%s i trash] != 1} {
	 	    # Require decimal formatted numbers with no suffix
	 	    return -code error "invalid version number: \"$version\""









	 	}
	 	if {[catch {incr i 0}] || $i < -2 } {
	           # Verify each component is integer >= -2
	 	    return -code error "invalid version number: \"$version\""
	 	}
	 	lappend list $i
	    }
	    return $list
	 }

	 proc compare {l1 l2} {
	     # Compare lists of integers
	     foreach i1 $l1 i2 $l2 {
	         if {$i1 eq {}} {set i1 0}
	         if {$i2 eq {}} {set i2 0}
	         if {$i1 < $i2} {return -1}
	         if {$i1 > $i2} {return 1}

	     }
	     return 0

	 }

	 proc {package vcompare} {v1 v2} {
	     compare [intList $v1] [intList $v2]

	 }

	 proc {package vsatisfies} {v args} {
	    set vList [intList $v]	;# verify valid version number
	    foreach requirement $args {  ;# check all valid requirements
	 	if {[llength [lassign [split $requirement -] min max]]} {
	 	    # More than one "-"
	 	    return -code error "invalid requirement: \"$requirement\""

	 	}
	 	if {[catch {intList $min}]} {
	 	    return -code error "invalid requirement: \"$requirement\""

	 	}
	 	if {$max ne "" && [catch {intList $max}]} {
	 	    return -code error "invalid requirement: \"$requirement\""


	 	}
	    }
	    foreach requirement $args {
	 	lassign [split $requirement -] min max
	 	set minList [intList $min]
	 	lappend minList -2
	 	if {[compare $vList $minList] < 0} {
	 	    continue ;# not satisfied; on to the next one

	 	}
	 	if {[string match *- $requirement]} {
	 	    # No max constraint => satisfied!
	 	    return 1

	 	}
	 	if {$max eq ""} {
	 	    set max [lindex $minList 0]
	 	    incr max

	 	}
	 	set maxList [intList $max]
	 	lappend maxList -2
	 	if {[compare $minList $maxList] == 0} {
	 	    # Special case for "-exact" range
	 	    set minList [lreplace $minList end end]
	 	    if {[compare $vList $minList] == 0} {
	 		return 1

	 	    }
	 	    continue

	 	}
	 	if {[compare $vList $maxList] < 0} {
	 	    # Within the range => satisfied!
	 	    return 1


	 	}
	    }
	    return 0

	 }

	 proc lassign {list args} {
	    foreach v $args {upvar 1 $v x ; set x {}}
	    foreach v $args x $list {upvar 1 $v var ; set var $x}
	    if {[llength $args] < [llength $list]} {
	 	set notassigned [lrange $list [llength $args] end]
	    } else {
	 	set notassigned {}

	    }
	    return $notassigned

	 }

	 proc {package require} {pkg args} {
	    if {$pkg eq "-exact"} {
	 	# Convert legacy syntax (details omitted)

	    }
	    set present [package provide $pkg]
	    if {$present ne ""} {
	 	# $pkg already provided; check satisfaction
	 	if {[package vsatisfies $present {expand}$args]} {
	 	    return $present

	 	}
	 	return -code error "have $present, need $args"

	    }
	    set pass 2
	    while {$pass} {
	 	set acceptable {}
	 	foreach v [lsort -command {package vcompare} \
	 		       -decreasing [package versions $pkg]] {
	 	    if {![package vatisfies $v {expand}$args]} {
	 		continue

	 	    }
	 	    if {[package prefer] eq "latest"
	 		    || ![string match {*[ab]*} $v]} {
	 		# Error handling omitted here













	 		uplevel #0 [package ifneeded $pkg $v]
	 		return $v



	 	    }
	 	    lappend acceptable $v
	 	}
	 	if {[incr pass -1]} {
	 	    # use [package unknown] to find more versions
	 	}
	    }
	    if {[llength $acceptable]} {
	 	# Accept best satisfactory alpha/beta even
	 	# though our preference mode is "stable"
	 	set v [lindex $acceptable 0]
	 	uplevel #0 [package ifneeded $pkg $v]
	 	return $v
	    }
	    return -code error "can't find $pkg $args"
	 }

# Copyright

This document has been placed in the public domain.

Name change from tip/269.tip to tip/269.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

TIP:		269
Title:		Add 'string is list' to the 'string is' Subcommand
Version:	$Revision: 1.7 $
Author:		Joe Mistachkin <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	19-May-2006
Keywords:	Tcl,lists,strings
Tcl-Version:	8.5
Post-History:	


~ Abstract

The '''string''' command supports tests for a number of Tcl's basic types, for
example, integers, doubles, and booleans. This TIP proposes adding lists to
the set of things that can be checked for.

~ Rationale

The '''string''' command includes tests for the common Tcl types: '''string is
boolean''', '''string is double''' and '''string is integer'''.
Unaccountably, '''string is list''' is missing from the list, making it
difficult for an input validation procedure to determine whether, in fact, a
string contains a proper list.

Currently, something similar to the following incantation is required:

| set is_list [expr {![catch {llength $str}]}]

The above construct (and others like it) are extremely counterintuitive,
especially to people without intimate knowledge of Tcl.

Compare and contrast with:

| set is_list [string is list $str]

Since '''string is''' currently serves in this capacity for determining
whether a string can be correctly interpreted as an integer or double, it
seems only natural to extend it so that it can determine whether a string can
be correctly interpreted as a list.

~ Specification

This document proposes augmenting the '''string is''' command with a '''string
is list''' subcommand, as follows:

 > '''string''' '''is''' '''list''' ?'''-strict'''? ?'''-failindex''' ''var''? ''str''

The result will be '''1''' if the string has proper list structure; otherwise,
it will be '''0'''. The option '''-strict''' is accepted for syntactic
compatability with other forms of '''string is''' but has no effect since
empty strings are proper lists.

~ Reference Implementation

A reference implementation of this TIP is available
[http://sf.net/tracker/?func=detail&aid=1491459&group_id=10894&atid=310894].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|

|
|
|





|

|




|

|




|

|
|

|

|
|
|


|


|

|


>

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

# TIP 269: Add 'string is list' to the 'string is' Subcommand

	Author:		Joe Mistachkin <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	19-May-2006
	Keywords:	Tcl,lists,strings
	Tcl-Version:	8.5
	Post-History:	
-----

# Abstract

The **string** command supports tests for a number of Tcl's basic types, for
example, integers, doubles, and booleans. This TIP proposes adding lists to
the set of things that can be checked for.

# Rationale

The **string** command includes tests for the common Tcl types: **string is
boolean**, **string is double** and **string is integer**.
Unaccountably, **string is list** is missing from the list, making it
difficult for an input validation procedure to determine whether, in fact, a
string contains a proper list.

Currently, something similar to the following incantation is required:

	 set is_list [expr {![catch {llength $str}]}]

The above construct \(and others like it\) are extremely counterintuitive,
especially to people without intimate knowledge of Tcl.

Compare and contrast with:

	 set is_list [string is list $str]

Since **string is** currently serves in this capacity for determining
whether a string can be correctly interpreted as an integer or double, it
seems only natural to extend it so that it can determine whether a string can
be correctly interpreted as a list.

# Specification

This document proposes augmenting the **string is** command with a **string
is list** subcommand, as follows:

 > **string** **is** **list** ?**-strict**? ?**-failindex** _var_? _str_

The result will be **1** if the string has proper list structure; otherwise,
it will be **0**. The option **-strict** is accepted for syntactic
compatability with other forms of **string is** but has no effect since
empty strings are proper lists.

# Reference Implementation

A reference implementation of this TIP is available
<http://sf.net/tracker/?func=detail&aid=1491459&group_id=10894&atid=310894> .

# Copyright

This document has been placed in the public domain.

Name change from tip/27.tip to tip/27.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

251
252
253

254
255
256
257
258
259
260
261

262
263
264
265
266
267
268

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307

TIP:            27
Title:          CONST Qualification on Pointers in Tcl API's
Version:        $Revision: 1.6 $
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        25-Feb-2001
Post-History:   
Discussions-To: news:comp.lang.tcl,mailto:[email protected]
Tcl-Version:    8.4


~ Abstract

Many of the C and C++ interfaces to the Tcl library lack a CONST
qualifier on the parameters that accept pointers, even though they do
not, in fact, modify the data that the pointers designate.  This lack
causes a persistent annoyance to C/C++ programmers.  Not only is the
code needed to work around this problem more verbose than required; it
also can lead to compromises in type safety.  This TIP proposes that
the C interfaces for Tcl be revised so that functions that accept
pointers to constant data have type signatures that reflect the fact.
The new interfaces will remain backward-compatible with the old,
except that a few must be changed to return pointers to CONST data.
(Changes of this magnitude, in the past, have been routine in minor
releases; the author of this TIP does not see a compelling reason to
wait for Tcl 9.0 to clean up these API's.)

~ Rationale

When the Tcl library was originally written, the ANSI C standard had
yet to be widely accepted, and the ''de facto'' standard language did
not support a ''const'' qualifier.  For this reason, none of the older
Tcl API's that accept pointers have CONST qualifiers, even when it is
known that the objects will not be modified.

In interfacing with other systems whose API's were designed after the
ANSI C standard, this limitation becomes annoying.  Code like:

| const char* const string = " ... whatever ... ";
| Tcl_SetStringObj( Tcl_GetObjResult( interp ),
|                   (char*) string, /* Have to cast away
|                                    * const-ness here
|                                    * even though the string
|                                    * will only be copied
|                                    */
|                   -1 );

is more verbose than necessary.  It is also unsafe: the cast allows a
number of unsafe type conversions (the author of this TIP has had to
debug at least one extension where an integer was cast to a character
pointer in this context).

In an C++ environment where engineering practice forbids using C-style
cast syntax, the syntax gets even more annoying, although it provides
improved safety.  C++ code analogous to the above snippet looks like:

| const char* const string = "...whatever...";
| Tcl_SetStringObj( Tcl_GetObjResult( interp ),
|                   const_cast< char* >( string ), -1 );

This code is hardly a paragon of readability.

The popular Gnu C compiler also has a problem with the ''char *''
declaration of so many of the parameters.  With the default set of
compilation options, a call like:

| Tcl_SetStringObj( Tcl_GetObjResult( interp ),
|                   "Hello world!", -1 );

results in an error; suppressing this message requires either using
the obscure option ''-fwritable-strings'' on the compiler command
line, or else applying awkward (and unsafe) cast syntax:

| Tcl_SetStringObj( Tcl_GetObjResult( interp ),
|                   const_cast< char* >( "Hello, world!" ), -1 );

Introducing CONST on parameters, however, does not bring in any
incompatibility; as long as there is a prototype in scope, any
ANSI-compliant compiler will implicitly cast non-CONST arguments to be
type-compatible with CONST formal parameters.

~ Specification

This TIP proposes that, wherever possible, Tcl API's that accept
pointers to constant data have their signatures in ''tcl.decls'' and
the corresponding source files adjusted to add the CONST qualifier.

The change introduces a potential incompatibility in that code
compiled on a (hypothetical) architecture where pointers to constant
data have a different representation from those to non-constant
data will not load against the revised stub table.  This incompatibility
is, in fact, not thought to be a problem, since no known port of
Tcl has encountered such an architecture.

If we confine the scope of this TIP to adding CONST only to
parameters, we preserve complete compatibility with existing
implementations.  It is neither possible nor desirable, however, to
preserve drop-in compatibility across all the API's.  The earliest
example in the stub table is the ''Tcl_PkgRequireEx'' function.  This
function is declared to return ''char *''; the pointer it returns,
however, is into memory managed by the Tcl library.  Any attempt by an
extension to scribble on this memory or free it will result in
corruption of Tcl's internal data structures; it is therefore safer
and more informative to return ''CONST char *''.  (This particular
example is also highly unlikely to break any existing extension; the
author of this TIP has yet to see one actually use the return value.)

Some of the API's, such as ''Tcl_GetStringFromObj'', will continue to
return pointers into writable memory inside the Tcl library.
''Tcl_GetStringFromObj'', for instance, deals with memory that is
managed co-operatively between extensions and the Tcl library; one
simply must trust extensions to do the right thing (for instance, not
overwrite the string representation of a shared object).

Some of the API's will not be modified, even though they appear to
accept constant strings.  For instance, ''Tcl_Eval'' modifies its
string argument while it is parsing it, even though it restores its
initial content when it returns.  This behavior has sufficient impact
on performance that it is probably not desirable to change it.  The
cases where the Tcl library does this sort of temporary modification,
however, must be documented in the programmers' manual.  They affect
thread safety and positioning of data in read-only memory.  One can
foresee that cleaning up the API's that do not suffer from
this problem will mean that programmers will be  less tempted
to use unsafe casts on the ones that remain.

Finally, there are a handful of API's that are essentially impossible
to clean up portably; the ones that accept variable arguments come to
mind.  These will be left alone.  One particular case in point is
''Tcl_SetResult'': its third argument determines whether its second
argument is constant or non-constant.  In an environment without
writable strings, a call like:

|    Tcl_SetResult( interp, "Hello, world!", TCL_STATIC );

or

|    Tcl_SetResult( interp, "Hello, world!", TCL_VOLATILE );

cannot be handled without unsafe casting.  Fortunately, several
alternatives are available.  The most attractive appears to be:

|    Tcl_SetObjResult( interp, 
|                      Tcl_NewStringObj( "Hello, world!", -1 ) );

which is also more informative about what is really going on.  Note
that ''TCL_STATIC'' no longer actually carries the static pointer
around.  Although ''Tcl_SetResult'' appears to do so, as soon as the
command returns, code in ''tclExecute.c'' converts the string result
into an object result by calling ''Tcl_GetObjResult''.  The code using
''Tcl_SetObjResult'' therefore carries no greater performance cost
than the original ''Tcl_SetResult''.

~ Reference Implementation

The changes described in this TIP cut across too many functional areas
to be implemented effectively all at once.  Several people have
pointed out that implementing this cleanup all at once appears to be
necessary to avoid "CONST pollution," where the library becomes full
of code that casts away the CONST qualifier.  To study this issue, the
author has conducted the experiment of imposing CONST strings on the
first API in the stubs table: ''Tcl_PkgProvideEx''.

The first concern that arose was that several other functions used the
CONST strings passed as parameters, and these functions also needed to
be updated. Fortunately, all were static within ''tclPkg.c''.  Next,
when updating the documentation, the author discovered that five other
functions were documented in the same man page, and shared a common
defintion of the ''package'' and ''version'' parameters.  They, too,
were included in the change, and once again, the change was propagated
forward into the functions that they called.  (This activity is where
the issue of replacing ''Tcl_SetResult'' with ''Tcl_SetObjResult'' was
detected.)

When replacing ''Tcl_SetResult'' with ''Tcl_SetObjResult'', the author
discovered that the ''file'' parameter to ''Tcl_DbNewStringObj'' was
also a constant string.  With more enthusiasm than caution, he decided
to attack the corresponding parameter in all the ''TCL_MEM_DEBUG''
interfaces.  (In retrospect, it would probably have been easier to
tackle this issue separately.)  This change wound up
cutting across virtually all of the external interfaces to
''tclStringObj.c'' and ''tclBinary.c'' and the associated
documentation.

The author expects that many of the other API's will be much less
closely coupled than the one studied. In particular, now that the
interfaces of ''tclStringObj.c'' have been done once, they don't need
to be done again!  In fact, starting with the interfaces, like
''tclStringObj.c'', that are used pervasively throughout the library
and working outward would certainly have been a better course of
action than tracing the dependencies forward from one function chosen
almost at random.

The result of the experimental change was that twenty-eight external
APIs, plus about a dozen static functions, needed to have the CONST
qualifier added to at least one pointer.  After these changes were
made, the test suite compiled, linked, and passed all regression tests
with all combinations of the NODEBUG and TCL_MEM_DEBUG options.  It
was nowhere necessary to cast away CONST-ness.  

Possible incompatibility with existing extensions was present
only in that the return values from the four functions,
''Tcl_PkgPresent'', ''Tcl_PkgPresentEx'', ''Tcl_PkgRequire'', and
''Tcl_PkgRequireEx'' had the CONST qualifier added.
 These four functions return pointers to memory
that must not be modified nor freed by the caller, so the CONST
qualifier is desirable, but existing extensions may depend on storing
the pointer in a variable that lacks the qualifier.
This level of incompatibility in a minor release has been
thought acceptable in the past; changes required to extensions
are trivial, and once changed, the extensions continue to back-port
cleanly to older releases.

An earlier version of these changes was uploaded to the SourceForge
patch manager as patch number 404026.  The revised version will be
added under the same patch number as soon as the author's technical
problems with uploading patches are resolved.  (The major difference
between the two patches is that the first patch implements the
two-Stub approach described under "Rejected alternatives" below.

The success of this change has convinced the author of this TIP that
the rest of the changes can be implemented in a staged manner, with
little source-level incompatibility being introduced for
extensions (and absolutely no incompatibility for stubs-enabled
extensions compiled and linked against earlier versions of the
library).

~ Rejected alternatives

The initial version of this TIP attempted to preserve backward
compatibility of stubs-enabled extensions, even on a hypothetical
architecture where pointer-to-constant and pointer-to-nonconstant
have different representations.

If this level of backward compatibility is desired,
it will be necessary to provide entries in the existing
stub table slots corresponding to the API's that lack the CONST
qualifiers.

The slots in the stub table corresponding to the non-CONST API's can
be filled with wrapper functions.  For example, the following function
definition of ''Tcl_SetStringObj_NONCONST'' will use the implicit
casting inherent in C to call the function with the new API.

|void
|Tcl_SetStringObj_NONCONST(Tcl_Obj* obj, /* Object to set */
|                          char* bytes,  /* String value to assign */
|                          int length)   /* Length of the string */
|{

|    Tcl_SetStringObj( obj, bytes, length );
|}


This sort of definition is so simple that ''tools/genStubs.tcl''
was extended in the original patch accompanying this TIP
to generate it.  For example, the declaration of
''Tcl_SetStringObj'' that once appeared as:

|declare 65 generic {
|    void Tcl_SetStringObj( Tcl_Obj* objPtr, char* bytes, int length )
|}


was replaced with:

|declare 458 -nonconst 65 generic {
|    void Tcl_SetStringObj( Tcl_Obj* objPtr, CONST char* bytes, int length )
|}


declaring that slot 458 in the stubs table is to be used for the new
API accepting a CONST char* for the string, while slot 65 remains used
for the legacy implementation.

The difficulty with this approach, which caused it to be
rejected, is that it introduces ''forward'' incompatibility.
Any extension compiled against header files from after the change
will fail to load against the stubs table from before the change.
This incompatibility would require extension authors to maintain
sets of header files for (at least) the earliest version of Tcl
that they intend to support, rather than always being able to compile
against the most current set.  This problem was thought to be worse
than the hypothetical and possibly non-existent problem of differing
pointer representations.

~ Procedural note

The intent of this TIP is that, if approved, it will empower
maintainers of individual modules to add ''CONST'' to any API
where it is appropriate, provided that:

   * the change does not introduce "CONST poisoning", that is,
     does not require type casts that remove CONST-ness;

   * the documentation of the API is updated to reflect the
     addition of the CONST qualifier; and

Individual TIP's detailing the changes to particular APIs shall
''not'' be required, provided that the changes comply with these
guidelines.

~ Change history

12 March 2001: Rejected the two-Stubs alternative and reworked
the patches to use only one Stub per modified function.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|






|

|

|


|
|






|
|
|
|
|
|
|
|


|

|

|

|

|
|
|



|



|
|


|
|

|
|






|


|



|









|
|



|

|

|

|

|
|


|













|



|



|




|
|


|
|
|
|
|
|

|







|



|


|

|
|
|

|
|

|
|
|

|




|

|








|




|
|












|






|

|

|













|


|
|
|
|
<
>
|
<
|
>
|


|

|
|
<
>



|
|
<
|
>

|



|



|





|


|









|


|




|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248

249
250

251
252
253
254
255
256
257
258
259

260
261
262
263
264
265

266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307

# TIP 27: CONST Qualification on Pointers in Tcl API's

	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        25-Feb-2001
	Post-History:   
	Discussions-To: news:comp.lang.tcl,mailto:[email protected]
	Tcl-Version:    8.4
-----

# Abstract

Many of the C and C\+\+ interfaces to the Tcl library lack a CONST
qualifier on the parameters that accept pointers, even though they do
not, in fact, modify the data that the pointers designate.  This lack
causes a persistent annoyance to C/C\+\+ programmers.  Not only is the
code needed to work around this problem more verbose than required; it
also can lead to compromises in type safety.  This TIP proposes that
the C interfaces for Tcl be revised so that functions that accept
pointers to constant data have type signatures that reflect the fact.
The new interfaces will remain backward-compatible with the old,
except that a few must be changed to return pointers to CONST data.
\(Changes of this magnitude, in the past, have been routine in minor
releases; the author of this TIP does not see a compelling reason to
wait for Tcl 9.0 to clean up these API's.\)

# Rationale

When the Tcl library was originally written, the ANSI C standard had
yet to be widely accepted, and the _de facto_ standard language did
not support a _const_ qualifier.  For this reason, none of the older
Tcl API's that accept pointers have CONST qualifiers, even when it is
known that the objects will not be modified.

In interfacing with other systems whose API's were designed after the
ANSI C standard, this limitation becomes annoying.  Code like:

	 const char* const string = " ... whatever ... ";
	 Tcl_SetStringObj( Tcl_GetObjResult( interp ),
	                   (char*) string, /* Have to cast away
	                                    * const-ness here
	                                    * even though the string
	                                    * will only be copied
	                                    */
	                   -1 );

is more verbose than necessary.  It is also unsafe: the cast allows a
number of unsafe type conversions \(the author of this TIP has had to
debug at least one extension where an integer was cast to a character
pointer in this context\).

In an C\+\+ environment where engineering practice forbids using C-style
cast syntax, the syntax gets even more annoying, although it provides
improved safety.  C\+\+ code analogous to the above snippet looks like:

	 const char* const string = "...whatever...";
	 Tcl_SetStringObj( Tcl_GetObjResult( interp ),
	                   const_cast< char* >( string ), -1 );

This code is hardly a paragon of readability.

The popular Gnu C compiler also has a problem with the _char \*_
declaration of so many of the parameters.  With the default set of
compilation options, a call like:

	 Tcl_SetStringObj( Tcl_GetObjResult( interp ),
	                   "Hello world!", -1 );

results in an error; suppressing this message requires either using
the obscure option _-fwritable-strings_ on the compiler command
line, or else applying awkward \(and unsafe\) cast syntax:

	 Tcl_SetStringObj( Tcl_GetObjResult( interp ),
	                   const_cast< char* >( "Hello, world!" ), -1 );

Introducing CONST on parameters, however, does not bring in any
incompatibility; as long as there is a prototype in scope, any
ANSI-compliant compiler will implicitly cast non-CONST arguments to be
type-compatible with CONST formal parameters.

# Specification

This TIP proposes that, wherever possible, Tcl API's that accept
pointers to constant data have their signatures in _tcl.decls_ and
the corresponding source files adjusted to add the CONST qualifier.

The change introduces a potential incompatibility in that code
compiled on a \(hypothetical\) architecture where pointers to constant
data have a different representation from those to non-constant
data will not load against the revised stub table.  This incompatibility
is, in fact, not thought to be a problem, since no known port of
Tcl has encountered such an architecture.

If we confine the scope of this TIP to adding CONST only to
parameters, we preserve complete compatibility with existing
implementations.  It is neither possible nor desirable, however, to
preserve drop-in compatibility across all the API's.  The earliest
example in the stub table is the _Tcl\_PkgRequireEx_ function.  This
function is declared to return _char \*_; the pointer it returns,
however, is into memory managed by the Tcl library.  Any attempt by an
extension to scribble on this memory or free it will result in
corruption of Tcl's internal data structures; it is therefore safer
and more informative to return _CONST char \*_.  \(This particular
example is also highly unlikely to break any existing extension; the
author of this TIP has yet to see one actually use the return value.\)

Some of the API's, such as _Tcl\_GetStringFromObj_, will continue to
return pointers into writable memory inside the Tcl library.
_Tcl\_GetStringFromObj_, for instance, deals with memory that is
managed co-operatively between extensions and the Tcl library; one
simply must trust extensions to do the right thing \(for instance, not
overwrite the string representation of a shared object\).

Some of the API's will not be modified, even though they appear to
accept constant strings.  For instance, _Tcl\_Eval_ modifies its
string argument while it is parsing it, even though it restores its
initial content when it returns.  This behavior has sufficient impact
on performance that it is probably not desirable to change it.  The
cases where the Tcl library does this sort of temporary modification,
however, must be documented in the programmers' manual.  They affect
thread safety and positioning of data in read-only memory.  One can
foresee that cleaning up the API's that do not suffer from
this problem will mean that programmers will be  less tempted
to use unsafe casts on the ones that remain.

Finally, there are a handful of API's that are essentially impossible
to clean up portably; the ones that accept variable arguments come to
mind.  These will be left alone.  One particular case in point is
_Tcl\_SetResult_: its third argument determines whether its second
argument is constant or non-constant.  In an environment without
writable strings, a call like:

	    Tcl_SetResult( interp, "Hello, world!", TCL_STATIC );

or

	    Tcl_SetResult( interp, "Hello, world!", TCL_VOLATILE );

cannot be handled without unsafe casting.  Fortunately, several
alternatives are available.  The most attractive appears to be:

	    Tcl_SetObjResult( interp, 
	                      Tcl_NewStringObj( "Hello, world!", -1 ) );

which is also more informative about what is really going on.  Note
that _TCL\_STATIC_ no longer actually carries the static pointer
around.  Although _Tcl\_SetResult_ appears to do so, as soon as the
command returns, code in _tclExecute.c_ converts the string result
into an object result by calling _Tcl\_GetObjResult_.  The code using
_Tcl\_SetObjResult_ therefore carries no greater performance cost
than the original _Tcl\_SetResult_.

# Reference Implementation

The changes described in this TIP cut across too many functional areas
to be implemented effectively all at once.  Several people have
pointed out that implementing this cleanup all at once appears to be
necessary to avoid "CONST pollution," where the library becomes full
of code that casts away the CONST qualifier.  To study this issue, the
author has conducted the experiment of imposing CONST strings on the
first API in the stubs table: _Tcl\_PkgProvideEx_.

The first concern that arose was that several other functions used the
CONST strings passed as parameters, and these functions also needed to
be updated. Fortunately, all were static within _tclPkg.c_.  Next,
when updating the documentation, the author discovered that five other
functions were documented in the same man page, and shared a common
defintion of the _package_ and _version_ parameters.  They, too,
were included in the change, and once again, the change was propagated
forward into the functions that they called.  \(This activity is where
the issue of replacing _Tcl\_SetResult_ with _Tcl\_SetObjResult_ was
detected.\)

When replacing _Tcl\_SetResult_ with _Tcl\_SetObjResult_, the author
discovered that the _file_ parameter to _Tcl\_DbNewStringObj_ was
also a constant string.  With more enthusiasm than caution, he decided
to attack the corresponding parameter in all the _TCL\_MEM\_DEBUG_
interfaces.  \(In retrospect, it would probably have been easier to
tackle this issue separately.\)  This change wound up
cutting across virtually all of the external interfaces to
_tclStringObj.c_ and _tclBinary.c_ and the associated
documentation.

The author expects that many of the other API's will be much less
closely coupled than the one studied. In particular, now that the
interfaces of _tclStringObj.c_ have been done once, they don't need
to be done again!  In fact, starting with the interfaces, like
_tclStringObj.c_, that are used pervasively throughout the library
and working outward would certainly have been a better course of
action than tracing the dependencies forward from one function chosen
almost at random.

The result of the experimental change was that twenty-eight external
APIs, plus about a dozen static functions, needed to have the CONST
qualifier added to at least one pointer.  After these changes were
made, the test suite compiled, linked, and passed all regression tests
with all combinations of the NODEBUG and TCL\_MEM\_DEBUG options.  It
was nowhere necessary to cast away CONST-ness.  

Possible incompatibility with existing extensions was present
only in that the return values from the four functions,
_Tcl\_PkgPresent_, _Tcl\_PkgPresentEx_, _Tcl\_PkgRequire_, and
_Tcl\_PkgRequireEx_ had the CONST qualifier added.
 These four functions return pointers to memory
that must not be modified nor freed by the caller, so the CONST
qualifier is desirable, but existing extensions may depend on storing
the pointer in a variable that lacks the qualifier.
This level of incompatibility in a minor release has been
thought acceptable in the past; changes required to extensions
are trivial, and once changed, the extensions continue to back-port
cleanly to older releases.

An earlier version of these changes was uploaded to the SourceForge
patch manager as patch number 404026.  The revised version will be
added under the same patch number as soon as the author's technical
problems with uploading patches are resolved.  \(The major difference
between the two patches is that the first patch implements the
two-Stub approach described under "Rejected alternatives" below.

The success of this change has convinced the author of this TIP that
the rest of the changes can be implemented in a staged manner, with
little source-level incompatibility being introduced for
extensions \(and absolutely no incompatibility for stubs-enabled
extensions compiled and linked against earlier versions of the
library\).

# Rejected alternatives

The initial version of this TIP attempted to preserve backward
compatibility of stubs-enabled extensions, even on a hypothetical
architecture where pointer-to-constant and pointer-to-nonconstant
have different representations.

If this level of backward compatibility is desired,
it will be necessary to provide entries in the existing
stub table slots corresponding to the API's that lack the CONST
qualifiers.

The slots in the stub table corresponding to the non-CONST API's can
be filled with wrapper functions.  For example, the following function
definition of _Tcl\_SetStringObj\_NONCONST_ will use the implicit
casting inherent in C to call the function with the new API.

	void
	Tcl_SetStringObj_NONCONST(Tcl_Obj* obj, /* Object to set */
	                          char* bytes,  /* String value to assign */
	                          int length)   /* Length of the string */

	{
	    Tcl_SetStringObj( obj, bytes, length );

	}

This sort of definition is so simple that _tools/genStubs.tcl_
was extended in the original patch accompanying this TIP
to generate it.  For example, the declaration of
_Tcl\_SetStringObj_ that once appeared as:

	declare 65 generic {
	    void Tcl_SetStringObj( Tcl_Obj* objPtr, char* bytes, int length )

	}

was replaced with:

	declare 458 -nonconst 65 generic {
	    void Tcl_SetStringObj( Tcl_Obj* objPtr, CONST char* bytes, int length )

	}

declaring that slot 458 in the stubs table is to be used for the new
API accepting a CONST char\* for the string, while slot 65 remains used
for the legacy implementation.

The difficulty with this approach, which caused it to be
rejected, is that it introduces _forward_ incompatibility.
Any extension compiled against header files from after the change
will fail to load against the stubs table from before the change.
This incompatibility would require extension authors to maintain
sets of header files for \(at least\) the earliest version of Tcl
that they intend to support, rather than always being able to compile
against the most current set.  This problem was thought to be worse
than the hypothetical and possibly non-existent problem of differing
pointer representations.

# Procedural note

The intent of this TIP is that, if approved, it will empower
maintainers of individual modules to add _CONST_ to any API
where it is appropriate, provided that:

   * the change does not introduce "CONST poisoning", that is,
     does not require type casts that remove CONST-ness;

   * the documentation of the API is updated to reflect the
     addition of the CONST qualifier; and

Individual TIP's detailing the changes to particular APIs shall
_not_ be required, provided that the changes comply with these
guidelines.

# Change history

12 March 2001: Rejected the two-Stubs alternative and reworked
the patches to use only one Stub per modified function.

# Copyright

This document has been placed in the public domain.

Name change from tip/270.tip to tip/270.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163

TIP:            270
Title:          Utility C Routines for String Formatting
Version:        $Revision: 1.10 $
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        19-Jun-2006
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes new public C utility routines for the convenience of C-coded
extensions and embedded uses of Tcl.

~ Background

During development of Tcl 8.5, several internal routines have been created
that provide useful string formatting functions. These routines are most
commonly used in the construction of error messages, but have a generally
useful nature. The Tcl source code itself makes significant use of them.

Making some of these routines public also addresses
Feature Request 1184069.

~ Proposed Changes

Add the following routines to Tcl's public interface:

~~ Tcl_AppendObjToErrorInfo

 > void '''Tcl_AppendObjToErrorInfo'''(Tcl_Interp *''interp'',
   Tcl_Obj *''objPtr'')

This routine is analogous to the existing routine '''Tcl_AddErrorInfo''',
but permits appending a Tcl_Obj value rather than requiring
a '''(const char *)'''.

~~ Tcl_AppendLimitedToObj

 > void '''Tcl_AppendLimitedToObj'''(Tcl_Obj *''objPtr'', const char *''bytes'',
   int ''length'', int ''limit'', const char *''ellipsis'')

This routine is used to append a string, but to impose a limit on how many
bytes are appended. This can be handy when the string to be appended might be
very large, but the value being constructed should not be allowed to grow
without bound. A common usage is when constructing an error message, where the
end result should be kept short enough to be read. 

Bytes from ''bytes'' are appended to ''objPtr'', but no more than ''limit''
bytes total are to be appended. If the limit prevents all ''length'' bytes
that are available from being appended, then the appending is done so that
the last bytes appended are from the string ''ellipsis''. This allows for
an indication of the truncation to be left in the string.

When ''length'' is -1, all bytes up to the first zero byte are appended,
subject to the limit. When ''ellipsis'' is NULL, the default string '''...'''
is used. When ''ellipsis'' is non-NULL, it must point to a zero-byte-terminated
string in Tcl's internal UTF encoding.  The number of bytes appended can
be less than the lesser of ''length'' and ''limit'' when appending fewer
bytes is necessary to append only whole multi-byte characters.

The ''objPtr'' must be unshared, or the attempt to append to it will panic.

~~ Tcl_Format

 > Tcl_Obj * '''Tcl_Format'''(Tcl_Interp *''interp'',
   const char *''format'', int ''objc'', Tcl_Obj *const ''objv''[])

This routine is the C-level interface to the engine of Tcl's '''format'''
command.  The actual command procedure for '''format''' is little more
than

| Tcl_Format(interp, Tcl_GetString(objv[1]), objc-2, objv+2);

The ''objc'' Tcl_Obj values in ''objv'' are formatted into a string
according to the conversion specification in ''format'' argument, following
the documentation for the '''format''' command.  The resulting formatted
string is converted to a new Tcl_Obj with refcount of zero and returned.
If some error happens during production of the formatted string, NULL is
returned, and an error message is recorded in ''interp'', if ''interp''
is non-NULL.

~~ Tcl_AppendFormatToObj

 > int '''Tcl_AppendFormatToObj'''(Tcl_Interp *''interp'', Tcl_Obj *''objPtr'',
   const char *''format'', int ''objc'', Tcl_Obj *const ''objv''[])

This routine is an appending alternative form of '''Tcl_Format'''.  Its
function is equivalent to:

| Tcl_Obj *newPtr = Tcl_Format(interp, format, objc, objv);
| if (newPtr == NULL) return TCL_ERROR;
| Tcl_AppendObjToObj(objPtr, newPtr);
| return TCL_OK;

But it is more convenient and efficient when the appending functionality
is needed.

The ''objPtr'' must be unshared, or the attempt to append to it will panic.

~~ Tcl_ObjPrintf

 > Tcl_Obj * '''Tcl_ObjPrintf'''(const char *''format'', ...)

This routine serves as a replacement for the common sequence:

| char buf[SOME_SUITABLE_LENGTH];
| sprintf(buf, format, ...);
| Tcl_NewStringObj(buf, -1);

Use of the proposed routine is shorter and doesn't require the programmer to
determine '''SOME_SUITABLE_LENGTH'''. The formatting is done with the same
core formatting engine used by '''Tcl_Format'''.  This means the set of
supported conversion specifiers is that of Tcl's '''format''' command and
not that of ''sprintf()'' where the two sets differ. When a conversion
specifier passed to '''Tcl_ObjPrintf''' includes a precision, the value is
taken as a number of bytes, as ''sprintf()'' does, and not as a number of
characters, as '''format''' does.  This is done on the assumption that C
code is more likely to know how many bytes it is passing around than the
number of encoded characters those bytes happen to represent.
The variable number of arguments passed in should be of the types that would
be suitable for passing to ''sprintf()''.  Note in this example usage, ''x''
is of type '''long'''.

|  long x = 5;
|  Tcl_Obj *objPtr = Tcl_ObjPrintf("Value is %d", x);

If the value of ''format'' contains internal inconsistencies or invalid
specifier formats, the formatted string result produced by 
'''Tcl_ObjPrintf''' will be an error message instead of any
attempt to Do What Is Meant.

~~ Tcl_AppendPrintfToObj

 > void '''Tcl_AppendPrintfToObj'''(Tcl_Obj *''objPtr'',
   const char *''format'', ...)

This routine is an appending alternative form of '''Tcl_ObjPrintf'''.  Its
function is equivalent to:

| Tcl_AppendObjToObj(objPtr, Tcl_ObjPrintf(format, ...));

But it is more convenient and efficient when the appending functionality
is needed.

The ''objPtr'' must be unshared, or the attempt to append to it will panic.

~ Compatibility

This proposal includes only new features. It is believed that existing scripts
and C code that operate without errors will continue to do so.

~ Reference Implementation

The actual code is already complete as internal routines corresponding to the
proposed public routines. Implementation is just an exercise in renaming,
placing in stub tables, documentation, etc.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|




|









|



|

|
|

|
|
|

|

|
|







|
|

|


|
|
|

|


|

|

|
|

|
|


|

|
|
|
|

|


|

|
|

|


|
|
|
|




|

|

|



|
|
|


|
|
|
|
|
|
|



|
|

|
|

|

|


|

|
|

|


|




|

|




|





|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163

# TIP 270: Utility C Routines for String Formatting

	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        19-Jun-2006
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes new public C utility routines for the convenience of C-coded
extensions and embedded uses of Tcl.

# Background

During development of Tcl 8.5, several internal routines have been created
that provide useful string formatting functions. These routines are most
commonly used in the construction of error messages, but have a generally
useful nature. The Tcl source code itself makes significant use of them.

Making some of these routines public also addresses
Feature Request 1184069.

# Proposed Changes

Add the following routines to Tcl's public interface:

## Tcl\_AppendObjToErrorInfo

 > void **Tcl\_AppendObjToErrorInfo**\(Tcl\_Interp \*_interp_,
   Tcl\_Obj \*_objPtr_\)

This routine is analogous to the existing routine **Tcl\_AddErrorInfo**,
but permits appending a Tcl\_Obj value rather than requiring
a **\(const char \*\)**.

## Tcl\_AppendLimitedToObj

 > void **Tcl\_AppendLimitedToObj**\(Tcl\_Obj \*_objPtr_, const char \*_bytes_,
   int _length_, int _limit_, const char \*_ellipsis_\)

This routine is used to append a string, but to impose a limit on how many
bytes are appended. This can be handy when the string to be appended might be
very large, but the value being constructed should not be allowed to grow
without bound. A common usage is when constructing an error message, where the
end result should be kept short enough to be read. 

Bytes from _bytes_ are appended to _objPtr_, but no more than _limit_
bytes total are to be appended. If the limit prevents all _length_ bytes
that are available from being appended, then the appending is done so that
the last bytes appended are from the string _ellipsis_. This allows for
an indication of the truncation to be left in the string.

When _length_ is -1, all bytes up to the first zero byte are appended,
subject to the limit. When _ellipsis_ is NULL, the default string **...**
is used. When _ellipsis_ is non-NULL, it must point to a zero-byte-terminated
string in Tcl's internal UTF encoding.  The number of bytes appended can
be less than the lesser of _length_ and _limit_ when appending fewer
bytes is necessary to append only whole multi-byte characters.

The _objPtr_ must be unshared, or the attempt to append to it will panic.

## Tcl\_Format

 > Tcl\_Obj \* **Tcl\_Format**\(Tcl\_Interp \*_interp_,
   const char \*_format_, int _objc_, Tcl\_Obj \*const _objv_[]\)

This routine is the C-level interface to the engine of Tcl's **format**
command.  The actual command procedure for **format** is little more
than

	 Tcl_Format(interp, Tcl_GetString(objv[1]), objc-2, objv+2);

The _objc_ Tcl\_Obj values in _objv_ are formatted into a string
according to the conversion specification in _format_ argument, following
the documentation for the **format** command.  The resulting formatted
string is converted to a new Tcl\_Obj with refcount of zero and returned.
If some error happens during production of the formatted string, NULL is
returned, and an error message is recorded in _interp_, if _interp_
is non-NULL.

## Tcl\_AppendFormatToObj

 > int **Tcl\_AppendFormatToObj**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_objPtr_,
   const char \*_format_, int _objc_, Tcl\_Obj \*const _objv_[]\)

This routine is an appending alternative form of **Tcl\_Format**.  Its
function is equivalent to:

	 Tcl_Obj *newPtr = Tcl_Format(interp, format, objc, objv);
	 if (newPtr == NULL) return TCL_ERROR;
	 Tcl_AppendObjToObj(objPtr, newPtr);
	 return TCL_OK;

But it is more convenient and efficient when the appending functionality
is needed.

The _objPtr_ must be unshared, or the attempt to append to it will panic.

## Tcl\_ObjPrintf

 > Tcl\_Obj \* **Tcl\_ObjPrintf**\(const char \*_format_, ...\)

This routine serves as a replacement for the common sequence:

	 char buf[SOME_SUITABLE_LENGTH];
	 sprintf(buf, format, ...);
	 Tcl_NewStringObj(buf, -1);

Use of the proposed routine is shorter and doesn't require the programmer to
determine **SOME\_SUITABLE\_LENGTH**. The formatting is done with the same
core formatting engine used by **Tcl\_Format**.  This means the set of
supported conversion specifiers is that of Tcl's **format** command and
not that of _sprintf\(\)_ where the two sets differ. When a conversion
specifier passed to **Tcl\_ObjPrintf** includes a precision, the value is
taken as a number of bytes, as _sprintf\(\)_ does, and not as a number of
characters, as **format** does.  This is done on the assumption that C
code is more likely to know how many bytes it is passing around than the
number of encoded characters those bytes happen to represent.
The variable number of arguments passed in should be of the types that would
be suitable for passing to _sprintf\(\)_.  Note in this example usage, _x_
is of type **long**.

	  long x = 5;
	  Tcl_Obj *objPtr = Tcl_ObjPrintf("Value is %d", x);

If the value of _format_ contains internal inconsistencies or invalid
specifier formats, the formatted string result produced by 
**Tcl\_ObjPrintf** will be an error message instead of any
attempt to Do What Is Meant.

## Tcl\_AppendPrintfToObj

 > void **Tcl\_AppendPrintfToObj**\(Tcl\_Obj \*_objPtr_,
   const char \*_format_, ...\)

This routine is an appending alternative form of **Tcl\_ObjPrintf**.  Its
function is equivalent to:

	 Tcl_AppendObjToObj(objPtr, Tcl_ObjPrintf(format, ...));

But it is more convenient and efficient when the appending functionality
is needed.

The _objPtr_ must be unshared, or the attempt to append to it will panic.

# Compatibility

This proposal includes only new features. It is believed that existing scripts
and C code that operate without errors will continue to do so.

# Reference Implementation

The actual code is already complete as internal routines corresponding to the
proposed public routines. Implementation is just an exercise in renaming,
placing in stub tables, documentation, etc.

# Copyright

This document has been placed in the public domain.

Name change from tip/271.tip to tip/271.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

TIP:            271
Title:          Windows-Style Open and Save File Dialog on Unix
Version:        $Revision: 1.5 $
Author:         Matthew Middleton <[email protected]>
Author:         susanta kumar mishra <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        11-Jul-2006
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP describes updates to the Unix file dialogs to make them more like the
dialogs found on the Windows platform. This increases the usability of the
dialog for general "power" users.

~ Rationale

It is nice to have a windows-type file dialog for Unix applications that wish
to have a Windows appearance. This makes the experience much smoother for
end-users that are experienced with the Windows file dialogs, which is an
extremely common case these days.

It has convienent attributes of being able to reorder file lists by name,
type, size, and date. It also has the typical cut, copy, paste, rename,
delete, new directory and properties selections.

Box selecting is also possible with the multiple option. As much functionality
as possible was included to match the windows dialog. Some things were left
out, such as the panel at the left of a typical windows dialog that contains
buttons that allow quick change to such things as "My Documents, and "My
Computer".

~ Reference Implementation

The source code has been included as script files. All of this was done at the
Tcl script level, and can be found in Patch 1520742 (currently written against
Tcl/Tk 8.4.12).
[http://sf.net/tracker/?func=detail&aid=1520742&group_id=12997&atid=312997]
Listing of modified/new files:

|tkfbox.tcl
|choosedir.tcl
|tkfprops.tcl
|Tkfprops.html
|ResizeButs.tcl
|ResizeButs.html

Two new megawidgets have been developed for these changes. They are
'''ResizeButs''' which is a button-alike specialized for acting as the heading
of a column or row of data, and '''tk_fileProperties'' which is a popup window
for viewing and editing file metadata.

~ Specification

The '''tk_getOpenFile''' and '''tk_getSaveFile''' have been greatly improved
to function much like a Windows file dialog (circa Windows 2000), when the
default dialogs are overridden. This is most useful on Unix systems where the
application is wanted to have a Windows-like appearance, but it will also
function on Windows. I have not been able to test on Macintosh.

This also affects '''tk_chooseDirectory''' when the default dialogs are
overridden, as that is also implemented in ''tkfbox.tcl''.

The dialogs will work without the BWidget package, but it will have more
functionality and look more like a windows dialog if BWidgets are available.
The only thing it really needs from BWidgets is the '''ComboBox''' widget. If
this were included in regular Tk, then BWidgets would not be needed. It also
uses the balloon messages of the "Button" widget from BWidgets.

This new file dialog widget requires two of the new widgets included -
'''ResizeButs''' and '''tk_fileProperties''', which are autoloaded from
''ResizeButs.tcl'' and ''tkfprops.tcl'' respectively. The two tcl files that
define these widgets are included, along with documentation on each one.

The file ''choosedir.tcl'' is also included. It is needed to work with the
modified ''tkfbox.tcl''.

~~ Functionality Outline

Added functionality of the file dialog:

 1. Back directory button

 2. Create directory button

 3. Details button

 4. Delete button

 5. You can type the directory path at the top (requires BWidgets). Selecting
    "desktop" expands what's available on the desktop if used on Windows.

 > Right mouse clicking on a file gives these options:

 > 1. Cut

 > 2. Copy

 > 3. Delete

 > 4. Rename

 > 5. Properties (uses tk_fileProperties widget)

 > Right mouse clicking in open white space gives these options:

 > 1. View

 > 1. List

 > 2. Details

 > 2. Arrange Icons

 > > 1. By Name

 > > 2. By Size

 > > 3. By Type

 > > 4. By Date

 > 3. Refresh

 > 4. Paste (ungreys if Cut or Copy were previously selected on files)

 > 5. New Folder

 > 6. Properties (uses tk_fileProperties widget)

 6. Recent selected files can be shown by pressing the down arrow in the entry
    field of the selected file name (requires BWidgets). Recent file names are
    saved to a file named .tk_recent_selections in the users home directory.

 7. Box selecting of files can be done with the "multiple 1" option. Left
    mouse click and hold and drag a box over files.

 8. The busy was improved to actually block mouse clicks instead of just
    showing an hourglass widget.

 9. Popup button descriptions. (requires BWidgets)

 10. Icons shade as well as text when selected.

~~ Details View

The Details button grids 4 columns (name, file type, size, and modified
date). (This uses ResizeButs widget.)

Moving the mouse over the border between two buttons of the top column
headings and left mouse clicking while dragging will allow the user to change
the size of the columns.

Pressing one of the heading buttons changes the order of the data between
increasing and decreasing and displays a triangle in the button to indicate
the order.

~~ Additional Arguments to the tk_getOpenFile and tk_getSaveFile Commands

The ''dir_leaf'' arguments allow a folder to be selected as a file to select
it as a project. Providing a '''-dir_leaf_check''' procedure defines the file
dialog as a special type that only lists folders, but the folder that passes
the '''-dir_leaf_check''' procedure can be selected as a file.

 1. '''-dir_leaf_check''' ''commandName'' - This is the name of a procedure
    which checks if the directory qualifies as the kind that can be selected
    as a project file. It returns a non-zero number if it qualifies, otherwise
    it returns zero. The directory name to check will be appended as an
    argument to the procedure.

 2. '''-dir_leaf_image''' ''imageName'' - an image to use for the folder types
    that will be treated as files. It should be an image created with '''image
    create photo'''.

 3. '''-dir_leaf_label''' ''string'' - text that appears at the left of the
    entry for the selected file when the dialog is defined as a project folder
    selection type (when the '''-dir_leaf_check''' procedure is defined). Not
    localized by Tk.

 4. '''-extra_widgets_bottom''' ''commandName'' - This is the name of a
    procedure which packs or grids additional widgets at the bottom of the
    dialog. The window name of a frame widget at the bottom of the dialog is
    appended as an argument, and any further widgets that this procedure
    creates to be gridded should be a child window of this frame. If this
    procedure returns anything, it will be treated as a number to configrue
    the width of the Ok and Cancel buttons, since the additional widgets could
    possibly stretch these buttons to any length.

 5. '''-extra_widgets_side''' ''commandName'' - This is the name of a
    procedure which does the packing or gridding for additional widgets at the
    right side of the dialog. The frame window name at the right side of the
    dialog will be appended as an argument.

 6. '''-pick_func''' ''commandName'' - A procedure which will be done every
    time a file is selected (activated).  The full path of the file name will
    be appended as an argument to this procedure.

 7. '''-allow_nonexistent''' - If the command used is '''tk_getOpenFile''',
    this will allow the user to enter a nonexistent file name. This name will
    be returned from '''tk_getOpenFile''', but it will still not exist. It is
    the programmer's responsibility to create this file afterwards.

 8. '''-open_button_name''' ''string'' - Alternate text to use for the "Open"
    or "Save" button. Not localized by Tk.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|
















|


|
|
|


|
|
|
|
|
|


|
|


|

|
|




|
|



|




|
|


|
|

|











|


|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|


|
|







|



|

|
|









|

|
|

|

|





|
|
|

|

|


|








|




|
|


|

|


|


|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

# TIP 271: Windows-Style Open and Save File Dialog on Unix

	Author:         Matthew Middleton <[email protected]>
	Author:         susanta kumar mishra <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        11-Jul-2006
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP describes updates to the Unix file dialogs to make them more like the
dialogs found on the Windows platform. This increases the usability of the
dialog for general "power" users.

# Rationale

It is nice to have a windows-type file dialog for Unix applications that wish
to have a Windows appearance. This makes the experience much smoother for
end-users that are experienced with the Windows file dialogs, which is an
extremely common case these days.

It has convienent attributes of being able to reorder file lists by name,
type, size, and date. It also has the typical cut, copy, paste, rename,
delete, new directory and properties selections.

Box selecting is also possible with the multiple option. As much functionality
as possible was included to match the windows dialog. Some things were left
out, such as the panel at the left of a typical windows dialog that contains
buttons that allow quick change to such things as "My Documents, and "My
Computer".

# Reference Implementation

The source code has been included as script files. All of this was done at the
Tcl script level, and can be found in Patch 1520742 \(currently written against
Tcl/Tk 8.4.12\).
<http://sf.net/tracker/?func=detail&aid=1520742&group_id=12997&atid=312997> 
Listing of modified/new files:

	tkfbox.tcl
	choosedir.tcl
	tkfprops.tcl
	Tkfprops.html
	ResizeButs.tcl
	ResizeButs.html

Two new megawidgets have been developed for these changes. They are
**ResizeButs** which is a button-alike specialized for acting as the heading
of a column or row of data, and **tk\_fileProperties_ which is a popup window
for viewing and editing file metadata.

# Specification

The **tk\_getOpenFile** and **tk\_getSaveFile** have been greatly improved
to function much like a Windows file dialog \(circa Windows 2000\), when the
default dialogs are overridden. This is most useful on Unix systems where the
application is wanted to have a Windows-like appearance, but it will also
function on Windows. I have not been able to test on Macintosh.

This also affects **tk\_chooseDirectory** when the default dialogs are
overridden, as that is also implemented in _tkfbox.tcl_.

The dialogs will work without the BWidget package, but it will have more
functionality and look more like a windows dialog if BWidgets are available.
The only thing it really needs from BWidgets is the **ComboBox** widget. If
this were included in regular Tk, then BWidgets would not be needed. It also
uses the balloon messages of the "Button" widget from BWidgets.

This new file dialog widget requires two of the new widgets included -
**ResizeButs** and **tk\_fileProperties**, which are autoloaded from
_ResizeButs.tcl_ and _tkfprops.tcl_ respectively. The two tcl files that
define these widgets are included, along with documentation on each one.

The file _choosedir.tcl_ is also included. It is needed to work with the
modified _tkfbox.tcl_.

## Functionality Outline

Added functionality of the file dialog:

 1. Back directory button

 2. Create directory button

 3. Details button

 4. Delete button

 5. You can type the directory path at the top \(requires BWidgets\). Selecting
    "desktop" expands what's available on the desktop if used on Windows.

	 > Right mouse clicking on a file gives these options:

	 > 1. Cut

	 > 2. Copy

	 > 3. Delete

	 > 4. Rename

	 > 5. Properties \(uses tk\_fileProperties widget\)

	 > Right mouse clicking in open white space gives these options:

	 > 1. View

	 > 1. List

	 > 2. Details

	 > 2. Arrange Icons

	 > > 1. By Name

	 > > 2. By Size

	 > > 3. By Type

	 > > 4. By Date

	 > 3. Refresh

	 > 4. Paste \(ungreys if Cut or Copy were previously selected on files\)

	 > 5. New Folder

	 > 6. Properties \(uses tk\_fileProperties widget\)

 6. Recent selected files can be shown by pressing the down arrow in the entry
    field of the selected file name \(requires BWidgets\). Recent file names are
    saved to a file named .tk\_recent\_selections in the users home directory.

 7. Box selecting of files can be done with the "multiple 1" option. Left
    mouse click and hold and drag a box over files.

 8. The busy was improved to actually block mouse clicks instead of just
    showing an hourglass widget.

 9. Popup button descriptions. \(requires BWidgets\)

 10. Icons shade as well as text when selected.

## Details View

The Details button grids 4 columns \(name, file type, size, and modified
date\). \(This uses ResizeButs widget.\)

Moving the mouse over the border between two buttons of the top column
headings and left mouse clicking while dragging will allow the user to change
the size of the columns.

Pressing one of the heading buttons changes the order of the data between
increasing and decreasing and displays a triangle in the button to indicate
the order.

## Additional Arguments to the tk\_getOpenFile and tk\_getSaveFile Commands

The _dir\_leaf_ arguments allow a folder to be selected as a file to select
it as a project. Providing a **-dir\_leaf\_check** procedure defines the file
dialog as a special type that only lists folders, but the folder that passes
the **-dir\_leaf\_check** procedure can be selected as a file.

 1. **-dir\_leaf\_check** _commandName_ - This is the name of a procedure
    which checks if the directory qualifies as the kind that can be selected
    as a project file. It returns a non-zero number if it qualifies, otherwise
    it returns zero. The directory name to check will be appended as an
    argument to the procedure.

 2. **-dir\_leaf\_image** _imageName_ - an image to use for the folder types
    that will be treated as files. It should be an image created with **image
    create photo**.

 3. **-dir\_leaf\_label** _string_ - text that appears at the left of the
    entry for the selected file when the dialog is defined as a project folder
    selection type \(when the **-dir\_leaf\_check** procedure is defined\). Not
    localized by Tk.

 4. **-extra\_widgets\_bottom** _commandName_ - This is the name of a
    procedure which packs or grids additional widgets at the bottom of the
    dialog. The window name of a frame widget at the bottom of the dialog is
    appended as an argument, and any further widgets that this procedure
    creates to be gridded should be a child window of this frame. If this
    procedure returns anything, it will be treated as a number to configrue
    the width of the Ok and Cancel buttons, since the additional widgets could
    possibly stretch these buttons to any length.

 5. **-extra\_widgets\_side** _commandName_ - This is the name of a
    procedure which does the packing or gridding for additional widgets at the
    right side of the dialog. The frame window name at the right side of the
    dialog will be appended as an argument.

 6. **-pick\_func** _commandName_ - A procedure which will be done every
    time a file is selected \(activated\).  The full path of the file name will
    be appended as an argument to this procedure.

 7. **-allow\_nonexistent** - If the command used is **tk\_getOpenFile**,
    this will allow the user to enter a nonexistent file name. This name will
    be returned from **tk\_getOpenFile**, but it will still not exist. It is
    the programmer's responsibility to create this file afterwards.

 8. **-open\_button\_name** _string_ - Alternate text to use for the "Open"
    or "Save" button. Not localized by Tk.

# Copyright

This document has been placed in the public domain.

Name change from tip/272.tip to tip/272.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

TIP:		272
Title:		String and List Reversal Operations
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Post-History:	
Version:	$Revision: 1.4 $
Author:		Donal K. Fellows <[email protected]>
Created:	23-Aug-2006
Keywords:	Tcl, lreverse


~ Abstract

This TIP proposes adding commands to reverse the order of characters
in strings and elements in lists.

~ Rationale

According to a recent thread on news:comp.lang.tcl
[http://groups.google.com/group/comp.lang.tcl/browse_frm/thread/a0b8c98c00a31ffc],
there are a number of use cases for reversing strings and lists. While
it has always been possible to write Tcl code to do this, it has
typically been a fairly inefficient operation, and for some algorithms
(admittedly including ones that are benchmarked when comparing Tcl to
other languages) this can be the source of a painful slowdown. By
putting an efficient implementation in the Tcl core, we will speed up
quite a bit of code, more than I originally anticipated it seems; this
will make us look better to programmers without much experience with
the language too.

~ Proposed Change

I propose to add two commands, '''lreverse''' to reverse the order of
items in a list, and '''string reverse''' (a subcommand of
'''string''') to reverse the order of characters in a string. I do not
propose to provide any C-level API for performing these operations.

~~ The lreverse Command

This shall have the following syntax:

 > '''lreverse''' ''list''

It shall return a list that is the same as the input list but with the
elements in reverse order.

~~ The reverse Subcommand of the string Command

This shall have the following syntax:

 > '''string reverse''' ''string''

It shall return a string that is the same as the input string but with
the characters in reverse order. (Note that it shall also return a
byte array when the input is a byte array.)

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|




|


|



|
|





|

|
|
|


|



|




|



|


|
|

|


>

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

# TIP 272: String and List Reversal Operations
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	23-Aug-2006
	Keywords:	Tcl, lreverse
-----

# Abstract

This TIP proposes adding commands to reverse the order of characters
in strings and elements in lists.

# Rationale

According to a recent thread on news:comp.lang.tcl
<http://groups.google.com/group/comp.lang.tcl/browse_frm/thread/a0b8c98c00a31ffc> ,
there are a number of use cases for reversing strings and lists. While
it has always been possible to write Tcl code to do this, it has
typically been a fairly inefficient operation, and for some algorithms
\(admittedly including ones that are benchmarked when comparing Tcl to
other languages\) this can be the source of a painful slowdown. By
putting an efficient implementation in the Tcl core, we will speed up
quite a bit of code, more than I originally anticipated it seems; this
will make us look better to programmers without much experience with
the language too.

# Proposed Change

I propose to add two commands, **lreverse** to reverse the order of
items in a list, and **string reverse** \(a subcommand of
**string**\) to reverse the order of characters in a string. I do not
propose to provide any C-level API for performing these operations.

## The lreverse Command

This shall have the following syntax:

 > **lreverse** _list_

It shall return a list that is the same as the input list but with the
elements in reverse order.

## The reverse Subcommand of the string Command

This shall have the following syntax:

 > **string reverse** _string_

It shall return a string that is the same as the input string but with
the characters in reverse order. \(Note that it shall also return a
byte array when the input is a byte array.\)

# Copyright

This document has been placed in the public domain.

Name change from tip/273.tip to tip/273.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

TIP:		273
Title:		Add Tcl_Expr... Support to Tcl_Get... Functions
Version:	$Revision: 1.5 $
Author:		Carsten Gosvig <[email protected]>
State:		Rejected
Type:		Project
Vote:		Done
Created:	30-Aug-2006
Post-History:	
Tcl-Version:	8.5
Obsoletes:	176


~Abstract

This TIP proposes adding '''Tcl_Expr'''... calls to '''Tcl_Get'''... functions,
supporting direct use of expressions for arguments to commands that is defined
as int, long, wide-int, double or boolean.

~Rationale

Many of Tcl's commands takes an int, long, wide-int, double or boolean as an
argument. For list and string commands even in the format of '''end-'''''N''.
However, this is limited to a direct string conversion of the argument to one
of the mentioned types, so for even simple expression the '''expr''' command
has to be called explicitly, which is quite cumbersome as can be seen in the
following examples:

|set x [lsearch $list $elem]
|set new [lrange $list [expr $x-1] [expr $x+1]]
|
|set x [string first $string "foo"]
|set new [string range $string $x [expr [$x+5]]
|
|set x [lsearch $list $elem]
|set hex [format "%X" [expr {$x & 0xFF}]]
|
|set file [open $name]
|set buf [read $file [expr {$len * 2 - 10}]]
|
|incr var [expr $step*5+1]
|after [expr $sec*1000]

~Specification

By adding a call to a '''Tcl_Expr'''... function at the point where the
current conversion fails in the '''Tcl_Get'''... functions (at the label named
''bad'' in the current implementation) we will add support for using
expressions directly as arguments without needing to go through the '''expr'''
command:

|set x [lsearch $list $elem]
|set new [lrange $list $x-1 $x+1]
|
|set x [string first $string "foo"]
|set new [string range $string $x $x+5]
|
|set x [lsearch $list $elem]
|set hex [format "%X" {$x & 0xFF}]
|
|set file [open $name]
|set buf [read $file {$len * 2 - 10}]
|
|incr var $step*5+1
|after $sec*1000

This TIP does not propose any alterations to any function or procedure
signatures.

~~Implementation Notes

The '''Tcl_Get'''<''Type''> functions needs to be updated with a call to the
'''Tcl_Expr'''<''Type''> functions, and the
'''Tcl_Get'''<''Type''>'''FromObj''' functions need to be updated with a call
to the '''Tcl_Expr'''<''Type''>'''Obj''' functions.

~~Compatibility

There should be no compability issues, as this TIP only adds functionality to
a current error situation.

This proposal renders [176] obsolete, as that describes a solution that is
effectively a subset of this TIP.

~Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|


|

|



|
|
|
|
|
|
|
|
|
|
|
|
|
|

|

|
|
|
|


|
|
|
|
|
|
|
|
|
|
|
|
|
|




|

|
|
|
|

|




|


|


>

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

# TIP 273: Add Tcl_Expr... Support to Tcl_Get... Functions

	Author:		Carsten Gosvig <[email protected]>
	State:		Rejected
	Type:		Project
	Vote:		Done
	Created:	30-Aug-2006
	Post-History:	
	Tcl-Version:	8.5
	Obsoletes:	176
-----

# Abstract

This TIP proposes adding **Tcl\_Expr**... calls to **Tcl\_Get**... functions,
supporting direct use of expressions for arguments to commands that is defined
as int, long, wide-int, double or boolean.

# Rationale

Many of Tcl's commands takes an int, long, wide-int, double or boolean as an
argument. For list and string commands even in the format of **end-**_N_.
However, this is limited to a direct string conversion of the argument to one
of the mentioned types, so for even simple expression the **expr** command
has to be called explicitly, which is quite cumbersome as can be seen in the
following examples:

	set x [lsearch $list $elem]
	set new [lrange $list [expr $x-1] [expr $x+1]]
	
	set x [string first $string "foo"]
	set new [string range $string $x [expr [$x+5]]
	
	set x [lsearch $list $elem]
	set hex [format "%X" [expr {$x & 0xFF}]]
	
	set file [open $name]
	set buf [read $file [expr {$len * 2 - 10}]]
	
	incr var [expr $step*5+1]
	after [expr $sec*1000]

# Specification

By adding a call to a **Tcl\_Expr**... function at the point where the
current conversion fails in the **Tcl\_Get**... functions \(at the label named
_bad_ in the current implementation\) we will add support for using
expressions directly as arguments without needing to go through the **expr**
command:

	set x [lsearch $list $elem]
	set new [lrange $list $x-1 $x+1]
	
	set x [string first $string "foo"]
	set new [string range $string $x $x+5]
	
	set x [lsearch $list $elem]
	set hex [format "%X" {$x & 0xFF}]
	
	set file [open $name]
	set buf [read $file {$len * 2 - 10}]
	
	incr var $step*5+1
	after $sec*1000

This TIP does not propose any alterations to any function or procedure
signatures.

## Implementation Notes

The **Tcl\_Get**<_Type_> functions needs to be updated with a call to the
**Tcl\_Expr**<_Type_> functions, and the
**Tcl\_Get**<_Type_>**FromObj** functions need to be updated with a call
to the **Tcl\_Expr**<_Type_>**Obj** functions.

## Compatibility

There should be no compability issues, as this TIP only adds functionality to
a current error situation.

This proposal renders [[176]](176.md) obsolete, as that describes a solution that is
effectively a subset of this TIP.

# Copyright

This document has been placed in the public domain.

Name change from tip/274.tip to tip/274.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

TIP:            274
Title:          Right-Associativity for the Exponentiation Operator
Version:        $Revision: 1.9 $
Author:         Arjen Markus <[email protected]>
Author:         David Smith <[email protected]>
Author:         Richard Suchenwirth <[email protected]>
Author:         Don Porter <[email protected]>
Author:         S�rgio Loureiro <[email protected]>
State:          Final
Type:           Project
Vote:		Done
Created:        15-Sep-2006
Post-History:   
Keywords:       Tcl,expr
Tcl-Version:    8.5


~ Abstract

This TIP clarifies and corrects the associativity behaviour of the
exponentation operator that was introduced in [123].

~ Background

The exponentiation operator found in various programming languages has a
distinct right associativity. In this way it differs from the other arithmetic
operators. Some languages do implement with left-associativity but this is
felt to be awkward by many users.

[123] introduced an exponentiation operator into Tcl 8.5 and was quite
elaborate in defining its behaviour with respect to integer arguments, as
there are quite a few corner cases to be examined.

However, it was vague on the issue of associativity and in fact showed by one
example that the operator as implemented then was left-associative.

~ Rationale

A left-associative exponentiation operator is less useful than a
right-associative operator, as pointed out in the Wikipedia article
http://en.wikipedia.org/wiki/Associative . To illustrate, a left-associative
exponentiation operator behaves like this:

 > ''x'' '''**''' ''y'' '''**''' ''z'' = (''x'' '''**''' ''y'') '''**''' ''z''
   = ''x'' '''**''' (''y'' * ''z'')

Whereas a right-associative exponentiation operator behaves like this:

 > ''x'' '''**''' ''y'' '''**''' ''z'' = ''x'' '''**''' (''y'' '''**''' ''z'')

Thus, if the operator is left-associative, then the above expression can be
rewritten using a single exponentiation.

For this reason many programming languages and mathematical systems, among
these Fortran, Perl, Python, Scilab, Mathematica and Maple, have chosen
right-associativity. Several others, MATLAB and Octave, which is intended to
be compatible to MATLAB, use left-associativity. (Microsoft Excel also uses
left-associativity, but this product exhibits more quirky arithmetic behaviour
and therefore should not be considered as a serious factor, in at least one
author's opinion.)

~ Proposal

Therefore, given the expectation of programmers, the choice made in many
programming languages and mathematical systems and the arguments about the
limited usefulness of left-associativity, this TIP proposes to correct the
behaviour of the exponentiation operator.

It should be right-associative, so that:

| 2 ** 3 ** 4 = 2 ** (3 ** 4) = 2 ** 81 = 2417851639229258349412352

(and not 4096, if left-associativity is used)

~ Compatibility

No official version of Tcl 8.5 has been released yet. Existing "private"
extensions that define an exponentiation operator that we are aware of use the
right-associativity as well. Therefore this correction will only enhance
compatibility.

~ Copyright

This document is placed in the public domain

<
|
<
|
|
|
|
|
|
|
|
|
|
|
|
>

|


|

|






|






|



|


|
|



|







|


|

|








|

|

|






|


>

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

# TIP 274: Right-Associativity for the Exponentiation Operator

	Author:         Arjen Markus <[email protected]>
	Author:         David Smith <[email protected]>
	Author:         Richard Suchenwirth <[email protected]>
	Author:         Don Porter <[email protected]>
	Author:         Sérgio Loureiro <[email protected]>
	State:          Final
	Type:           Project
	Vote:		Done
	Created:        15-Sep-2006
	Post-History:   
	Keywords:       Tcl,expr
	Tcl-Version:    8.5
-----

# Abstract

This TIP clarifies and corrects the associativity behaviour of the
exponentation operator that was introduced in [[123]](123.md).

# Background

The exponentiation operator found in various programming languages has a
distinct right associativity. In this way it differs from the other arithmetic
operators. Some languages do implement with left-associativity but this is
felt to be awkward by many users.

[[123]](123.md) introduced an exponentiation operator into Tcl 8.5 and was quite
elaborate in defining its behaviour with respect to integer arguments, as
there are quite a few corner cases to be examined.

However, it was vague on the issue of associativity and in fact showed by one
example that the operator as implemented then was left-associative.

# Rationale

A left-associative exponentiation operator is less useful than a
right-associative operator, as pointed out in the Wikipedia article
<http://en.wikipedia.org/wiki/Associative> . To illustrate, a left-associative
exponentiation operator behaves like this:

 > _x_ **\*\*** _y_ **\*\*** _z_ = \(_x_ **\*\*** _y_\) **\*\*** _z_
   = _x_ **\*\*** \(_y_ \* _z_\)

Whereas a right-associative exponentiation operator behaves like this:

 > _x_ **\*\*** _y_ **\*\*** _z_ = _x_ **\*\*** \(_y_ **\*\*** _z_\)

Thus, if the operator is left-associative, then the above expression can be
rewritten using a single exponentiation.

For this reason many programming languages and mathematical systems, among
these Fortran, Perl, Python, Scilab, Mathematica and Maple, have chosen
right-associativity. Several others, MATLAB and Octave, which is intended to
be compatible to MATLAB, use left-associativity. \(Microsoft Excel also uses
left-associativity, but this product exhibits more quirky arithmetic behaviour
and therefore should not be considered as a serious factor, in at least one
author's opinion.\)

# Proposal

Therefore, given the expectation of programmers, the choice made in many
programming languages and mathematical systems and the arguments about the
limited usefulness of left-associativity, this TIP proposes to correct the
behaviour of the exponentiation operator.

It should be right-associative, so that:

	 2 ** 3 ** 4 = 2 ** (3 ** 4) = 2 ** 81 = 2417851639229258349412352

\(and not 4096, if left-associativity is used\)

# Compatibility

No official version of Tcl 8.5 has been released yet. Existing "private"
extensions that define an exponentiation operator that we are aware of use the
right-associativity as well. Therefore this correction will only enhance
compatibility.

# Copyright

This document is placed in the public domain

Name change from tip/275.tip to tip/275.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

TIP:            275
Title:          Support Unsigned Values in binary Command
Version:        $Revision: 1.5 $
Author:         Pat Thoyts <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        27-Sep-2006
Post-History:   
Keywords:       Tcl,binary,unsigned
Tcl-Version:    8.5


~ Abstract

This TIP proposes to add support for unsigned values to the '''binary'''
command.

~ Rationale

It is quite common when handling binary data to need to read unsigned values.
All values read in by '''binary scan''' are converted to integers and sign
extended, which requires code to trim the excess bits using the '''expr'''
command if the values need to be treated as unsigned values. This makes Tcl
slow when handling large quantities of binary data, for instance in
crytographic or checksum functions. Simply by avoiding this '''expr'''
operation we significantly improve the speed of processing such data.

~ Specification

The '''binary scan''' should be updated so as to add a flag identifier into
the binary field format. This makes the field specification:

 > <''type code''><''flag''>?<''length''>?

The flag character for unsigned fields (the only one defined) is "u", so the
following are all acceptable:

 cu*: read all bytes as unsigned

 c2cu2: two signed bytes then two unsigned bytes

 su2: two unsigned little-endian shorts

 Su: a single big-endian unsigned short.

 iu: a single unsigned little-endian integer

 mu3: three unsigned machine-endian 64-bit integers.

The "u" flag will be supported combined with all field types but will have no
effect on non-integer types. Also the flag is valid but ignored for the
'''binary format''' command.

~ Reference Implementation

A reference implementation is available in SourceForge Patch 156751
[http://sf.net/tracker/?func=detail&aid=1565751&group_id=10894&atid=310894].

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|


|
|


|


|

|


|

|


|













|

|


|

|


>

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

# TIP 275: Support Unsigned Values in binary Command

	Author:         Pat Thoyts <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        27-Sep-2006
	Post-History:   
	Keywords:       Tcl,binary,unsigned
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to add support for unsigned values to the **binary**
command.

# Rationale

It is quite common when handling binary data to need to read unsigned values.
All values read in by **binary scan** are converted to integers and sign
extended, which requires code to trim the excess bits using the **expr**
command if the values need to be treated as unsigned values. This makes Tcl
slow when handling large quantities of binary data, for instance in
crytographic or checksum functions. Simply by avoiding this **expr**
operation we significantly improve the speed of processing such data.

# Specification

The **binary scan** should be updated so as to add a flag identifier into
the binary field format. This makes the field specification:

 > <_type code_><_flag_>?<_length_>?

The flag character for unsigned fields \(the only one defined\) is "u", so the
following are all acceptable:

 cu\*: read all bytes as unsigned

 c2cu2: two signed bytes then two unsigned bytes

 su2: two unsigned little-endian shorts

 Su: a single big-endian unsigned short.

 iu: a single unsigned little-endian integer

 mu3: three unsigned machine-endian 64-bit integers.

The "u" flag will be supported combined with all field types but will have no
effect on non-integer types. Also the flag is valid but ignored for the
**binary format** command.

# Reference Implementation

A reference implementation is available in SourceForge Patch 156751
<http://sf.net/tracker/?func=detail&aid=1565751&group_id=10894&atid=310894> .

# Copyright

This document is placed in the public domain.

Name change from tip/276.tip to tip/276.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

TIP:            276
Title:          Specify and Unify Variable Linking Commands
Version:        $Revision: 1.20 $
Author:         Miguel Sofer <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        01-Oct-2006
Post-History:   
Keywords:       Tcl,global,variable,upvar,namespace upvar
Tcl-Version:    8.7


~ Abstract

The purpose of this TIP is to simplify and clarify the semantics of the
commands in Tcl that couple variables in different scopes together.

~ Rationale

This TIP proposes to specify and document the behaviour of the different
variable linking commands in Tcl: '''global''', '''variable''', '''upvar'''
and '''namespace upvar'''.

In particular, as many of these commands were initially designed to be mainly
useful from within procedure bodies, the documentation does not specify their
behaviour with respect to qualified variable names.

This TIP proposes to specify and document this behaviour, insuring that it is
essentially the same in all these commands.

~~ Current Situation

There have been a few bug reports concerning the behaviour of variable linking
commands with respect to qualified variable names: 604226, 1274916, 1274918.
Some are real bugs, some are just surprising but correct behaviour, some are
surprising unspecified behaviour.

Within proc bodies all of these commands create local variables that are
linked to original variables elsewhere (the following assumes that ''local''
is a non-qualified name):

 * "'''global''' ''var''" creates a local variable "[['''namespace tail'''
   ''var'']]" that is linked to "''var''" as resolved from the global
   namespace.

 * "'''variable''' ''var''" creates a local variable "[['''namespace
   tail''' ''var'']]" that is linked to "''var''" as resolved from
   [['''namespace current''']].

 * "'''upvar''' ''level var local''" creates a local variable "''local''" that
   is linked to "''var''" as resolved in the context of the frame identified
   by ''level''. It is an error to try to link to a proc-local variable from a namespace context. It is an error to link a variable to itself.

 * "'''namespace upvar''' ''ns var local''" creates a local variable
   "''local''" that is linked to "''var''" as resolved from namespace ''ns''
   (itself resolved in the current context). It is an error to link a variable to itself.

One undocumented issue is what should happen when ''local'' is a qualified
name.

Another issue is the behaviour of these commands when invoked outside of
procedure bodies:

 * "'''global''' ''var''" is documented to be a no-op.

 * "'''variable''' ''var''" is documented to create a namespace variable in
   the current namespace, without any mention of the behaviour when "''var''"
   is qualified. Currently that is a a no-op in terms of creating a variable,
   but it can change the value of the target, see [[Bug #604226]]. If '''var''' is a simple name and the corresponding variable already existed, '''variable''' may set its value (and an internal flag), but does no linking.

 * "'''upvar''' ''level var local''" creates a variable "''local''" (as
   resolved from [['''namespace current''']]) that is linked to "''var''" as
   resolved in the context of the frame identified by ''level''. It is an error to try to link to a proc-local variable from a namespace context. It is an error to link a variable to itself.

 * "'''namespace upvar''' ''ns var local'' creates a variable "''local''" (as
   resolved from [['''namespace current''']]) that is linked to "''var''" as
   resolved from namespace ''ns'' (itself resolved in the current context). It is an error to link a variable to itself.

~ Proposal

This TIP proposes to unify the criteria, making all of these commands
essentially implementable in Tcl from the most general, '''upvar'''. The
behaviour should ''not'' depend on the commands being invoked within or
outside of a procedure body.

In all of the following, it is an error for ''local'' to be a qualified
variable name.

 * "'''global''' ''var''" always creates a variable "[['''namespace tail'''
   ''var'']]" in the current context, linked to a global variable "''var''".

 * "'''variable''' ''var''" always creates a variable "[['''namespace tail'''
   ''var'']]" in the current context, linked to a variable "''var''" as
   resolved from [['''namespace current''']].

 * "'''upvar''' ''level var local''" always creates a variable "''local''" in
   the current context, linked to "''var''" as resolved in the context of the
   frame identified by ''level''. It is an error to try to link to a proc-local variable from a namespace context.

 * "'''namespace upvar''' ''ns var local''" always creates a variable
   "''local''" in the current context, linked to "''var''" as resolved from
   namespace ''ns'' (itself resolved in the current context).

In all cases, attempting to link a variable to itself will be a no-op.

~ Compatibility

This TIP may cause breakage in some scripts relying on undocumented behaviour.

The specification changes for '''global''' and '''variable''' outside of proc bodies is almost certainly implementing what the programmer meant them to do, hence likely to fix more bugs than it causes. 

~ Reference Implementation and Documentation

Forthcoming at SF.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|


|
|








|







|
|

|
|


|
|
|

|
|
|

|
|
|

|





|

|
|

|

|
|
|

|
|
|

|


|
|


|


|
|

|
|
|

|
|
|

|
|
|



|



|

|



|


>

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

# TIP 276: Specify and Unify Variable Linking Commands

	Author:         Miguel Sofer <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        01-Oct-2006
	Post-History:   
	Keywords:       Tcl,global,variable,upvar,namespace upvar
	Tcl-Version:    8.7
-----

# Abstract

The purpose of this TIP is to simplify and clarify the semantics of the
commands in Tcl that couple variables in different scopes together.

# Rationale

This TIP proposes to specify and document the behaviour of the different
variable linking commands in Tcl: **global**, **variable**, **upvar**
and **namespace upvar**.

In particular, as many of these commands were initially designed to be mainly
useful from within procedure bodies, the documentation does not specify their
behaviour with respect to qualified variable names.

This TIP proposes to specify and document this behaviour, insuring that it is
essentially the same in all these commands.

## Current Situation

There have been a few bug reports concerning the behaviour of variable linking
commands with respect to qualified variable names: 604226, 1274916, 1274918.
Some are real bugs, some are just surprising but correct behaviour, some are
surprising unspecified behaviour.

Within proc bodies all of these commands create local variables that are
linked to original variables elsewhere \(the following assumes that _local_
is a non-qualified name\):

 * "**global** _var_" creates a local variable "[**namespace tail**
   _var_]" that is linked to "_var_" as resolved from the global
   namespace.

 * "**variable** _var_" creates a local variable "[**namespace
   tail** _var_]" that is linked to "_var_" as resolved from
   [**namespace current**].

 * "**upvar** _level var local_" creates a local variable "_local_" that
   is linked to "_var_" as resolved in the context of the frame identified
   by _level_. It is an error to try to link to a proc-local variable from a namespace context. It is an error to link a variable to itself.

 * "**namespace upvar** _ns var local_" creates a local variable
   "_local_" that is linked to "_var_" as resolved from namespace _ns_
   \(itself resolved in the current context\). It is an error to link a variable to itself.

One undocumented issue is what should happen when _local_ is a qualified
name.

Another issue is the behaviour of these commands when invoked outside of
procedure bodies:

 * "**global** _var_" is documented to be a no-op.

 * "**variable** _var_" is documented to create a namespace variable in
   the current namespace, without any mention of the behaviour when "_var_"
   is qualified. Currently that is a a no-op in terms of creating a variable,
   but it can change the value of the target, see [Bug #604226]. If **var** is a simple name and the corresponding variable already existed, **variable** may set its value \(and an internal flag\), but does no linking.

 * "**upvar** _level var local_" creates a variable "_local_" \(as
   resolved from [**namespace current**]\) that is linked to "_var_" as
   resolved in the context of the frame identified by _level_. It is an error to try to link to a proc-local variable from a namespace context. It is an error to link a variable to itself.

 * "**namespace upvar** _ns var local_ creates a variable "_local_" \(as
   resolved from [**namespace current**]\) that is linked to "_var_" as
   resolved from namespace _ns_ \(itself resolved in the current context\). It is an error to link a variable to itself.

# Proposal

This TIP proposes to unify the criteria, making all of these commands
essentially implementable in Tcl from the most general, **upvar**. The
behaviour should _not_ depend on the commands being invoked within or
outside of a procedure body.

In all of the following, it is an error for _local_ to be a qualified
variable name.

 * "**global** _var_" always creates a variable "[**namespace tail**
   _var_]" in the current context, linked to a global variable "_var_".

 * "**variable** _var_" always creates a variable "[**namespace tail**
   _var_]" in the current context, linked to a variable "_var_" as
   resolved from [**namespace current**].

 * "**upvar** _level var local_" always creates a variable "_local_" in
   the current context, linked to "_var_" as resolved in the context of the
   frame identified by _level_. It is an error to try to link to a proc-local variable from a namespace context.

 * "**namespace upvar** _ns var local_" always creates a variable
   "_local_" in the current context, linked to "_var_" as resolved from
   namespace _ns_ \(itself resolved in the current context\).

In all cases, attempting to link a variable to itself will be a no-op.

# Compatibility

This TIP may cause breakage in some scripts relying on undocumented behaviour.

The specification changes for **global** and **variable** outside of proc bodies is almost certainly implementing what the programmer meant them to do, hence likely to fix more bugs than it causes. 

# Reference Implementation and Documentation

Forthcoming at SF.

# Copyright

This document has been placed in the public domain.

Name change from tip/277.tip to tip/277.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

TIP:		277
Title:		Create Namespaces as Needed
Version:	$Revision: 1.3 $
Author:		Miguel Sofer <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Created:	01-Oct-2006
Post-History:	


~ Abstract

This TIP proposes that namespaces be created automatically whenever a script
tries to create a command, variable or child namespace in it.

~ Proposal

As proposed in [[FR 582926]], whenever a script tries to create a command,
variable or namespace, Tcl should automatically create all namespaces in the
path if they do not already exist.

In other words, as an example, the current behaviour

|   % namespace children [namespace current]
|   ::activestate ::tcl
|   % set a::b::x 2
|   can't set "a::b::x": parent namespace doesn't exist
|   % namespace children [namespace current]
|   ::activestate ::tcl

should become

|   % namespace children [namespace current]
|   ::activestate ::tcl
|   % set a::b::x 2
|   2

|   % namespace children [namespace current]
|   ::a ::activestate ::tcl
|   % namespace children ::a
|   ::a::b

~ Reference Implementation and Documentation

Forthcoming at SF.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|




|

|





|
|
|
|
|
|



|
|
|
<
>
|
|
|
|

|



|


>

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

# TIP 277: Create Namespaces as Needed

	Author:		Miguel Sofer <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Created:	01-Oct-2006
	Post-History:	
-----

# Abstract

This TIP proposes that namespaces be created automatically whenever a script
tries to create a command, variable or child namespace in it.

# Proposal

As proposed in [FR 582926], whenever a script tries to create a command,
variable or namespace, Tcl should automatically create all namespaces in the
path if they do not already exist.

In other words, as an example, the current behaviour

	   % namespace children [namespace current]
	   ::activestate ::tcl
	   % set a::b::x 2
	   can't set "a::b::x": parent namespace doesn't exist
	   % namespace children [namespace current]
	   ::activestate ::tcl

should become

	   % namespace children [namespace current]
	   ::activestate ::tcl
	   % set a::b::x 2

	   2
	   % namespace children [namespace current]
	   ::a ::activestate ::tcl
	   % namespace children ::a
	   ::a::b

# Reference Implementation and Documentation

Forthcoming at SF.

# Copyright

This document has been placed in the public domain.

Name change from tip/278.tip to tip/278.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219

220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249

TIP:            278
Title:          Fix Variable Name Resolution Quirks
Version:        $Revision: 1.18 $
Author:         Miguel Sofer <[email protected]>
Author:         Miguel Sofer <[email protected]>
Author:         Kevin Kenny <[email protected]>
Author:         Jan Nijtmans <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        03-Oct-2006
Post-History:   
Tcl-Version:    9.0


~ Abstract

This TIP proposes to fix the behaviour for variable name resolution, modelling
it on the resolution for namespace names instead of the current command name
resolution.

~ Definitions

   * a variable name is "simple" if it does not contain the character sequence
     "::".

   * a variable name is "absolute" if it starts with the character sequence
     "::".

   * a variable name is "relative" if it is neither simple nor absolute, it
     contains the character sequence "::", but not at its beginning.

~ Specification

Variable name resolution shall proceed as follows:

   * a simple name refers to a local variable if within a proc body, to a variable resolved [[*]] in the current namespace otherwise 

   * an absolute name does not need resolving, ::foo::bar::baz always refers to a variable named "baz" in a namespace
named "bar" that is a child of a namespace named "foo" that is a child
of the global namespace of the interpreter [[*]].

   * a relative name is always resolved [[*]] starting at the current namespace. In the absence of special resolvers, foo::bar::baz refers to a variable named "baz" in a namespace
named "bar" that is a child of a namespace named "foo" that is a child
of the current namespace of the interpreter.

The changes with respect to the current behaviour is for relative names in all
contexts, and simple names outside of proc bodies: the alternative lookup
starting from the global namespace is lost.

The resolution is independent of the previous existence of namespaces or
variables. The 'declaration' of namespace variables with the '''variable'''
command, currently needed to avoid some confusing behaviour, becomes
unnecessary. In short:

 > '''It is possible to know what variable is meant by just looking at its
   name and knowing the context, without any interference from the rest of the
   program.'''

These are the same rules as presently used for the resolution of namespace names.

[[*]] Currently there are hooks in the core for special resolvers that can be attached to a namespace or interpreter, mainly (only?) used by itcl. The present TIP does not address resolvers, except for the specification that an absolute name ignores them. The rule that a simple name in a proc-body always refers to a local variable is not new in that sense, as any resolver hooks in that case create local variables linked to some other vars, in the manner of upvar. 

~ Rationale: avoid confusion

Repeating myself: the rationale is to make it a reality that

 > '''It is possible to know what variable is meant by just looking at its
   name and knowing the context, without any interference from the rest of the
   program.'''

Ever since the birth of namespaces, the resolution path for variables has been
modelled on the resolution path for commands: if a variable is not found in
the current namespace, it will be looked up in the global namespace.

This behaviour hides a few surprises, especially but not only with respect to
creative writing. Consider for instance the test

| test namespace-17.7 {Tcl_FindNamespaceVar, relative name found} {
|     namespace eval test_ns_1 {
|         unset x
|         set x  ;# must be global x now
|     }

| } {314159}

as well as following examples:

|   % set x 1
|   1

|   % namespace eval a set x
|   1

|   % set a::x
|   can't read "a::x": no such variable
|
|   % namespace eval b {upvar #0 x y}
|   % info vars x
|   % namespace eval a set x 1
|   1

|   % set x
|   1

|
|   % namespace eval a set x
|   can't read "x": no such variable
|   % set x 1
|   1

|   % namespace eval a set x
|   1

|   % upvar 0 ::a::x y
|   % namespace eval a set x
|   can't read "x": no such variable
|
|   % namespace eval a set x
|   can't read "x": no such variable
|   % set x 1
|   1

|   % namespace eval a set x
|   1

|   % trace add variable a::x read {;#}
|   % namespace eval a set x
|   can't read "x": no such variable
|
|   % set x 1
|   1

|   % namespace eval a {set x 2; set y 3}
|   3

|   % set x
|   2

|   % info vars a::*
|   ::a::y
|   % set a::x
|   can't read "a::x": no such variable
|   % set a::y
|   3


In order to restore some sanity, '''variable''' has been
invented to selectively force the behaviour that this TIP is proposing (in its usage outside of procedure bodies).

The present behaviour forces a subtle and confusing concept of "variable
existence", forcing some implementation details to be visible to
scripts. Internally, a variable may

 * not exist at all

 * exist in the namespace's hash table, but be undefined

 * exist and have a value

In principle scripts should not be able to distinguish the first two states -
except as to the existence of traces on undefined variables. In particular,
the existence of a link to an undefined variable (which forces the target to
exist in state 2) should have no influence whatsoever on the concept of
variable existence. But it does (see examples in #959052).

This behaviour also causes [namespace which -variable] and [info vars] to give
different answers as to the existence of variables: the first looks in the
hashtable, the second verifies that the variable has a value or that it has
been declared via [variable].

Some of the problems inherent in the current way of things are illustrated by
Bugs 959052, 1251123, 1274916, 1274918, 1280497

Bug 1185933 is perhaps particularly illustrative. In it, 
Kevin Kenny <[email protected]>, a long-time
Tcl maintainer (and reputed expert) had placed in 'clock.tcl' the
group of lines:

|    set i 0
|    foreach j $DaysInRomanMonthInLeapYear {
|        lappend DaysInPriorMonthsInLeapYear [incr i $j]
|    }

|    unset i j

within a [namespace eval] context.  This code performed without
ill effect for some months, until it was observed that it would
cause a failure if a script were to create a variable named 'i'
or 'j' in the global context prior to the first invocation of
the [clock] command.  This case was also inordinately difficult
to simulate in the test suite, because tcltest reads the clock
as part of its initialization.  The fix was to move the offending
code from the [namespace eval] into an 'init' procedure (which
was called once and then deleted via [rename]).  

~ Side Benefit: Code Simplification, Performance

Variable name resolution has a relatively complicated implementation, and
interplays strangely with many core commands - in particular '''variable'''
and '''upvar'''. This TIP would enable a non-negligible simplification of a
lot of code.

An optimisation in variable name caching that permits massive speed
improvements in namespace variable accesses could also be enabled - it is
currently #ifdef'ed out, it was active briefly in Tcl8.5a2. Note that
currently it is wrong to cache the pointer to an undefined variable: as the
variable has to be kept in the corresponding hashtable, the variable jumps
from the first to the second state of inexistence. This may cause breakage in
scripts depending on full non-existence. See also Bug 959052.

Quite a few flag values that are currently needed to specify special code
behaviour under different circumstances (VAR_NAMESPACE_VAR, LOOKUP_FOR_UPVAR,
possibly others) become obsolete: the behaviour is the same under all
circumstances.

~Down-Sides

This is known to expose some "bugs" in code in the wild, and break at least
one program (AlphaTk, see below).

~~ AlphaTk breakage

AlphaTk breaks with this change
[http://aspn.activestate.com/ASPN/Mail/Message/Tcl-core/2083396]
[http://sf.net/tracker/?func=detail&aid=959786&group_id=10894&atid=110894].

This is the result of code of the form

|   namespace eval foo {}
|   proc foo::bar {} {
|       global foo::name
|       set foo::name 1
|   }


which works since Tcl7.x until now, and would cease to work properly if this
change is implemented. It is interesting to understand how this code works:

 * '''Tcl7.x''' I assume that there is conditional compat code that makes '''namespace''' a noop. The code creates a global variable foo::name,   the proc accesses it as required by '''global'''.

 * '''Tcl8.x''' the code links the local variable "name" to the global "::foo::name"; after this, "name" goes unused. The access to the variable is by the name "foo::name": first "::foo::foo::name" is attempted, and, as it does not exist, "::foo::name". As this variable exists, in the sense that it is in the global hashtable by virtue of the created link, it is used.

Note that the code works in Tcl8.x through a quirk, and that it foregoes the
usage of fast local variable access to "name". Should this TIP be accepted, I
commit to helping out with the adaptation of AlphaTk.

Note also that, should both this TIP and [277] be accepted, the code will
continue to work as is through a different quirk. In that case, the namespace
"::foo::foo" would be created, and the variable "::foo::foo::name" would be
getting all the action. The code is however fragile, this aspect is not to be understood as minimising the impact of this TIP.

~ Reference Implementation and Documentation

A cvs branch tip-278-branch has been opened to test the implementation of this tip; the modifications are logged in the Changelog of the branch.

~ Notes

 * '''namespace which -variable var''' becomes relatively useless, as it will always return either {} or [[namespace current]]::var whenever var is not fully qualified.

 * the only effect of '''variable''' outside of proc bodies is now on '''namespace which -variable var'''. This might change again if TIP276 is approved

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|





|










|



|



|

|








|



|

|



|

|



|

|








|
|
|
|
<
>
|



|
<
>
|
<
>
|
|
|
|
|
|
<
>
|
<
>
|
|
|
|
<
>
|
<
>
|
|
|
|
|
|
|
<
>
|
<
>
|
|
|
|
|
<
>
|
<
>
|
<
>
|
|
|
|
|
<
|
>
|
|













|
|
|











|


|
|
|
<
>
|








|
|

|


|
|




|






|
|


|


|

|


|
|



|
|
|
|
<
>




|

|





|




|



|

|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217

218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249

# TIP 278: Fix Variable Name Resolution Quirks

	Author:         Miguel Sofer <[email protected]>
	Author:         Miguel Sofer <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	Author:         Jan Nijtmans <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        03-Oct-2006
	Post-History:   
	Tcl-Version:    9.0
-----

# Abstract

This TIP proposes to fix the behaviour for variable name resolution, modelling
it on the resolution for namespace names instead of the current command name
resolution.

# Definitions

   * a variable name is "simple" if it does not contain the character sequence
     "::".

   * a variable name is "absolute" if it starts with the character sequence
     "::".

   * a variable name is "relative" if it is neither simple nor absolute, it
     contains the character sequence "::", but not at its beginning.

# Specification

Variable name resolution shall proceed as follows:

   * a simple name refers to a local variable if within a proc body, to a variable resolved [*] in the current namespace otherwise 

   * an absolute name does not need resolving, ::foo::bar::baz always refers to a variable named "baz" in a namespace
named "bar" that is a child of a namespace named "foo" that is a child
of the global namespace of the interpreter [*].

   * a relative name is always resolved [*] starting at the current namespace. In the absence of special resolvers, foo::bar::baz refers to a variable named "baz" in a namespace
named "bar" that is a child of a namespace named "foo" that is a child
of the current namespace of the interpreter.

The changes with respect to the current behaviour is for relative names in all
contexts, and simple names outside of proc bodies: the alternative lookup
starting from the global namespace is lost.

The resolution is independent of the previous existence of namespaces or
variables. The 'declaration' of namespace variables with the **variable**
command, currently needed to avoid some confusing behaviour, becomes
unnecessary. In short:

 > **It is possible to know what variable is meant by just looking at its
   name and knowing the context, without any interference from the rest of the
   program.**

These are the same rules as presently used for the resolution of namespace names.

[*] Currently there are hooks in the core for special resolvers that can be attached to a namespace or interpreter, mainly \(only?\) used by itcl. The present TIP does not address resolvers, except for the specification that an absolute name ignores them. The rule that a simple name in a proc-body always refers to a local variable is not new in that sense, as any resolver hooks in that case create local variables linked to some other vars, in the manner of upvar. 

# Rationale: avoid confusion

Repeating myself: the rationale is to make it a reality that

 > **It is possible to know what variable is meant by just looking at its
   name and knowing the context, without any interference from the rest of the
   program.**

Ever since the birth of namespaces, the resolution path for variables has been
modelled on the resolution path for commands: if a variable is not found in
the current namespace, it will be looked up in the global namespace.

This behaviour hides a few surprises, especially but not only with respect to
creative writing. Consider for instance the test

	 test namespace-17.7 {Tcl_FindNamespaceVar, relative name found} {
	     namespace eval test_ns_1 {
	         unset x
	         set x  ;# must be global x now

	     }
	 } {314159}

as well as following examples:

	   % set x 1

	   1
	   % namespace eval a set x

	   1
	   % set a::x
	   can't read "a::x": no such variable
	
	   % namespace eval b {upvar #0 x y}
	   % info vars x
	   % namespace eval a set x 1

	   1
	   % set x

	   1
	
	   % namespace eval a set x
	   can't read "x": no such variable
	   % set x 1

	   1
	   % namespace eval a set x

	   1
	   % upvar 0 ::a::x y
	   % namespace eval a set x
	   can't read "x": no such variable
	
	   % namespace eval a set x
	   can't read "x": no such variable
	   % set x 1

	   1
	   % namespace eval a set x

	   1
	   % trace add variable a::x read {;#}
	   % namespace eval a set x
	   can't read "x": no such variable
	
	   % set x 1

	   1
	   % namespace eval a {set x 2; set y 3}

	   3
	   % set x

	   2
	   % info vars a::*
	   ::a::y
	   % set a::x
	   can't read "a::x": no such variable
	   % set a::y

	   3

In order to restore some sanity, **variable** has been
invented to selectively force the behaviour that this TIP is proposing \(in its usage outside of procedure bodies\).

The present behaviour forces a subtle and confusing concept of "variable
existence", forcing some implementation details to be visible to
scripts. Internally, a variable may

 * not exist at all

 * exist in the namespace's hash table, but be undefined

 * exist and have a value

In principle scripts should not be able to distinguish the first two states -
except as to the existence of traces on undefined variables. In particular,
the existence of a link to an undefined variable \(which forces the target to
exist in state 2\) should have no influence whatsoever on the concept of
variable existence. But it does \(see examples in \#959052\).

This behaviour also causes [namespace which -variable] and [info vars] to give
different answers as to the existence of variables: the first looks in the
hashtable, the second verifies that the variable has a value or that it has
been declared via [variable].

Some of the problems inherent in the current way of things are illustrated by
Bugs 959052, 1251123, 1274916, 1274918, 1280497

Bug 1185933 is perhaps particularly illustrative. In it, 
Kevin Kenny <[email protected]>, a long-time
Tcl maintainer \(and reputed expert\) had placed in 'clock.tcl' the
group of lines:

	    set i 0
	    foreach j $DaysInRomanMonthInLeapYear {
	        lappend DaysInPriorMonthsInLeapYear [incr i $j]

	    }
	    unset i j

within a [namespace eval] context.  This code performed without
ill effect for some months, until it was observed that it would
cause a failure if a script were to create a variable named 'i'
or 'j' in the global context prior to the first invocation of
the [clock] command.  This case was also inordinately difficult
to simulate in the test suite, because tcltest reads the clock
as part of its initialization.  The fix was to move the offending
code from the [namespace eval] into an 'init' procedure \(which
was called once and then deleted via [rename]\).  

# Side Benefit: Code Simplification, Performance

Variable name resolution has a relatively complicated implementation, and
interplays strangely with many core commands - in particular **variable**
and **upvar**. This TIP would enable a non-negligible simplification of a
lot of code.

An optimisation in variable name caching that permits massive speed
improvements in namespace variable accesses could also be enabled - it is
currently \#ifdef'ed out, it was active briefly in Tcl8.5a2. Note that
currently it is wrong to cache the pointer to an undefined variable: as the
variable has to be kept in the corresponding hashtable, the variable jumps
from the first to the second state of inexistence. This may cause breakage in
scripts depending on full non-existence. See also Bug 959052.

Quite a few flag values that are currently needed to specify special code
behaviour under different circumstances \(VAR\_NAMESPACE\_VAR, LOOKUP\_FOR\_UPVAR,
possibly others\) become obsolete: the behaviour is the same under all
circumstances.

# Down-Sides

This is known to expose some "bugs" in code in the wild, and break at least
one program \(AlphaTk, see below\).

## AlphaTk breakage

AlphaTk breaks with this change
<http://aspn.activestate.com/ASPN/Mail/Message/Tcl-core/2083396> 
<http://sf.net/tracker/?func=detail&aid=959786&group_id=10894&atid=110894> .

This is the result of code of the form

	   namespace eval foo {}
	   proc foo::bar {} {
	       global foo::name
	       set foo::name 1

	   }

which works since Tcl7.x until now, and would cease to work properly if this
change is implemented. It is interesting to understand how this code works:

 * **Tcl7.x** I assume that there is conditional compat code that makes **namespace** a noop. The code creates a global variable foo::name,   the proc accesses it as required by **global**.

 * **Tcl8.x** the code links the local variable "name" to the global "::foo::name"; after this, "name" goes unused. The access to the variable is by the name "foo::name": first "::foo::foo::name" is attempted, and, as it does not exist, "::foo::name". As this variable exists, in the sense that it is in the global hashtable by virtue of the created link, it is used.

Note that the code works in Tcl8.x through a quirk, and that it foregoes the
usage of fast local variable access to "name". Should this TIP be accepted, I
commit to helping out with the adaptation of AlphaTk.

Note also that, should both this TIP and [[277]](277.md) be accepted, the code will
continue to work as is through a different quirk. In that case, the namespace
"::foo::foo" would be created, and the variable "::foo::foo::name" would be
getting all the action. The code is however fragile, this aspect is not to be understood as minimising the impact of this TIP.

# Reference Implementation and Documentation

A cvs branch tip-278-branch has been opened to test the implementation of this tip; the modifications are logged in the Changelog of the branch.

# Notes

 * **namespace which -variable var** becomes relatively useless, as it will always return either \{\} or [namespace current]::var whenever var is not fully qualified.

 * the only effect of **variable** outside of proc bodies is now on **namespace which -variable var**. This might change again if TIP276 is approved

# Copyright

This document has been placed in the public domain.

Name change from tip/279.tip to tip/279.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352

TIP:            279
Title:          Adding an Extensible Object System to the Core
Version:        $Revision: 1.10 $
Author:         Gustaf Neumann <[email protected]>
Author:         Larry W. Virden <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        05-Oct-2006
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes adding OO support to the Tcl core, consisting mostly
of a dispatcher plus a small number of helper commands. The TIP
allows the coexistence of multiple object systems by providing a
common framework, the Tcl Minimal Object System (TMOS).  The framework
will contain, as well, a small, basic oriented language (Tcl Core Object
Oriented Language, TclCOOL) to make it usable in the core without any
extensions. All defined commands of the minimal object system are
defined in the '''::oo''' namespace, which is not used by any current
mainstream OO system. It has been designed specifically to allow a relatively 
simple re-implementation of the known object systems.

~ Rationale and Basic Requirements

Rather than proposing any kind of OO language, the TIP suggests to add a
framework to the core that many existing and future extensions (including
XOTcl) can use. This framework alone is not useful as an OO language, but is
an environment that can host multiple OO languages in parallel, such as Snit
or XOTcl (maybe the language from current [257] as well), without pushing a
single model. Languages like Snit or XOTcl can continue to develop, the core
developers can optimize and integrate better with the tcl-core, etc.

The framework (Tcl Minimal Object System, TMOS) consists of an
flexible object interpreter (dispatcher) able to run the most powerful
current object extensions. This dispatcher is accompanied by a
"minimal object system" and a small set of predefined, but unattached 
methods (basic method set) and an "extension mechanism". For the
bootstrapping of different object systems, only a single method for
allocating objects or classes is proposed, plus a few commands for
setting up the object/class relations and registering methods.

The Tcl Minimal Object System is used for the definition of TclCOOL
(Tcl Core Object Oriented Language). TclCOOL is simple but powerful
object language realized with TMOS. 

Additional object systems (like XOTcl, SNIT or STOOP) can be loaded as
an extensions (being not part of the core), and can provide their own
method-sets (or re-use the predefined method set, or reuse the
methods-set of some extension).

This approach provides a flexibility much higher than in other popular
scripting languages and lets object system designers continue to
improve their work based on Tcl.

~ The Tcl Minimal Object System

The minimal object system consists of a base class ('''::oo::object''') and a
meta-class ('''::oo::class''', subclass of '''::oo::object''').

|   name of class  kind of class  superclass     instance-of
|  ==========================================================
|   ::oo::object   class          ::oo::object   ::oo::class
|   ::oo::class    meta-class     ::oo::object   ::oo::class

The meta-class '''::oo::class''' has two methods named "'''alloc'''" and "'''dealloc'''" 
(names are arbitrary, as shown later) to create objects or classes. '''::oo::object'''
has no methods at all.

The minimal object system is intended to be specialized by one or more
different object systems. An object system is created by sub-classing the base
classes, configuring these according to the object systems needs. This
configuration consists of defining its relations to the general base and
meta-class, and equipping these extension-specific classes with additional
functionality (providing methods). The whole configuration of the object
system can be done completely from the scripting level.

The minimal object system defines the following commands and methods 
in the ::oo namespace:

 * Two classes

|   ::oo::class
|   ::oo::object

 * Two unexported Tcl commands for OO-language designer

|   ::oo::alias
|   ::oo::setrelation

 * Three exported Tcl commands to be used by in the languages

|   ::oo::my
|   ::oo::self
|   ::oo::next 

 * An unregistered (unattached) set of methods that can be used for classes

|   alloc, dealloc, instproc, instforward, info

 * An unregistered (unattached) set of methods that can be used for objects
|   instvar forward info

The Tcl command ::oo::setrelation

|   ::oo::setrelation class|obj <relation> <target>

allows one to define/redefine relations between objects, classes and
mixins. This is a primitive command designed for the language
developer, not for the user of the implemented object oriented
language. The following relations are supported: '''mixin'''
(abbreviation for per-object mixin), '''instmixin''' (for per-class
mixin), '''filter''' (for per-object filter), '''instfilter''' (for
per-class filter), '''class''', and '''superclass'''. The meaning of
these relations is defined by the dispatcher, which is responsible for
the linearization of the commands.

The dispatcher determines the invocation order depending on the
precedence order and the resolution order. The precedence order
defines the priorization of classes and determines therefore the
shadowing of methods. The precedence order is per-object mixins,
followed by per-class mixins, followed by the class hierarchy. All of
these refer not to single classes but to class hierarchies, where the
contained classes are linearized; when a class is mixed into a
precedence order, where it is already present, it has no effect.
The precedence of object specific methods is between mixins 
and the intrinsic class hierarchy.

The method resolution order overlays the precedence order. While the
precedence order determines, what method should be called, the method
resolution order determines what other methods should be called before
this method. The resolution order supports per class filters (methods
to be called before every method dispatch for every instance of this
class) and per-object filters (to be called before every method
dispatch of this object). Filters are defined in a filter chain, where
object specific filters take precedence over class specific
filters. Filters can change the results of methods. Immediately before
and after certain methods pre- and post-conditions can be evaluated
(similar to method-combinators in CLOS), between statements,
invariants can be checked.

The invocation order defines the layering of methods, the method
chaining (calling shadowed/filtered methods) is performed through the
command next. Per-object filters, per-class filters, per-object mixins
and per-class mixins can be applied conditionally based on
tcl-expressions (guards) executed int the object context.

When an undefined method is invoked on an object, the
call (method name and the arguments of the invocation) are passed to
the method '''unknown'''. If no such method exists, an error message
is generated.

The Tcl command ::oo::alias

|   ::oo::alias class|obj methodName ?-objscope? ?-per-object? cmdName

registers a command (''cmdName'') under a certain name (''methodName'')
to an object or class (1st argument) to make the command available 
as a method. The options ''-objscope'' makes instance variables of the
object/class appear as local variables, therefore Tcl commands to which
variable names are passed (e.g. set, append, lappend, ...) can access
instance variables without additional effort. 

~~ Example for defining TclCOOL (Tcl Core Object Oriented Language)

~~~ Create base and meta class:

|   namespace eval tcl-cool {}
|   ::oo::class alloc ::tcl-cool::object
|   ::oo::class alloc ::tcl-cool::class

After creation, the classes ::tcl-cool::class and
::tcl-cool::object are instances of ::oo::class.
This is not what we want to have. ''tcl-cool::object''
should be the most general superclass of TclCOOL, and
''tcl-cool::class'' should be the most general superclass of
TclCOOL. Without this redefinition ::tcl-cool::class and 
::tcl-cool::object would not have methods (except alloc and dealloc),
even if we provide methods for these base classes.

~~~ Define the basic class relations:

Since we are bootstrapping the language from a minimal
command-set, we will use the setrelation command to define the
basic relationships of the freshly defined classes.

First, we define that the superclasses of the newly defined class
named ''::tcl-cool::class'') should be the general meta-class
::oo::class and as well ''::tcl-cool::object''. Therefore,
::tcl-cool::class will be a meta-class (its instances are classes) and
it will inherit all properties of the most general TclCOOL class.

|   ::oo::setrelation ::tcl::cool::class superclass {::oo::class ::tcl-cool::object} 

The next two commands define that ::tcl-cool::object and
::tcl-cool::class are instances of ::tcl-cool::class. In other words,
the class of e.g. ::tcl-cool::object is ::tcl-cool::class.

|   ::oo::setrelation ::tcl-cool::object class ::tcl-cool::class 
|   ::oo::setrelation ::tcl-cool::class  class ::tcl-cool::class 

The basic OO-relations of the two basic classes are defined. 
In a next step of the bootstrapping we attach methods to these classes.

~~~ Define methods for classes:

We define 3 methods for ''::tcl-cool::class'' based on the method-set for classes:

 * ''method'' is a means to define the methods, which are provided 
               to the instances of the class (''instproc'' in XOTcl)

 * ''forward'' is a forwarder for instances of the object (''instforward'' in XOTcl)

 * ''info'' is an introspection method for classes

|   ::oo::alias ::tcl-cool::class method  ::oo::methodset::class::instproc
|   ::oo::alias ::tcl-cool::class forward ::oo::methodset::class::instforward
|   ::oo::alias ::tcl-cool::class info    ::oo::methodset::class::info

~~~ Define methods for objects:

Next, we define 3 methods for ''object'' (actually ''::tcl-cool::object'') 
based on the method-set for objects:

 * ''variable'' is a means to import instance variables into
               the current scope (''instvar'' in XOTcl)

 * ''forward'' is a method for delegating calls to different objects

 * ''info'' is an introspection method for objects

|   ::oo::alias ::tcl-cool::object variable ::oo::methodset::object::instvar
|   ::oo::alias ::tcl-cool::object forward  ::oo::methodset::object::forward
|   ::oo::alias ::tcl-cool::object info     ::oo::methodset::object::info

The full definition of TclCOOL is available from
[http://media.wu-wien.ac.at/download/tcl-cool.tcl]

~ Methods from Extensions

This proposal defines only a small method-set (see above). However, it makes it 
straightforward to reuse the existing method-set (with maybe different names)
without forcing an intermediate interpretation layer, or to load an additional
method-set as extension. This additional method-set can be loaded dynamically via
'''package require'''. The object system developer can provided the methods as
Tcl commands in the extension's namespace. These commands can be attached to
the objects and classes of the object system to be defined with the command
''::oo::alias''.

The command alias should not allow extensions to register methods on 
'''::oo::object''' and '''::oo::class'''. All application object systems 
should only be allowed to register their methods on the language specific
superclasses.

The exact API for methods accessing the dispatcher internals will be specified
in another TIP.

The primitive commands (like '''my''', '''next''', '''self''',
'''configure''', ...) are provided by the OO namespace, and these can be 
provided by the extension writers by accessing the dispatcher structure
and its stack.

~ Strengths of the Approach

 * All OO extensions can use the powerful dispatcher

 * If a certain extensions don't require filters, mixins, etc., they simply
   don't have to activate these.

 * The XOTcl dispatcher can be seen as a prototype implementation, but it should
   be replaced by a more efficient implementation with tighter core
   integration, provided the regression tests of the languages (e.g., XOTcl)
   continue to work.

 * The prototype implementation based on the current XOTcl 1.5.3 alpha release

 > * is proven to work and sufficiently bug-free,

 > * is free of memory leaks,

 > * thread safe,

 > * provides execution of the destroy callbacks when a thread or
     program exits,

 > * provides uplevel transparency for interceptors,

 > * is well suited for IDEs (an arbitrary class from a class tree can be
     reloaded and redefined without altering the relations between classes
     and/or instances)

 * All OO systems are treated equal

 > * since we do not want to allow to register methods on '''::oo::object'''
     or '''::oo::class''', there is no "preferred" object system,

 > * every object system defines its own classes with its own names and own
     methods (although, it can reuse methods from all extensions with
     arbitrary names, as shown above)

 > * there is no need to namespace export from "oo::*" (these are no end-user
     commands).

 > * nobody is forced on any predefined semantics

 * no extensions are locked out

 > * existing "high level" extensions (like XOTcl) and their applications
     (e.g. OpenACS) continue to work

 > * since other OO language definitions are not part of the core, their development
     can continue, 

 > * other OO languages can easily benefit from the new core functionality

 > * the dispatcher is based on a superset of the requirements of 
     existing languages, so these should be able to use it.

 > * extending the dispatcher requires a TIP.

 * This proposal is in the Tcl tradition of Tcl as a 2-level meta-language,
   since it provides a highly adjustable framework for object oriented
   languages.

 * Providing such a framework will attract people and put Tcl in front of the
   other OO scripting languages.

~ Sample Implementation

 * XOTcl 1.5.3alpha is the reference dispatcher (it should be rewritten
   for inclusion in the core, and serves here only as proof-of-concept)
   [http://media.wu-wien.ac.at/download/xotcl-1.5.3-alpha2.tar.gz].

 * Example of the TclCOOL language (to be the ''part'' of the framework)
   [http://media.wu-wien.ac.at/download/tcl-cool.tcl]

 * Example of a subset of ITcl based on this TIP (implemented with 
   the framework, runs already part of the itcl regression tests:
   protection.test and basic.test, in the latter, only three error 
   messages differ) 
   [http://media.wu-wien.ac.at/download/itcl.tcl]

 * Example of the XOTcl language (as implemented ''with'' the
   framework):
   See generic/predefined.xotcl in the XOTcl 1.5.3alpha reference 
   implementation

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|
|
|

|



|


|
|

|



|
|


|





|


|
|
|
|





|

|
|

|
|
|
|

|
|







|







|
|



|
|



|
|
|

|

|

|
|



|




|
|
|
|

















|

|
|



|



|


|


|
|




|

|
|
|

|


|

|

|
|
|



|

|

|


|






|
|
|


|





|
|




|

|

|
|

|

|

|
|
|

|

|


|
|

|

|

|
|
|


|

|

|
|


|


|


|






|
|



|








|




|

|

|

|


|

|

|



|
|

|
|
|

|
|

|



|
|

|


|

|


|








|

|
|
|

|
|

|


|
|

|
|



|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352

# TIP 279: Adding an Extensible Object System to the Core

	Author:         Gustaf Neumann <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        05-Oct-2006
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes adding OO support to the Tcl core, consisting mostly
of a dispatcher plus a small number of helper commands. The TIP
allows the coexistence of multiple object systems by providing a
common framework, the Tcl Minimal Object System \(TMOS\).  The framework
will contain, as well, a small, basic oriented language \(Tcl Core Object
Oriented Language, TclCOOL\) to make it usable in the core without any
extensions. All defined commands of the minimal object system are
defined in the **::oo** namespace, which is not used by any current
mainstream OO system. It has been designed specifically to allow a relatively 
simple re-implementation of the known object systems.

# Rationale and Basic Requirements

Rather than proposing any kind of OO language, the TIP suggests to add a
framework to the core that many existing and future extensions \(including
XOTcl\) can use. This framework alone is not useful as an OO language, but is
an environment that can host multiple OO languages in parallel, such as Snit
or XOTcl \(maybe the language from current [[257]](257.md) as well\), without pushing a
single model. Languages like Snit or XOTcl can continue to develop, the core
developers can optimize and integrate better with the tcl-core, etc.

The framework \(Tcl Minimal Object System, TMOS\) consists of an
flexible object interpreter \(dispatcher\) able to run the most powerful
current object extensions. This dispatcher is accompanied by a
"minimal object system" and a small set of predefined, but unattached 
methods \(basic method set\) and an "extension mechanism". For the
bootstrapping of different object systems, only a single method for
allocating objects or classes is proposed, plus a few commands for
setting up the object/class relations and registering methods.

The Tcl Minimal Object System is used for the definition of TclCOOL
\(Tcl Core Object Oriented Language\). TclCOOL is simple but powerful
object language realized with TMOS. 

Additional object systems \(like XOTcl, SNIT or STOOP\) can be loaded as
an extensions \(being not part of the core\), and can provide their own
method-sets \(or re-use the predefined method set, or reuse the
methods-set of some extension\).

This approach provides a flexibility much higher than in other popular
scripting languages and lets object system designers continue to
improve their work based on Tcl.

# The Tcl Minimal Object System

The minimal object system consists of a base class \(**::oo::object**\) and a
meta-class \(**::oo::class**, subclass of **::oo::object**\).

	   name of class  kind of class  superclass     instance-of
	  ==========================================================
	   ::oo::object   class          ::oo::object   ::oo::class
	   ::oo::class    meta-class     ::oo::object   ::oo::class

The meta-class **::oo::class** has two methods named "**alloc**" and "**dealloc**" 
\(names are arbitrary, as shown later\) to create objects or classes. **::oo::object**
has no methods at all.

The minimal object system is intended to be specialized by one or more
different object systems. An object system is created by sub-classing the base
classes, configuring these according to the object systems needs. This
configuration consists of defining its relations to the general base and
meta-class, and equipping these extension-specific classes with additional
functionality \(providing methods\). The whole configuration of the object
system can be done completely from the scripting level.

The minimal object system defines the following commands and methods 
in the ::oo namespace:

 * Two classes

		   ::oo::class
		   ::oo::object

 * Two unexported Tcl commands for OO-language designer

		   ::oo::alias
		   ::oo::setrelation

 * Three exported Tcl commands to be used by in the languages

		   ::oo::my
		   ::oo::self
		   ::oo::next 

 * An unregistered \(unattached\) set of methods that can be used for classes

		   alloc, dealloc, instproc, instforward, info

 * An unregistered \(unattached\) set of methods that can be used for objects
		   instvar forward info

The Tcl command ::oo::setrelation

	   ::oo::setrelation class|obj <relation> <target>

allows one to define/redefine relations between objects, classes and
mixins. This is a primitive command designed for the language
developer, not for the user of the implemented object oriented
language. The following relations are supported: **mixin**
\(abbreviation for per-object mixin\), **instmixin** \(for per-class
mixin\), **filter** \(for per-object filter\), **instfilter** \(for
per-class filter\), **class**, and **superclass**. The meaning of
these relations is defined by the dispatcher, which is responsible for
the linearization of the commands.

The dispatcher determines the invocation order depending on the
precedence order and the resolution order. The precedence order
defines the priorization of classes and determines therefore the
shadowing of methods. The precedence order is per-object mixins,
followed by per-class mixins, followed by the class hierarchy. All of
these refer not to single classes but to class hierarchies, where the
contained classes are linearized; when a class is mixed into a
precedence order, where it is already present, it has no effect.
The precedence of object specific methods is between mixins 
and the intrinsic class hierarchy.

The method resolution order overlays the precedence order. While the
precedence order determines, what method should be called, the method
resolution order determines what other methods should be called before
this method. The resolution order supports per class filters \(methods
to be called before every method dispatch for every instance of this
class\) and per-object filters \(to be called before every method
dispatch of this object\). Filters are defined in a filter chain, where
object specific filters take precedence over class specific
filters. Filters can change the results of methods. Immediately before
and after certain methods pre- and post-conditions can be evaluated
\(similar to method-combinators in CLOS\), between statements,
invariants can be checked.

The invocation order defines the layering of methods, the method
chaining \(calling shadowed/filtered methods\) is performed through the
command next. Per-object filters, per-class filters, per-object mixins
and per-class mixins can be applied conditionally based on
tcl-expressions \(guards\) executed int the object context.

When an undefined method is invoked on an object, the
call \(method name and the arguments of the invocation\) are passed to
the method **unknown**. If no such method exists, an error message
is generated.

The Tcl command ::oo::alias

	   ::oo::alias class|obj methodName ?-objscope? ?-per-object? cmdName

registers a command \(_cmdName_\) under a certain name \(_methodName_\)
to an object or class \(1st argument\) to make the command available 
as a method. The options _-objscope_ makes instance variables of the
object/class appear as local variables, therefore Tcl commands to which
variable names are passed \(e.g. set, append, lappend, ...\) can access
instance variables without additional effort. 

## Example for defining TclCOOL \(Tcl Core Object Oriented Language\)

### Create base and meta class:

	   namespace eval tcl-cool {}
	   ::oo::class alloc ::tcl-cool::object
	   ::oo::class alloc ::tcl-cool::class

After creation, the classes ::tcl-cool::class and
::tcl-cool::object are instances of ::oo::class.
This is not what we want to have. _tcl-cool::object_
should be the most general superclass of TclCOOL, and
_tcl-cool::class_ should be the most general superclass of
TclCOOL. Without this redefinition ::tcl-cool::class and 
::tcl-cool::object would not have methods \(except alloc and dealloc\),
even if we provide methods for these base classes.

### Define the basic class relations:

Since we are bootstrapping the language from a minimal
command-set, we will use the setrelation command to define the
basic relationships of the freshly defined classes.

First, we define that the superclasses of the newly defined class
named _::tcl-cool::class_\) should be the general meta-class
::oo::class and as well _::tcl-cool::object_. Therefore,
::tcl-cool::class will be a meta-class \(its instances are classes\) and
it will inherit all properties of the most general TclCOOL class.

	   ::oo::setrelation ::tcl::cool::class superclass {::oo::class ::tcl-cool::object} 

The next two commands define that ::tcl-cool::object and
::tcl-cool::class are instances of ::tcl-cool::class. In other words,
the class of e.g. ::tcl-cool::object is ::tcl-cool::class.

	   ::oo::setrelation ::tcl-cool::object class ::tcl-cool::class 
	   ::oo::setrelation ::tcl-cool::class  class ::tcl-cool::class 

The basic OO-relations of the two basic classes are defined. 
In a next step of the bootstrapping we attach methods to these classes.

### Define methods for classes:

We define 3 methods for _::tcl-cool::class_ based on the method-set for classes:

 * _method_ is a means to define the methods, which are provided 
               to the instances of the class \(_instproc_ in XOTcl\)

 * _forward_ is a forwarder for instances of the object \(_instforward_ in XOTcl\)

 * _info_ is an introspection method for classes

		   ::oo::alias ::tcl-cool::class method  ::oo::methodset::class::instproc
		   ::oo::alias ::tcl-cool::class forward ::oo::methodset::class::instforward
		   ::oo::alias ::tcl-cool::class info    ::oo::methodset::class::info

### Define methods for objects:

Next, we define 3 methods for _object_ \(actually _::tcl-cool::object_\) 
based on the method-set for objects:

 * _variable_ is a means to import instance variables into
               the current scope \(_instvar_ in XOTcl\)

 * _forward_ is a method for delegating calls to different objects

 * _info_ is an introspection method for objects

		   ::oo::alias ::tcl-cool::object variable ::oo::methodset::object::instvar
		   ::oo::alias ::tcl-cool::object forward  ::oo::methodset::object::forward
		   ::oo::alias ::tcl-cool::object info     ::oo::methodset::object::info

The full definition of TclCOOL is available from
<http://media.wu-wien.ac.at/download/tcl-cool.tcl> 

# Methods from Extensions

This proposal defines only a small method-set \(see above\). However, it makes it 
straightforward to reuse the existing method-set \(with maybe different names\)
without forcing an intermediate interpretation layer, or to load an additional
method-set as extension. This additional method-set can be loaded dynamically via
**package require**. The object system developer can provided the methods as
Tcl commands in the extension's namespace. These commands can be attached to
the objects and classes of the object system to be defined with the command
_::oo::alias_.

The command alias should not allow extensions to register methods on 
**::oo::object** and **::oo::class**. All application object systems 
should only be allowed to register their methods on the language specific
superclasses.

The exact API for methods accessing the dispatcher internals will be specified
in another TIP.

The primitive commands \(like **my**, **next**, **self**,
**configure**, ...\) are provided by the OO namespace, and these can be 
provided by the extension writers by accessing the dispatcher structure
and its stack.

# Strengths of the Approach

 * All OO extensions can use the powerful dispatcher

 * If a certain extensions don't require filters, mixins, etc., they simply
   don't have to activate these.

 * The XOTcl dispatcher can be seen as a prototype implementation, but it should
   be replaced by a more efficient implementation with tighter core
   integration, provided the regression tests of the languages \(e.g., XOTcl\)
   continue to work.

 * The prototype implementation based on the current XOTcl 1.5.3 alpha release

	 > \* is proven to work and sufficiently bug-free,

	 > \* is free of memory leaks,

	 > \* thread safe,

	 > \* provides execution of the destroy callbacks when a thread or
     program exits,

	 > \* provides uplevel transparency for interceptors,

	 > \* is well suited for IDEs \(an arbitrary class from a class tree can be
     reloaded and redefined without altering the relations between classes
     and/or instances\)

 * All OO systems are treated equal

	 > \* since we do not want to allow to register methods on **::oo::object**
     or **::oo::class**, there is no "preferred" object system,

	 > \* every object system defines its own classes with its own names and own
     methods \(although, it can reuse methods from all extensions with
     arbitrary names, as shown above\)

	 > \* there is no need to namespace export from "oo::\*" \(these are no end-user
     commands\).

	 > \* nobody is forced on any predefined semantics

 * no extensions are locked out

	 > \* existing "high level" extensions \(like XOTcl\) and their applications
     \(e.g. OpenACS\) continue to work

	 > \* since other OO language definitions are not part of the core, their development
     can continue, 

	 > \* other OO languages can easily benefit from the new core functionality

	 > \* the dispatcher is based on a superset of the requirements of 
     existing languages, so these should be able to use it.

	 > \* extending the dispatcher requires a TIP.

 * This proposal is in the Tcl tradition of Tcl as a 2-level meta-language,
   since it provides a highly adjustable framework for object oriented
   languages.

 * Providing such a framework will attract people and put Tcl in front of the
   other OO scripting languages.

# Sample Implementation

 * XOTcl 1.5.3alpha is the reference dispatcher \(it should be rewritten
   for inclusion in the core, and serves here only as proof-of-concept\)
   <http://media.wu-wien.ac.at/download/xotcl-1.5.3-alpha2.tar.gz> .

 * Example of the TclCOOL language \(to be the _part_ of the framework\)
   <http://media.wu-wien.ac.at/download/tcl-cool.tcl> 

 * Example of a subset of ITcl based on this TIP \(implemented with 
   the framework, runs already part of the itcl regression tests:
   protection.test and basic.test, in the latter, only three error 
   messages differ\) 
   <http://media.wu-wien.ac.at/download/itcl.tcl> 

 * Example of the XOTcl language \(as implemented _with_ the
   framework\):
   See generic/predefined.xotcl in the XOTcl 1.5.3alpha reference 
   implementation

# Copyright

This document has been placed in the public domain.

Name change from tip/28.tip to tip/28.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
TIP:            28
Title:          How to be a good maintainer for Tcl/Tk
Version:        $Revision: 1.24 $
Author:         Don Porter <[email protected]>
State:          Draft
Type:           Informative
Vote:           Pending
Created:        23-Feb-2001
Post-History:   


~ Abstract

This document presents information and advice to maintainers in the
form of a Frequently Asked Questions (FAQ) list.

~ Preface

Notice in the header above that this is a Draft document.  It won't be
the ''official'' word of the TCT unless/until it is accepted by the
TCT.  Meanwhile, it should still be a helpful guide to those serving
or considering service as maintainers.  At the very least it's a
useful straw man to revise into something better.  Help us make it
even more useful by using the [[Edit]] link at the bottom of this page
(if any) to add/revise the questions and answers, or add your
comments.

~ Background

TCT procedures (see [0]) calls for one or more ''maintainers'' to take
responsibility for each functional area of the Tcl ([16]) or Tk ([23])
source code.  Every source code patch to Tcl or Tk will be committed
to the official branches of the appropriate CVS repository only after
approval by an appropriate set of maintainers.

~ Can I be a Tcl/Tk maintainer?

Most likely.  To be a maintainer, you should have...

 * ...an interest in Tcl/Tk.

 * ...access to the Internet (Web and e-mail).

 * ...some volunteer time to contribute.

 * ...the ability and the support software to code in C and/or Tcl,
   use CVS, use SourceForge facilities, and familiarity with a portion
   of the Tcl/Tk source code to be maintained, or the willingness to
   acquire these things.

For the most part, if you are reading this document, you probably have
what it takes to be a Tcl/Tk maintainer.

~ What can I maintain?

The Tcl Core Team (TCT) has divided up the Tcl/Tk source code into
functional areas as described in [16] and [23].  You can volunteer to
help maintain as many areas as you think you can handle.  Select those
you have experience with or an interest in.

~ What does a maintainer do?

Maintainers are the people who make changes to the files that make up
the source code distribution of Tcl or Tk -- code, documentation, and
tests.  That's what a maintainer does: check in changes to the
official source code in the area he/she maintains.

The source code can be changed for several reasons: to correct a bug,
to add a new feature, or to re-implement an existing feature in a new
way.  The reason for a change controls how much oversight the
maintainer must have while making the change.  More on this below.

~ How do I prepare to be a maintainer?

The official repositories of Tcl and Tk source code are kept at
SourceForge, so you need to register for a SourceForge account
[https://sourceforge.net/account/register.php].  As part of the
registration, you will select a login name.  When you volunteer as a
maintainer, the administrators of the Tcl or Tk projects will need
that name to give you write access to the appropriate repository.

Once you have a SourceForge account, get familiar with the tools it
provides.  Most important is that you get set up to use CVS over SSH
to access the repository.  This can be difficult.  There are some
notes [http://tcltk.org/sourceforge] on how other Developers on the
Tcl and Tk projects have been able to successfully get this done.

This document does not include instructions on how to use CVS.  See
the following references for assistance with learning CVS.

 * http://cvsbook.red-bean.com/cvsbook.html

''Add more references here please.''

~ How do I volunteer to be a maintainer?

Send a message to <[email protected]> telling the TCT
your SourceForge login name and what area(s) you want to help
maintain.  Someone will add you to the list of ''Developers'' on the
Tcl or Tk projects and enable your access to SourceForge features like
the Bug Tracker and Patch Manager.  As a Developer, you will have
write access to the appropriate repository of official source code.

~ Write access!  So I can just start changing Tcl/Tk?!

For some purposes, yes.  For others, you'll need to get approval from
the TCT first.  Read on...

~ What Internet resources does a maintainer use?

A maintainer uses the SourceForge Bug Tracker for Tcl or Tk to learn
what bugs are reported in his area (browse by Category).

  * http://sourceforge.net/bugs/?group_id=10894

  * http://sourceforge.net/bugs/?group_id=12997

A maintainer uses the SourceForge Patch Manager for Tcl or Tk to learn
what patches make changes in his area (browse by Category).

  * http://sourceforge.net/patch/?group_id=10894

  * http://sourceforge.net/patch/?group_id=12997

A maintainer uses CVS via SSH to access, track, and modify the various
branches of development in the repository of official Tcl or Tk source
code.

|cvs -d :ext:[email protected]:/cvsroot/tcl \
|   checkout -r $BRANCH_TAG -d $LOCAL_DIR tcl
|
|cvs -d :ext:[email protected]:/cvsroot/tktoolkit \
|   checkout -r $BRANCH_TAG -d $LOCAL_DIR tk

A maintainer examines the state of Tcl Improvement Proposals (TIPs) and
adds his comments to them at the TIP Document Collection.

  * http://purl.org/tcl/home/cgi-bin/tct/tip/

A maintainer may follow and participate in TCT discussions about TIPs
and other matters concerning Tcl/Tk development on the TCLCORE mailing
list.

  * http://lists.sourceforge.net/lists/listinfo/tcl-core

A maintainer may receive e-mail notification every time any change is
made to any entry in Tcl's or Tk's Bug Tracker or Patch Manager by
subscribing to the TCLBUGS mailing list.

  * http://lists.sourceforge.net/lists/listinfo/tcl-bugs

~ There are multiple maintainers in my area.  What do I do?

The maintainer tasks are the same; you just have more hands to get the
job done.  It is up to the maintainers of an area to decide among
themselves how they will divide the tasks.  They might each take on a
particular subset of files.  Or they might let some maintainers fix
bugs while others review new features.  Or they might appoint one
maintainer as the ''lead'' and let him assign tasks to the others.
Whatever works for you, and gets the work done.

~ I found a bug in my area.  What do I do?

Bug finding and reporting is a job for the whole community, so when
you find a bug, take off your maintainer hat.  Report it to the Bug
Tracker just like anyone would.  If you recognize that the bug is in
your area, go ahead and assign it to the Category for your area and to
yourself or one of the other maintainers who share responsibility for
that area.

~ Why do I report the bug to myself?

So that the bug appears in the database.  Someone else may find it
too, and when they go to report it to the Bug Tracker, they should
discover that it's an already reported problem.  A registered bug
report is also the place where progress on fixing the bug can be
recorded for all to see.

~ There's a bug reported in the Category for the area I maintain. What do I do?

First, understand the bug report.  The best bug reports are clear and
come with a demonstration script, but not all reports are so well
crafted.  You may need to exchange messages with the person who
reported the bug.  If the reporter logged in to SourceForge as
''username'' before submitting a report, then you can write back to
''[email protected]''.  If the bug was reported by
''nobody'', the best you can do is post a followup comment to the bug
asking for more information, and hope the reporter comes back to
check.

Next, confirm that the bug report is valid, original, and that it
belongs in your area.  Does it correctly assert that some public
interface provided by your area behaves differently from its
documented behavior?  If not, then you should take the appropriate
action:

  1. If the bug report notes a problem in another project, assign it
     to a Developer who is an Admin of the other project.  Add a
     comment asking them to reassign to the correct project.  Assigned
     To: ''an Admin of the other project''.

  >  If no Developer is an Admin of the other project, or the other
     project isn't hosted by SourceForge, note the error in a comment,
     and mark the report invalid.  Resolution: Invalid; Status:
     Closed; Assigned To: ''yourself''.

  1. If the bug report notes a problem due to a bug in another area,
     reassign it to the appropriate Category.  Category: ''correct
     category''

  1. If the reporter's expectations are incorrect, point them to the
     documentation.  You may also want to revise the documentation if
     it is not clear.  Resolution: Invalid; Status: Closed; Assigned
     To: ''yourself''.

  1. If the bug report notes a problem already noted by another bug
     report, note the duplication.  Resolution: Duplicate; Status:
     Closed; Assigned To: ''yourself''.

  1. If the bug report acknowledges that the code is behaving as
     documented, but argues that the documented behavior should be
     revised, then the report is a feature request rather than a bug
     report.  More on handling feature requests below.  Group: Feature
     Request.

Valid, original bug reports in your area should be assigned to a
maintainer of your area.  If you are the only maintainer of your area,
assign the bug to yourself.  If there are multiple maintainers, you
should decide among yourselves how to divide up the bug report
assignments.

~ There's a bug assigned to me.  What do I do?

Now we get the the heart of what a maintainer does.  This is where you
unleash the energies and talents you bring to the table.  So, the best
answer is "Do what works best for you." The rest of this answer should
be read as additional guidelines and tips that have worked well for
others and might help you, but not as a mandatory checklist you must
follow.  If some advice below seems more burdensome than helpful, fall
<
|
<
|
|
|
|
|
|
>

|


|

|


|



|
|


|

|
|




|





|











|

|
|



|











|



|







|





|

|

|


|
|




|




|


|

|

|


|

|

|





|
|
|
|
|

|


|





|





|

|






|


|








|







|





|
|
|












|

|


|


|
|




|



|













|








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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237

# TIP 28: How to be a good maintainer for Tcl/Tk

	Author:         Don Porter <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        23-Feb-2001
	Post-History:   
-----

# Abstract

This document presents information and advice to maintainers in the
form of a Frequently Asked Questions \(FAQ\) list.

# Preface

Notice in the header above that this is a Draft document.  It won't be
the _official_ word of the TCT unless/until it is accepted by the
TCT.  Meanwhile, it should still be a helpful guide to those serving
or considering service as maintainers.  At the very least it's a
useful straw man to revise into something better.  Help us make it
even more useful by using the [Edit] link at the bottom of this page
\(if any\) to add/revise the questions and answers, or add your
comments.

# Background

TCT procedures \(see [[0]](0.md)\) calls for one or more _maintainers_ to take
responsibility for each functional area of the Tcl \([[16]](16.md)\) or Tk \([[23]](23.md)\)
source code.  Every source code patch to Tcl or Tk will be committed
to the official branches of the appropriate CVS repository only after
approval by an appropriate set of maintainers.

# Can I be a Tcl/Tk maintainer?

Most likely.  To be a maintainer, you should have...

 * ...an interest in Tcl/Tk.

 * ...access to the Internet \(Web and e-mail\).

 * ...some volunteer time to contribute.

 * ...the ability and the support software to code in C and/or Tcl,
   use CVS, use SourceForge facilities, and familiarity with a portion
   of the Tcl/Tk source code to be maintained, or the willingness to
   acquire these things.

For the most part, if you are reading this document, you probably have
what it takes to be a Tcl/Tk maintainer.

# What can I maintain?

The Tcl Core Team \(TCT\) has divided up the Tcl/Tk source code into
functional areas as described in [[16]](16.md) and [[23]](23.md).  You can volunteer to
help maintain as many areas as you think you can handle.  Select those
you have experience with or an interest in.

# What does a maintainer do?

Maintainers are the people who make changes to the files that make up
the source code distribution of Tcl or Tk -- code, documentation, and
tests.  That's what a maintainer does: check in changes to the
official source code in the area he/she maintains.

The source code can be changed for several reasons: to correct a bug,
to add a new feature, or to re-implement an existing feature in a new
way.  The reason for a change controls how much oversight the
maintainer must have while making the change.  More on this below.

# How do I prepare to be a maintainer?

The official repositories of Tcl and Tk source code are kept at
SourceForge, so you need to register for a SourceForge account
<https://sourceforge.net/account/register.php> .  As part of the
registration, you will select a login name.  When you volunteer as a
maintainer, the administrators of the Tcl or Tk projects will need
that name to give you write access to the appropriate repository.

Once you have a SourceForge account, get familiar with the tools it
provides.  Most important is that you get set up to use CVS over SSH
to access the repository.  This can be difficult.  There are some
notes <http://tcltk.org/sourceforge>  on how other Developers on the
Tcl and Tk projects have been able to successfully get this done.

This document does not include instructions on how to use CVS.  See
the following references for assistance with learning CVS.

 * <http://cvsbook.red-bean.com/cvsbook.html>

_Add more references here please._

# How do I volunteer to be a maintainer?

Send a message to <[email protected]> telling the TCT
your SourceForge login name and what area\(s\) you want to help
maintain.  Someone will add you to the list of _Developers_ on the
Tcl or Tk projects and enable your access to SourceForge features like
the Bug Tracker and Patch Manager.  As a Developer, you will have
write access to the appropriate repository of official source code.

# Write access!  So I can just start changing Tcl/Tk?!

For some purposes, yes.  For others, you'll need to get approval from
the TCT first.  Read on...

# What Internet resources does a maintainer use?

A maintainer uses the SourceForge Bug Tracker for Tcl or Tk to learn
what bugs are reported in his area \(browse by Category\).

  * <http://sourceforge.net/bugs/?group\_id=10894>

  * <http://sourceforge.net/bugs/?group\_id=12997>

A maintainer uses the SourceForge Patch Manager for Tcl or Tk to learn
what patches make changes in his area \(browse by Category\).

  * <http://sourceforge.net/patch/?group\_id=10894>

  * <http://sourceforge.net/patch/?group\_id=12997>

A maintainer uses CVS via SSH to access, track, and modify the various
branches of development in the repository of official Tcl or Tk source
code.

	cvs -d :ext:[email protected]:/cvsroot/tcl \
	   checkout -r $BRANCH_TAG -d $LOCAL_DIR tcl
	
	cvs -d :ext:[email protected]:/cvsroot/tktoolkit \
	   checkout -r $BRANCH_TAG -d $LOCAL_DIR tk

A maintainer examines the state of Tcl Improvement Proposals \(TIPs\) and
adds his comments to them at the TIP Document Collection.

  * <http://purl.org/tcl/home/cgi-bin/tct/tip/>

A maintainer may follow and participate in TCT discussions about TIPs
and other matters concerning Tcl/Tk development on the TCLCORE mailing
list.

  * <http://lists.sourceforge.net/lists/listinfo/tcl-core>

A maintainer may receive e-mail notification every time any change is
made to any entry in Tcl's or Tk's Bug Tracker or Patch Manager by
subscribing to the TCLBUGS mailing list.

  * <http://lists.sourceforge.net/lists/listinfo/tcl-bugs>

# There are multiple maintainers in my area.  What do I do?

The maintainer tasks are the same; you just have more hands to get the
job done.  It is up to the maintainers of an area to decide among
themselves how they will divide the tasks.  They might each take on a
particular subset of files.  Or they might let some maintainers fix
bugs while others review new features.  Or they might appoint one
maintainer as the _lead_ and let him assign tasks to the others.
Whatever works for you, and gets the work done.

# I found a bug in my area.  What do I do?

Bug finding and reporting is a job for the whole community, so when
you find a bug, take off your maintainer hat.  Report it to the Bug
Tracker just like anyone would.  If you recognize that the bug is in
your area, go ahead and assign it to the Category for your area and to
yourself or one of the other maintainers who share responsibility for
that area.

# Why do I report the bug to myself?

So that the bug appears in the database.  Someone else may find it
too, and when they go to report it to the Bug Tracker, they should
discover that it's an already reported problem.  A registered bug
report is also the place where progress on fixing the bug can be
recorded for all to see.

# There's a bug reported in the Category for the area I maintain. What do I do?

First, understand the bug report.  The best bug reports are clear and
come with a demonstration script, but not all reports are so well
crafted.  You may need to exchange messages with the person who
reported the bug.  If the reporter logged in to SourceForge as
_username_ before submitting a report, then you can write back to
_[email protected]_.  If the bug was reported by
_nobody_, the best you can do is post a followup comment to the bug
asking for more information, and hope the reporter comes back to
check.

Next, confirm that the bug report is valid, original, and that it
belongs in your area.  Does it correctly assert that some public
interface provided by your area behaves differently from its
documented behavior?  If not, then you should take the appropriate
action:

  1. If the bug report notes a problem in another project, assign it
     to a Developer who is an Admin of the other project.  Add a
     comment asking them to reassign to the correct project.  Assigned
     To: _an Admin of the other project_.

	  >  If no Developer is an Admin of the other project, or the other
     project isn't hosted by SourceForge, note the error in a comment,
     and mark the report invalid.  Resolution: Invalid; Status:
     Closed; Assigned To: _yourself_.

  1. If the bug report notes a problem due to a bug in another area,
     reassign it to the appropriate Category.  Category: _correct
     category_

  1. If the reporter's expectations are incorrect, point them to the
     documentation.  You may also want to revise the documentation if
     it is not clear.  Resolution: Invalid; Status: Closed; Assigned
     To: _yourself_.

  1. If the bug report notes a problem already noted by another bug
     report, note the duplication.  Resolution: Duplicate; Status:
     Closed; Assigned To: _yourself_.

  1. If the bug report acknowledges that the code is behaving as
     documented, but argues that the documented behavior should be
     revised, then the report is a feature request rather than a bug
     report.  More on handling feature requests below.  Group: Feature
     Request.

Valid, original bug reports in your area should be assigned to a
maintainer of your area.  If you are the only maintainer of your area,
assign the bug to yourself.  If there are multiple maintainers, you
should decide among yourselves how to divide up the bug report
assignments.

# There's a bug assigned to me.  What do I do?

Now we get the the heart of what a maintainer does.  This is where you
unleash the energies and talents you bring to the table.  So, the best
answer is "Do what works best for you." The rest of this answer should
be read as additional guidelines and tips that have worked well for
others and might help you, but not as a mandatory checklist you must
follow.  If some advice below seems more burdensome than helpful, fall
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
feature is added to Tcl/Tk.  In those cases, add a comment to the
original bug report so those interested will know what is causing the
delay.  SourceForge may offer a way to denote these dependencies as
well.

If you have trouble fixing the bug, ask for help.  Try the other
maintainers of your area first.  Then try posting comments attached to
the original bug report.  Using ''cvs log'', you can get a list of
developers who've recently made changes to the files you maintain.
They might be able to offer advice, or explanations about why the code
is the way it is.  If none of these focused searches for help bears
fruit, then try broader requests to the TCLCORE mailing lists, or the
news:comp.lang.tcl newsgroup.

At any time, you may have several bugs assigned to you.  It will help







|







266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
feature is added to Tcl/Tk.  In those cases, add a comment to the
original bug report so those interested will know what is causing the
delay.  SourceForge may offer a way to denote these dependencies as
well.

If you have trouble fixing the bug, ask for help.  Try the other
maintainers of your area first.  Then try posting comments attached to
the original bug report.  Using _cvs log_, you can get a list of
developers who've recently made changes to the files you maintain.
They might be able to offer advice, or explanations about why the code
is the way it is.  If none of these focused searches for help bears
fruit, then try broader requests to the TCLCORE mailing lists, or the
news:comp.lang.tcl newsgroup.

At any time, you may have several bugs assigned to you.  It will help
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
    1. Other bug fixes are waiting on this bug fix.

    1. Several duplicate reports or "me too" comments about the bug
       are coming in from the community.

Some reasons you might give a bug a lower priority include:

    1. A workaround is identified (add it as a comment attached to the
       bug report).

    1. Feature requests tend to get lower priority since they should
       be handled through the TIP process.

Once you have crafted a fix for the bug, create a patch to the
official source code (including the new tests that test for the fixed
bug) and register it with the SourceForge Patch Manager.  Note the
number of the bug report fixed by the patch somewhere in the summary
or comments associated with the patch.  Assign the patch to yourself.
Assign the Category to the area you maintain.

~ There's a patch registered under the Category I maintain.  What do I do?

The SourceForge Patch Manager is used to review and revise patches
before they are committed to the official source code.  Your actions
depend on what the patch does to your area, and who the patch is
assigned to.  The patch may change the public interface provided by
your area (feature change); or the change may be completely internal
(bug fix, or re-implementation) within your area.  The patch may be
assigned to you, to someone else, or to nobody.  The person the patch
is assigned to is the person who is leading the effort to integrate
the patch into the official source code.

~ What if the patch is assigned to nobody?

The patch has probably been contributed by someone not on the list of
Developers.  It may be a contributed bug fix, or a contributed
implementation of a TIP.  Assign contributed bug fixes to the same
maintainer who is assigned the corresponding bug report.  If there is
no corresponding bug report, add one.  Assign TIP implementations to
the Developer identified in the TIP as the one responsible for
implementation of that TIP, or the TCT member who sponsored the TIP.

If the patch changes only your area (and shared or generated files),
then leave the Category in your area.  If the patch changes other
areas as well as yours, change the category to None.

~ What if the patch is assigned to me?

Presumably you've assigned it to yourself to indicate that you're
taking charge of integrating that patch into the official sources.  If
that's a mistake, treat the patch as if it were assigned to nobody.
If you are the one leading the integration effort, see below (How do I
integrate a patch into the official sources?).

~ What if the patch is assigned to someone else?

If the patch is assigned to another maintainer in your area, let him
handle it.  Leave it alone.

If the patch makes no changes in your area, change the Category of the
patch to None.

If the patch makes changes in your area, and is assigned to a
Developer who is not a maintainer of your area, that Developer is
asking for review of the patch's changes to your area.  You or one of
the other maintainers of your area should review the patch and accept
or reject it.  Read on...

~ What special review does a "feature change" patch require?

Changes to the public interface of your section must be proposed to
and accepted by the TCT through the TIP process before they can be
added to the official Tcl source code.  If the patch changes the
public interface of your section, then there should be an associated
TIP describing the new feature(s) that patch implements.  Until there
is such a TIP, and that TIP has been accepted by the TCT (check the
value of the State header), you should not approve the patch.

Once there is an approved TIP corresponding to the patch, you should
confirm that the patch correctly implements the accepted feature as
described by the TIP.  If not, you should not approve the patch.

After confirming that the patch correctly implements the feature
change described in an accepted TIP, you should still review the
technical merit of the patch's changes to your area before approving
it.

~ How do I review the technical merits of a patch?

Apply the patch and run the test suites that cover your area.  Check
that the patch does not add any new test failures.  If the patch is a
bug fix, check that it actually fixes the bug.  Think five times
before approving a patch that causes new test failures or incompletely
fixes a bug or incompletely implements an approved TIP.

Keep in mind that once the patch is integrated into the official
sources, you'll be expected to maintain it.  It is not in your
interest to approve patches that make your job harder.  Think four
times before approving a patch that you do not understand.

Check that the patch keeps the features offered on different platforms
consistent.  If not, be certain that the documentation properly notes
the platform-specific behavior.  Think three times before approving a
patch that causes the capabilities of Tcl/Tk to further diverge on
different platforms.

Check that the patch follows Tcl's established coding conventions.
See the Tcl/Tk Engineering Manual
[http://purl.org/tcl/home/doc/engManual.pdf] and the Tcl Style Guide
[http://purl.org/tcl/home/doc/styleGuide.pdf] for details.  This is
especially important when accepting contributed patches.  Think twice
before approving a patch that doesn't conform to these conventions.

Check the effect of the patch on the performance of Tcl/Tk.  Use the
tclbench set of benchmarks.

|cvs -d :pserver:[email protected]:/cvsroot/tcllib \
|      checkout tclbench

Think carefully before approving a patch that significantly degrades
the performance of important operations.

Finally, while examining the patch, you may see a better way to
accomplish the effect of the changes in your area.  If you can provide
that alternative implementation reasonably quickly, then propose it as







|
|





|
|




|





|
|




|









|



|




|
|

|













|





|
|
|










|




















|
|






|
|







290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
    1. Other bug fixes are waiting on this bug fix.

    1. Several duplicate reports or "me too" comments about the bug
       are coming in from the community.

Some reasons you might give a bug a lower priority include:

    1. A workaround is identified \(add it as a comment attached to the
       bug report\).

    1. Feature requests tend to get lower priority since they should
       be handled through the TIP process.

Once you have crafted a fix for the bug, create a patch to the
official source code \(including the new tests that test for the fixed
bug\) and register it with the SourceForge Patch Manager.  Note the
number of the bug report fixed by the patch somewhere in the summary
or comments associated with the patch.  Assign the patch to yourself.
Assign the Category to the area you maintain.

# There's a patch registered under the Category I maintain.  What do I do?

The SourceForge Patch Manager is used to review and revise patches
before they are committed to the official source code.  Your actions
depend on what the patch does to your area, and who the patch is
assigned to.  The patch may change the public interface provided by
your area \(feature change\); or the change may be completely internal
\(bug fix, or re-implementation\) within your area.  The patch may be
assigned to you, to someone else, or to nobody.  The person the patch
is assigned to is the person who is leading the effort to integrate
the patch into the official source code.

# What if the patch is assigned to nobody?

The patch has probably been contributed by someone not on the list of
Developers.  It may be a contributed bug fix, or a contributed
implementation of a TIP.  Assign contributed bug fixes to the same
maintainer who is assigned the corresponding bug report.  If there is
no corresponding bug report, add one.  Assign TIP implementations to
the Developer identified in the TIP as the one responsible for
implementation of that TIP, or the TCT member who sponsored the TIP.

If the patch changes only your area \(and shared or generated files\),
then leave the Category in your area.  If the patch changes other
areas as well as yours, change the category to None.

# What if the patch is assigned to me?

Presumably you've assigned it to yourself to indicate that you're
taking charge of integrating that patch into the official sources.  If
that's a mistake, treat the patch as if it were assigned to nobody.
If you are the one leading the integration effort, see below \(How do I
integrate a patch into the official sources?\).

# What if the patch is assigned to someone else?

If the patch is assigned to another maintainer in your area, let him
handle it.  Leave it alone.

If the patch makes no changes in your area, change the Category of the
patch to None.

If the patch makes changes in your area, and is assigned to a
Developer who is not a maintainer of your area, that Developer is
asking for review of the patch's changes to your area.  You or one of
the other maintainers of your area should review the patch and accept
or reject it.  Read on...

# What special review does a "feature change" patch require?

Changes to the public interface of your section must be proposed to
and accepted by the TCT through the TIP process before they can be
added to the official Tcl source code.  If the patch changes the
public interface of your section, then there should be an associated
TIP describing the new feature\(s\) that patch implements.  Until there
is such a TIP, and that TIP has been accepted by the TCT \(check the
value of the State header\), you should not approve the patch.

Once there is an approved TIP corresponding to the patch, you should
confirm that the patch correctly implements the accepted feature as
described by the TIP.  If not, you should not approve the patch.

After confirming that the patch correctly implements the feature
change described in an accepted TIP, you should still review the
technical merit of the patch's changes to your area before approving
it.

# How do I review the technical merits of a patch?

Apply the patch and run the test suites that cover your area.  Check
that the patch does not add any new test failures.  If the patch is a
bug fix, check that it actually fixes the bug.  Think five times
before approving a patch that causes new test failures or incompletely
fixes a bug or incompletely implements an approved TIP.

Keep in mind that once the patch is integrated into the official
sources, you'll be expected to maintain it.  It is not in your
interest to approve patches that make your job harder.  Think four
times before approving a patch that you do not understand.

Check that the patch keeps the features offered on different platforms
consistent.  If not, be certain that the documentation properly notes
the platform-specific behavior.  Think three times before approving a
patch that causes the capabilities of Tcl/Tk to further diverge on
different platforms.

Check that the patch follows Tcl's established coding conventions.
See the Tcl/Tk Engineering Manual
<http://purl.org/tcl/home/doc/engManual.pdf>  and the Tcl Style Guide
<http://purl.org/tcl/home/doc/styleGuide.pdf>  for details.  This is
especially important when accepting contributed patches.  Think twice
before approving a patch that doesn't conform to these conventions.

Check the effect of the patch on the performance of Tcl/Tk.  Use the
tclbench set of benchmarks.

	cvs -d :pserver:[email protected]:/cvsroot/tcllib \
	      checkout tclbench

Think carefully before approving a patch that significantly degrades
the performance of important operations.

Finally, while examining the patch, you may see a better way to
accomplish the effect of the changes in your area.  If you can provide
that alternative implementation reasonably quickly, then propose it as
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582

you can supply the needed revisions with reasonable effort, do so.  If
the patch changes multiple areas, set the Category of the patch back
to None.

Unless the patch is assigned to you, do not change the Status of the
patch.  Leave that to the Developer assigned to the patch.

~ How do I integrate a patch into the official sources?

First you need the approval of at least one maintainer of each section
changed by the patch.

~ How do I get approval for integration?

First, assign the patch to yourself to indicate that you are leading
the integration effort.  Next, determine the list of categories
corresponding to the areas changed by the patch.  It may help if you
list them in a comment attached to the patch.

For each category in the list, assign the Category of the patch to
that category.  Then wait for a maintainer for that area to review the
patch.  If one approves it, then assign the next Category in the list.
If maintainers for all areas on the list approve the same patch, you
may integrate the patch into the official sources.

If a maintainer rejects the patch, revise the patch to address his
concerns.  Then start the review again.  Start with the maintainer who
rejected the first patch to be sure his concerns are addressed first.

Note that if the patch changes only the area you maintain, then you
may immediately integrate the patch into the official sources once you
are satisfied with it and it is registered in the Patch Manager.

~ The patch is approved.  How should it be integrated?

Get a CVS working directory that is up to date with the HEAD branch of
the official source repository.  Apply the patch to your working
directory, and then 'cvs commit' the changes to the HEAD branch.

At the same time you commit the patch, be sure to add an entry to the
ChangeLog file describing the change.  Follow the established format,
which is derived from the GNU coding conventions.  The description
should be brief, but should describe the change reasonably completely.
Include the SourceForge Bug and Patch ID numbers in the ChangeLog
entry, but do not assume that the reader will have access to the Bug
Tracker and Patch Manager to be able to understand the entry.  You may
assume the reader has access to the documentation.

Finally, with the patch integrated, change the Status of the patch in
the Patch Manager to Accepted.  If any bugs were fixed by the patch,
change their Resolution to Fixed, and their Status to Closed.

~ I want a patch review even though the patch changes only my area.

Keep in mind that integrating a patch into the official sources is not
an irreversible act.  Commits to the HEAD branch will be checked out
and tested by members of the Tcl community who are tracking Tcl/Tk
development.  Alpha and beta releases of Tcl/Tk that include your
patch will also get your changes reviewed in practical settings.

That said, if you really want a pre-commit review of your patch, you
can add a comment to the patch asking for review.  Someone will
probably respond.  It's up to your judgment how long to wait, keeping
in mind that you are the maintainer, so your judgment on the quality
of patches in your area is implicitly trusted.

~ What about CVS branches?

When you integrate a patch into the official source code, you will
usually 'cvs commit' the patch onto the HEAD branch.  If the patch
includes a feature change, it must (except in unusual circumstances
approved by the TCT) be committed to the HEAD branch.  The HEAD branch
is the development branch from which alpha releases of Tcl/Tk are
generated.

At any time, there is also one or more ''stable'' branches of
development.  As of February, 2001, the branch 'core-8-3-1-branch'
indicates the sequence of revisions from which the 8.3.x releases of
Tcl/Tk are generated.

Since the Tcl Core Team took over development of Tcl/Tk, no changes
have been committed to a stable branch, so we really have not
established procedures on how we will decide what bug fixes should and
should not be applied to the stable branch.  It is possible that
maintainers will be involved, though.  It is also possible that a
special team will be appointed to update the stable branch in
preparation for the next stable release.  In the case that you as a
maintainer are asked to commit to the stable branch, be aware that the
only patches that should be committed to a stable branch are those
that fix bugs.  No new features should be committed here.

The other kind of branch is a ''feature'' branch.  This is a
development branch on which a sequence of several revisions may be
committed as work in progress on a new feature, or re-implementation
of existing features.  Typically a feature branch will be created if
the effort...

   * ...touches on several functional areas;

   * ...is worked on jointly by several Developers;

   * ...is complex enough to require several revisions;

   * ...needs prototyping to determine the best TIP proposal to make;
     or

   * ...makes an incompatible change to Tcl/Tk that properly belongs
     on the next major version of Tcl/Tk before the HEAD branch has
     been designated for work toward the next major version.

As a Developer, feel free to create a feature branch if you have a
reason to use one.  Make a note of your branch tags in [31].  Avoid
the use of a branch tag matching core-* .
Save the core-* branch tags for the tags of official stable branches
and releases.  To avoid conflict with other Developers, consider using
your SourceForge login name as a prefix on the feature branch tags you
create.  Try to also make the branch tag descriptive of the purpose of
the branch.

One big advantage of a feature branch is that any Developer may commit
changes to a feature branch without all the publication, review, and
approval overhead required when committing patches to the HEAD or
stable branches.  On the feature branches you can go through multiple
revisions reasonably quickly and spend the administrative overhead
only at the end when it is time to apply the finished product to the
official branches.

~ What other things does a maintainer do?

The tasks of fixing bugs and approving and committing patches to the
official source code of Tcl and Tk are the core tasks that maintainers
perform.  That's all the job actually requires.

You will probably want to keep an eye on the TCT's plans for Tcl/Tk
development as well.  If a TIP proposes a new feature in your area, it
is in your interest to know about it, and propose revisions and
improvements to it.  Ultimately you will be asked to approve the patch
that implements the new feature, and then you will be expected to
maintain it, so if you have concerns about a proposal, it's best to
make them known early.  TCT members will probably ask your opinion on
TIPs that propose changes to your area for this reason.

~ Comments

Please add your comments here.

   > Well, since I drafted this SourceForge has replaced the
     Bug Tracker and Patch Manager with a ''Tracker''.  This
     TIP ''really'' needs revision now.

~ Copyright

This document has been placed in the public domain.








|




|




















|


















|













|



|
|



|















|



















|
|
|













|














|




|
|

|


>
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
you can supply the needed revisions with reasonable effort, do so.  If
the patch changes multiple areas, set the Category of the patch back
to None.

Unless the patch is assigned to you, do not change the Status of the
patch.  Leave that to the Developer assigned to the patch.

# How do I integrate a patch into the official sources?

First you need the approval of at least one maintainer of each section
changed by the patch.

# How do I get approval for integration?

First, assign the patch to yourself to indicate that you are leading
the integration effort.  Next, determine the list of categories
corresponding to the areas changed by the patch.  It may help if you
list them in a comment attached to the patch.

For each category in the list, assign the Category of the patch to
that category.  Then wait for a maintainer for that area to review the
patch.  If one approves it, then assign the next Category in the list.
If maintainers for all areas on the list approve the same patch, you
may integrate the patch into the official sources.

If a maintainer rejects the patch, revise the patch to address his
concerns.  Then start the review again.  Start with the maintainer who
rejected the first patch to be sure his concerns are addressed first.

Note that if the patch changes only the area you maintain, then you
may immediately integrate the patch into the official sources once you
are satisfied with it and it is registered in the Patch Manager.

# The patch is approved.  How should it be integrated?

Get a CVS working directory that is up to date with the HEAD branch of
the official source repository.  Apply the patch to your working
directory, and then 'cvs commit' the changes to the HEAD branch.

At the same time you commit the patch, be sure to add an entry to the
ChangeLog file describing the change.  Follow the established format,
which is derived from the GNU coding conventions.  The description
should be brief, but should describe the change reasonably completely.
Include the SourceForge Bug and Patch ID numbers in the ChangeLog
entry, but do not assume that the reader will have access to the Bug
Tracker and Patch Manager to be able to understand the entry.  You may
assume the reader has access to the documentation.

Finally, with the patch integrated, change the Status of the patch in
the Patch Manager to Accepted.  If any bugs were fixed by the patch,
change their Resolution to Fixed, and their Status to Closed.

# I want a patch review even though the patch changes only my area.

Keep in mind that integrating a patch into the official sources is not
an irreversible act.  Commits to the HEAD branch will be checked out
and tested by members of the Tcl community who are tracking Tcl/Tk
development.  Alpha and beta releases of Tcl/Tk that include your
patch will also get your changes reviewed in practical settings.

That said, if you really want a pre-commit review of your patch, you
can add a comment to the patch asking for review.  Someone will
probably respond.  It's up to your judgment how long to wait, keeping
in mind that you are the maintainer, so your judgment on the quality
of patches in your area is implicitly trusted.

# What about CVS branches?

When you integrate a patch into the official source code, you will
usually 'cvs commit' the patch onto the HEAD branch.  If the patch
includes a feature change, it must \(except in unusual circumstances
approved by the TCT\) be committed to the HEAD branch.  The HEAD branch
is the development branch from which alpha releases of Tcl/Tk are
generated.

At any time, there is also one or more _stable_ branches of
development.  As of February, 2001, the branch 'core-8-3-1-branch'
indicates the sequence of revisions from which the 8.3.x releases of
Tcl/Tk are generated.

Since the Tcl Core Team took over development of Tcl/Tk, no changes
have been committed to a stable branch, so we really have not
established procedures on how we will decide what bug fixes should and
should not be applied to the stable branch.  It is possible that
maintainers will be involved, though.  It is also possible that a
special team will be appointed to update the stable branch in
preparation for the next stable release.  In the case that you as a
maintainer are asked to commit to the stable branch, be aware that the
only patches that should be committed to a stable branch are those
that fix bugs.  No new features should be committed here.

The other kind of branch is a _feature_ branch.  This is a
development branch on which a sequence of several revisions may be
committed as work in progress on a new feature, or re-implementation
of existing features.  Typically a feature branch will be created if
the effort...

   * ...touches on several functional areas;

   * ...is worked on jointly by several Developers;

   * ...is complex enough to require several revisions;

   * ...needs prototyping to determine the best TIP proposal to make;
     or

   * ...makes an incompatible change to Tcl/Tk that properly belongs
     on the next major version of Tcl/Tk before the HEAD branch has
     been designated for work toward the next major version.

As a Developer, feel free to create a feature branch if you have a
reason to use one.  Make a note of your branch tags in [[31]](31.md).  Avoid
the use of a branch tag matching core-\* .
Save the core-\* branch tags for the tags of official stable branches
and releases.  To avoid conflict with other Developers, consider using
your SourceForge login name as a prefix on the feature branch tags you
create.  Try to also make the branch tag descriptive of the purpose of
the branch.

One big advantage of a feature branch is that any Developer may commit
changes to a feature branch without all the publication, review, and
approval overhead required when committing patches to the HEAD or
stable branches.  On the feature branches you can go through multiple
revisions reasonably quickly and spend the administrative overhead
only at the end when it is time to apply the finished product to the
official branches.

# What other things does a maintainer do?

The tasks of fixing bugs and approving and committing patches to the
official source code of Tcl and Tk are the core tasks that maintainers
perform.  That's all the job actually requires.

You will probably want to keep an eye on the TCT's plans for Tcl/Tk
development as well.  If a TIP proposes a new feature in your area, it
is in your interest to know about it, and propose revisions and
improvements to it.  Ultimately you will be asked to approve the patch
that implements the new feature, and then you will be expected to
maintain it, so if you have concerns about a proposal, it's best to
make them known early.  TCT members will probably ask your opinion on
TIPs that propose changes to your area for this reason.

# Comments

Please add your comments here.

   > Well, since I drafted this SourceForge has replaced the
     Bug Tracker and Patch Manager with a _Tracker_.  This
     TIP _really_ needs revision now.

# Copyright

This document has been placed in the public domain.

Name change from tip/280.tip to tip/280.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
TIP:		280
Title:		Add Full Stack Trace Capability With Location Introspection
Version:	$Revision: 1.13 $
Author:		Andreas Kupries <[email protected]>
Author:		Andreas Kupries <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	10-Aug-2004
Post-History:	
Keywords:	Tcl
Obsoletes:	211
Tcl-Version:	8.5


~ Abstract

This TIP proposes adding a new subcommand to the '''info''' command to get a
list of all the frames on the current stack, with additional information about
command location, type of execution, etc., rather than the limited list
returned by '''info level'''. It is also related to Peter MacDonald's [86], or
rather, to the '''info linenum''' feature proposed there. The base feature of
providing location information for a command was extended, allowing the user
to ask for the current location in all stack levels. Enough information is
returned to consider this as an extended [211].

~ Rationale

The motivation for this feature is the debugging of scripts in situations
where an error stack is wanted, to see where the problem occurred, but
aborting the execution is not desired. To enable this a means of providing the
essential information shown in an error stack is needed, which does not
require an abort (and subsequent unwinding of the C stack) to assemble this
information.

An example is the testing of scripts where an unexpected error should not fail
the test case, nor the framework, yet still allow the recording of the
problematic location and how it was reached in some log.

The original motivation for [211] was that there is currently no way to get a
list of all the frames in the current stack managed by
'''Tcl_PushCallFrame()''' and '''Tcl_PopCallFrame()'''. The '''info level'''
command does not contain frames that are callers of '''uplevel''', reporting
only the frames that are accessible via another '''uplevel''' command. There
are times when the lack of information can have a negative impact on code
design.

This motivation asks in essence for an error stack as well, but limited itself
to the returning commands themselves, and not the other information, like the
line the command is on, its context, etc.

Other use cases, also found in [211]:

 1. '''tcltest''', and other testing frameworks.

 > The first case is with the core's Tcltest package, where the
   complete lack of ability to gain access to that information means
   it is impossible to gain information about a test without modifying
   the Tcltest code itself. Being able to find out the caller info
   would be very useful, especially for logging information. Currently,
   there is no way to get the caller's info, due to the fact that the
   code for the test is ''uplevel''ed and, hence, not visible via
   '''info level'''.

 2. '''TestStubs Package'''

 > The TestStubs package provides the ability to temporarily redefine
   commands, in particular for stubbing out or replacing functionality in a
   test case. There is a command in the package called '''chain''', which is
   used within the code replacing a command (or part of a command) to call the
   original definition of the command. For example, one could do:

|stubs::stub ensemble array names {
|    return [lsort [uplevel 1 chain names $args]]
|}

 > However, since the '''chain''' command is (and should be) limited to only

   running from within a stub definition, it needs to call '''info level''' to
   find out if its caller is one of the stubbed commands, and what the name of
   that command is. With '''info level''', it would not have access to the
   level that is running inside the stubbed procedure. Hence, either it cannot
   check this constraint, or stubs cannot be allowed to use '''uplevel''' when
   calling it (which means things like the above either cannot work, or need
   to be rewritten in a considerably less clear manner).

~ Specification of the Proposed Change

~~ Tcl Level API

The builtin command '''info''' is extended to accept a new subcommand,
'''frame'''. When this subcommand is called it returns information about the
current command and its location. This information is available not only for
the current stack level, but also the higher stack levels used to reach the
current location.

The syntax of the new subcommand is

 > '''info frame''' ?''level''?

The new functionality will provide access to all frames on the stack rather
than the current limited subset. This TIP does ''not'' propose to alter
'''uplevel''' or '''upvar''' so that they can see these hidden levels.

If ''level'' is not specified, this command returns a number giving the frame
level of the command. This is 1 if the command is invoked at top-level.

If ''level'' is specified, then the result is a dictionary containing the
location information for the command at the ''level'' on the stack.

If ''level'' is positive (> 0) then it selects a particular stack level (1
refers to the top-most active command, i.e., '''info frame''' itself, 2 to the
command it was called from, and so on); otherwise it gives a level relative to
the current command (0 refers to the current command, i.e., '''info frame'''
itself, -1 to its caller, and so on).

This is similar to how '''info level''' works, except that this subcommand
reports all frames, like '''source''''d scripts, '''eval'''s, '''uplevel'''s,
etc.

Note that for nested commands, like "foo [[bar [[x]]]]" only "x" will be seen
by an '''info frame''' invoked within "x". This is the same as for '''info
level''' and error stack traces.

The result dictionary may contain the keys listed below, with the specified
meanings for their values.

 * '''type'''

 > This entry is always present and describes the nature of the location for
   the command. The recognized values are '''source''', '''proc''',
   '''eval''', and '''precompiled'''.

 > In some circumstances it makes sense to have this information extensible,
   i.e. to allow user-defined type names. For more about this topic see the
   discussion at the end of the document.

 > * '''source''' means that the command is found in a script loaded by the
     '''source''' command.

 > * '''proc''' means that the command is found in dynamically created
     procedure body.

 > * '''eval''' means that the command is executed by '''eval''' or
     '''uplevel'''.

 > * '''precompiled''' means that the command is found in a precompiled script
     (loadable by the package ''tbcload''), and no further information will be
     available.

 * '''line'''

 > This entry provides the number of the line the command is at inside of the
   script it is a part of. This information is not present for type
   '''precompiled'''. For type '''source''' this information is counted
   relative to the beginning of the file, whereas for the last two types the
   line is counted relative to the start of the script.

 * '''file'''

 > This entry is present only for type '''source'''. It provides the
   normalized path of the file the command is in.

 * '''cmd'''

 > This entry provides the string representation of the command. This is
   usually the unsubstituted form, however for commands which are a pure list
   executed by eval it is the substituted form as they have no other string
   representation. Care is taken that the pure-List property of the latter is
   not spoiled.

 * '''proc'''

 > This entry is present only if the command is found in the body of a regular
   Tcl procedure. It then provides the name of that procedure.

 * '''lambda'''

 > This entry is present only if the command is found in the body of an
   anonymous Tcl procedure, i.e. a lambda. It then provides the entire
   definition of the lambda in question.

 * '''level'''

 > This entry is present only if the queried frame has a corresponding frame
   returned by '''info level'''. It provides the index of this frame, relative
   to the current level (0 and negative numbers).

A thing of note is that for procedures statically defined in files the
locations of commands in their bodies will be reported with type '''source'''
and absolute line numbers, and not as type '''proc'''. The same is true for
procedures nested in statically defined procedures, and literal eval scripts
in files or statically defined procedures.

In contrast, for a procedure definition or eval within a dynamically
eval'uated environment count linenumbers relative to the start of their
script, even if they would be able to count relative to the start of the outer
dynamic script. That type of number usually makes more sense.

A different way of describing this behaviour is that we track file based
locations as deeply as we can, and where we cannot the lines are counted based
on the smallest possible eval or procbody scope, as that scope is usually
easier to find than any dynamic outer scope.

The syntactic form '''{expand}''' is handled like '''eval'''. This means that
if it is given a literal list argument the system tracks the line-number
within the list words as well, and otherwise all line-numbers are counted
relative to the start of each word (smallest scope)

The following other builtin commands are changed as well to support the
tracking of line numbers:

 1. catch

 1. dict for
<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|


|
|


|

|





|






|

|
|
|







|

|

|





|
|

|

|

|
|


|
|
<
|
|
>
|

|

|
|
|

|

|

|
|






|


|
|

|


|
|

|
|
|
|
|

|
|


|
|
|




|

|
|
|

|



|
|

|


|
|

|
|


|

|

|



|

|


|

|





|

|


|

|



|

|
|
|


|
|













|


|








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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212

# TIP 280: Add Full Stack Trace Capability With Location Introspection

	Author:		Andreas Kupries <[email protected]>
	Author:		Andreas Kupries <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	10-Aug-2004
	Post-History:	
	Keywords:	Tcl
	Obsoletes:	211
	Tcl-Version:	8.5
-----

# Abstract

This TIP proposes adding a new subcommand to the **info** command to get a
list of all the frames on the current stack, with additional information about
command location, type of execution, etc., rather than the limited list
returned by **info level**. It is also related to Peter MacDonald's [[86]](86.md), or
rather, to the **info linenum** feature proposed there. The base feature of
providing location information for a command was extended, allowing the user
to ask for the current location in all stack levels. Enough information is
returned to consider this as an extended [[211]](211.md).

# Rationale

The motivation for this feature is the debugging of scripts in situations
where an error stack is wanted, to see where the problem occurred, but
aborting the execution is not desired. To enable this a means of providing the
essential information shown in an error stack is needed, which does not
require an abort \(and subsequent unwinding of the C stack\) to assemble this
information.

An example is the testing of scripts where an unexpected error should not fail
the test case, nor the framework, yet still allow the recording of the
problematic location and how it was reached in some log.

The original motivation for [[211]](211.md) was that there is currently no way to get a
list of all the frames in the current stack managed by
**Tcl\_PushCallFrame\(\)** and **Tcl\_PopCallFrame\(\)**. The **info level**
command does not contain frames that are callers of **uplevel**, reporting
only the frames that are accessible via another **uplevel** command. There
are times when the lack of information can have a negative impact on code
design.

This motivation asks in essence for an error stack as well, but limited itself
to the returning commands themselves, and not the other information, like the
line the command is on, its context, etc.

Other use cases, also found in [[211]](211.md):

 1. **tcltest**, and other testing frameworks.

	 > The first case is with the core's Tcltest package, where the
   complete lack of ability to gain access to that information means
   it is impossible to gain information about a test without modifying
   the Tcltest code itself. Being able to find out the caller info
   would be very useful, especially for logging information. Currently,
   there is no way to get the caller's info, due to the fact that the
   code for the test is _uplevel_ed and, hence, not visible via
   **info level**.

 2. **TestStubs Package**

	 > The TestStubs package provides the ability to temporarily redefine
   commands, in particular for stubbing out or replacing functionality in a
   test case. There is a command in the package called **chain**, which is
   used within the code replacing a command \(or part of a command\) to call the
   original definition of the command. For example, one could do:

		stubs::stub ensemble array names {
		    return [lsort [uplevel 1 chain names $args]]

		}

	 > However, since the **chain** command is \(and should be\) limited to only
   running from within a stub definition, it needs to call **info level** to
   find out if its caller is one of the stubbed commands, and what the name of
   that command is. With **info level**, it would not have access to the
   level that is running inside the stubbed procedure. Hence, either it cannot
   check this constraint, or stubs cannot be allowed to use **uplevel** when
   calling it \(which means things like the above either cannot work, or need
   to be rewritten in a considerably less clear manner\).

# Specification of the Proposed Change

## Tcl Level API

The builtin command **info** is extended to accept a new subcommand,
**frame**. When this subcommand is called it returns information about the
current command and its location. This information is available not only for
the current stack level, but also the higher stack levels used to reach the
current location.

The syntax of the new subcommand is

 > **info frame** ?_level_?

The new functionality will provide access to all frames on the stack rather
than the current limited subset. This TIP does _not_ propose to alter
**uplevel** or **upvar** so that they can see these hidden levels.

If _level_ is not specified, this command returns a number giving the frame
level of the command. This is 1 if the command is invoked at top-level.

If _level_ is specified, then the result is a dictionary containing the
location information for the command at the _level_ on the stack.

If _level_ is positive \(> 0\) then it selects a particular stack level \(1
refers to the top-most active command, i.e., **info frame** itself, 2 to the
command it was called from, and so on\); otherwise it gives a level relative to
the current command \(0 refers to the current command, i.e., **info frame**
itself, -1 to its caller, and so on\).

This is similar to how **info level** works, except that this subcommand
reports all frames, like **source**'d scripts, **eval**s, **uplevel**s,
etc.

Note that for nested commands, like "foo [bar [x]]" only "x" will be seen
by an **info frame** invoked within "x". This is the same as for **info
level** and error stack traces.

The result dictionary may contain the keys listed below, with the specified
meanings for their values.

 * **type**

	 > This entry is always present and describes the nature of the location for
   the command. The recognized values are **source**, **proc**,
   **eval**, and **precompiled**.

	 > In some circumstances it makes sense to have this information extensible,
   i.e. to allow user-defined type names. For more about this topic see the
   discussion at the end of the document.

	 > \* **source** means that the command is found in a script loaded by the
     **source** command.

	 > \* **proc** means that the command is found in dynamically created
     procedure body.

	 > \* **eval** means that the command is executed by **eval** or
     **uplevel**.

	 > \* **precompiled** means that the command is found in a precompiled script
     \(loadable by the package _tbcload_\), and no further information will be
     available.

 * **line**

	 > This entry provides the number of the line the command is at inside of the
   script it is a part of. This information is not present for type
   **precompiled**. For type **source** this information is counted
   relative to the beginning of the file, whereas for the last two types the
   line is counted relative to the start of the script.

 * **file**

	 > This entry is present only for type **source**. It provides the
   normalized path of the file the command is in.

 * **cmd**

	 > This entry provides the string representation of the command. This is
   usually the unsubstituted form, however for commands which are a pure list
   executed by eval it is the substituted form as they have no other string
   representation. Care is taken that the pure-List property of the latter is
   not spoiled.

 * **proc**

	 > This entry is present only if the command is found in the body of a regular
   Tcl procedure. It then provides the name of that procedure.

 * **lambda**

	 > This entry is present only if the command is found in the body of an
   anonymous Tcl procedure, i.e. a lambda. It then provides the entire
   definition of the lambda in question.

 * **level**

	 > This entry is present only if the queried frame has a corresponding frame
   returned by **info level**. It provides the index of this frame, relative
   to the current level \(0 and negative numbers\).

A thing of note is that for procedures statically defined in files the
locations of commands in their bodies will be reported with type **source**
and absolute line numbers, and not as type **proc**. The same is true for
procedures nested in statically defined procedures, and literal eval scripts
in files or statically defined procedures.

In contrast, for a procedure definition or eval within a dynamically
eval'uated environment count linenumbers relative to the start of their
script, even if they would be able to count relative to the start of the outer
dynamic script. That type of number usually makes more sense.

A different way of describing this behaviour is that we track file based
locations as deeply as we can, and where we cannot the lines are counted based
on the smallest possible eval or procbody scope, as that scope is usually
easier to find than any dynamic outer scope.

The syntactic form **\{expand\}** is handled like **eval**. This means that
if it is given a literal list argument the system tracks the line-number
within the list words as well, and otherwise all line-numbers are counted
relative to the start of each word \(smallest scope\)

The following other builtin commands are changed as well to support the
tracking of line numbers:

 1. catch

 1. dict for
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355

356
357
358
359
360
361
362
363
364
365
366
367
368
369

370
371
372
373
374
375
376
377
378
379
380
381
382
383
384

385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431

432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454


 1. source

 1. switch

 1. while

~~ Public C API

No changes are made to the public C API.

~ Examples

Note that this is not a complete set of examples covering all possible cases.
Let us assume that the file is named EX. The "cmd" is always the "info frame
..." command, and "level" is 0 too, always, in this situation. This is left
out of the result dictionaries to keep them small.

| puts [info frame 0]           ;# 01* - output: {cmd {info frame 0} line 1 file EX type source}
|                               ;# 02
| proc foo {} {                 ;# 03  /foo remembers 3
|     puts [info frame 0]       ;# 04*
| }                             ;# 05
| foo                           ;# 06  - output: {cmd {...} line 4 file EX type source}
|                               ;# 07
| set script {                  ;# 08  1
|     puts [info frame 0]       ;# 09  2*
| }                             ;# 10  3
| eval $script                  ;# 11  - output: {cmd {...} line 2 type eval}
|                               ;# 12
| eval {                        ;# 13  1
|     puts [info frame 0]       ;# 14* 2*
| }                             ;# 15  3  - output: {cmd {...} line 14 type source}
|                               ;# 16
| proc fox {} {                 ;# 17  /fox remembers 17
|     eval $::script            ;# 18
| }                             ;# 19
| fox                           ;# 20  - output: {cmd {...} line 2 type eval}
|                               ;# 21
| proc squirrel {} {            ;# 22  /squirrel remembers 22
|     eval {                    ;# 23  1
|         puts [info frame 0]   ;# 24* 2*
|     }                         ;# 25  3
| }                             ;# 26
| squirrel                      ;# 27  - output: {cmd {...} line 24 type source}
|                               ;# 28
| proc fuchs {} {               ;# 29    /fuchs remembers 29
|     proc dog {} {             ;# 30  1 /dog   remembers 30
|         puts [info frame 0]   ;# 31* 2*
|     }                         ;# 32  3
| }                             ;# 33
| fuchs                         ;# 34
| dog                           ;# 35  - output: {cmd {...} line 31 type source}
|                               ;# 36
| eval {                        ;# 37  1
|     proc wolf {               ;# 38  2 /wolf remembers 38
|         puts [info frame 0]   ;# 39* 3*
|     }                         ;# 40  4
| }                             ;# 41  5
| wolf                          ;# 42  - output: {cmd {...} line 39 type source}
|                               ;# 43
| set scripted {                ;# 44  1
|     proc deer {} {            ;# 45  2 /deer remembers 2
|         puts [info frame 0]   ;# 46  3*
|     }                         ;# 47  4
| }                             ;# 48  5
| eval $scripted                ;# 49
| deer                          ;# 50  - output: {cmd {...} line 3 type eval}
|                               ;# 51
| puts [set a b                 ;# 52
|       info frame 0]           ;# 53* - output: {cmd {...} line 53 type source file EX}
|                               ;# 54
| puts [info \
|       frame 0]                ;# 56  - output: {cmd {...} line 55 type source file EX}
|                               ;# 57
| proc salmon {} \
| {                             ;# 59
|     puts [info frame 0]       ;# 60*
| }                             ;# 61
| salmon                        ;# 62  - output: {cmd {...} line 60 type source file EX}
|                               ;# 63
| set method frame              ;# 64
| puts [info $method 0]         ;# 65* - output: {cmd {info $method 0} line 65 type source file EX}
|                               ;# 66
| proc trout {} {               ;# 67
|     puts [info $method 0]     ;# 68*
| }                             ;# 69
| trout                         ;# 70  - output: {cmd {info $method 0} line 68 type source file EX}

Another example showing how to query the whole stack of frames. It assumed
that the file is named EX. The output shown after the example was manually
reformatted to explicitly ordered the keys and the columns vertically aligned,
for readability and better comparability of the lines. The returned level
information was removed, and level numbers for '''info frame''' were added at
the beginning of the lines.

| proc setRes {result} {               ;# 01
|   if {$result == "fail"} {           ;# 02
|      set level [info frame]          ;# 03
|      while {$level} {                ;# 04
|           puts [info frame $level]   ;# 05
|           incr level -1              ;# 06
|       } ;# end of while              ;# 07
|   } ;# end of if                     ;# 08
| } ;# end of proc setRes              ;# 09
| proc runTest {tc} {                  ;# 10
|      # run the testcase              ;# 11
|      uplevel 1  setRes fail          ;# 12
| } ;# end of proc runTest             ;# 13
| runTest TC0001                       ;# 14

'''Output:'''

| 4 {cmd {runTest TC0001}        line 14 type source file EX}
| 3 {cmd {uplevel 1 setRes fail} line 12 type source file EX proc runTest}
| 2 {cmd {setRes fail}           line  1 type eval}
| 1 {cmd {info frame $level}     line  5 type source file EX proc setRes}

To see the connection between the new feature and error stack traces replace
the '''info frame''' command on line 3 of ''setRes'' with "'''return''' -code
error X". This will generate an error trace and with a bit of reformatting the
relationship can be seen easily:

'''Stack trace:'''

|	X

|	    while executing
|	"setRes fail"
|	    ("uplevel" body line 1)
|	    invoked from within
|	"uplevel 1  setRes fail"
|	    (procedure "runTest" line 3)
|	    invoked from within
|	"runTest TC0001"
|	    (file "EX.tcl" line 14)

Reformat the trace, with all output from a single command on one line, and
some noise removed.

|	X

|	"setRes fail" ("uplevel" body line 1)
|	"uplevel 1  setRes fail" (procedure "runTest" line 3)
|	"runTest TC0001" (file "EX.tcl" line 14)

Now revert the order of the lines, and add vertical alignment. Now have in
essence the ouput of the unmodified example, with same difference in the line
numbers. But that is only because the error stack trace always counts lines
relative to the script, and doesn't attempt to determine an absolute location
in a file.

|	"runTest TC0001"         (file "EX.tcl" line 14)
|	"uplevel 1  setRes fail" (procedure "runTest" line 3)
|	"setRes fail"            ("uplevel" body line 1)
|	X


~~ Child Interpreters

The current implementation of '''info level''' only returns levels up to the
top of the stack for the current interpreter. Such an approach puts
limitations on what information can be retrieved, but allows for a certain
level of "''security''" when running code in child interps, especially safe
interps.

Given the security considerations of safe interps, and consistancy with
regards to what information is returned across multiple circumstances, the
stack trace returned will only return information up to the top level of the
current interp, the same limit '''info level''' is bound by.

~ Discussion

A point noted by Lars Hellstrom is that this TIP makes the builtin
'''source''' command special. It is not possible anymore to re-create
'''source''' purely in Tcl, doing so will loose the name of the file. We are
still tracking line numbers, but they are then relative to the start of the
eval'd script, withut a connection to the file.

In a similar way, user-defined control structures lose the ability of the
builtin ''if'', etc. to track line numbers in a literal code block relative to
the enclosing file. The user-defined commands are again reduced to providing
line numbers relative to the start of the code block.

To bring user-defined commands back to the same level as the builtins we need:

 1. An extension of '''info frame''' which delivers the line information for
    all words of the command we are inside of. As each word can start on a
    different line (because of continuation lines and preceding multi-line
    literals).

  > This information is actually already available internally. The current
    implementation needs it for the tracking into literals.

 1. Extensions to the ''uplevel'' and ''eval'' commands which allow a script
    to provide them with location information for the script they are
    evaluating.

For example:

| proc newsource {foo script} {
|   ... preprocess whatever ...
|   set loc [info frame data for word 2]
|   uplevel -location $loc 1 $script
| }


Internally we also need quite a bit more flexible data structures. The type
names for example are defined through a C enum, and can be checked quickly and
efficiently. The file information, i.e. path, is stored and used dependent on
that, only for type '''source'''.

To keep this TIP and its implementation reasonably small the actual detailed
specification and implementation of such extensibility is defered to a future
TIP.

~ Reference Implementation

An implementation patch is available on
SourceForge[http://sourceforge.net/support/tracker.php?aid=1571568].

~ Copyright

This document has been placed in the public domain.

Please note that any correspondence to the author concerning this TIP is
considered in the public domain unless otherwise specifically requested by the
individual(s) authoring said correspondence. This is to allow information
about the TIP to be placed in a public forum for discussion.








|



|






|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|





|


|
|
|
|
|
|
|
|
|
|
|
|
|
|

|

|
|
|
|


|



|

<
>
|
|
|
|
|
|
|
|
|




<
>
|
|
|







|
|
|
<
|
>
|

|


|





|

|


|
|




|





|

|
|

|


|





|
|
|
|
<
>




|





|


|

|





|

>
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353

354
355
356
357
358
359
360
361
362
363
364
365
366
367

368
369
370
371
372
373
374
375
376
377
378
379
380
381

382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429

430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454

 1. source

 1. switch

 1. while

## Public C API

No changes are made to the public C API.

# Examples

Note that this is not a complete set of examples covering all possible cases.
Let us assume that the file is named EX. The "cmd" is always the "info frame
..." command, and "level" is 0 too, always, in this situation. This is left
out of the result dictionaries to keep them small.

	 puts [info frame 0]           ;# 01* - output: {cmd {info frame 0} line 1 file EX type source}
	                               ;# 02
	 proc foo {} {                 ;# 03  /foo remembers 3
	     puts [info frame 0]       ;# 04*
	 }                             ;# 05
	 foo                           ;# 06  - output: {cmd {...} line 4 file EX type source}
	                               ;# 07
	 set script {                  ;# 08  1
	     puts [info frame 0]       ;# 09  2*
	 }                             ;# 10  3
	 eval $script                  ;# 11  - output: {cmd {...} line 2 type eval}
	                               ;# 12
	 eval {                        ;# 13  1
	     puts [info frame 0]       ;# 14* 2*
	 }                             ;# 15  3  - output: {cmd {...} line 14 type source}
	                               ;# 16
	 proc fox {} {                 ;# 17  /fox remembers 17
	     eval $::script            ;# 18
	 }                             ;# 19
	 fox                           ;# 20  - output: {cmd {...} line 2 type eval}
	                               ;# 21
	 proc squirrel {} {            ;# 22  /squirrel remembers 22
	     eval {                    ;# 23  1
	         puts [info frame 0]   ;# 24* 2*
	     }                         ;# 25  3
	 }                             ;# 26
	 squirrel                      ;# 27  - output: {cmd {...} line 24 type source}
	                               ;# 28
	 proc fuchs {} {               ;# 29    /fuchs remembers 29
	     proc dog {} {             ;# 30  1 /dog   remembers 30
	         puts [info frame 0]   ;# 31* 2*
	     }                         ;# 32  3
	 }                             ;# 33
	 fuchs                         ;# 34
	 dog                           ;# 35  - output: {cmd {...} line 31 type source}
	                               ;# 36
	 eval {                        ;# 37  1
	     proc wolf {               ;# 38  2 /wolf remembers 38
	         puts [info frame 0]   ;# 39* 3*
	     }                         ;# 40  4
	 }                             ;# 41  5
	 wolf                          ;# 42  - output: {cmd {...} line 39 type source}
	                               ;# 43
	 set scripted {                ;# 44  1
	     proc deer {} {            ;# 45  2 /deer remembers 2
	         puts [info frame 0]   ;# 46  3*
	     }                         ;# 47  4
	 }                             ;# 48  5
	 eval $scripted                ;# 49
	 deer                          ;# 50  - output: {cmd {...} line 3 type eval}
	                               ;# 51
	 puts [set a b                 ;# 52
	       info frame 0]           ;# 53* - output: {cmd {...} line 53 type source file EX}
	                               ;# 54
	 puts [info \
	       frame 0]                ;# 56  - output: {cmd {...} line 55 type source file EX}
	                               ;# 57
	 proc salmon {} \
	 {                             ;# 59
	     puts [info frame 0]       ;# 60*
	 }                             ;# 61
	 salmon                        ;# 62  - output: {cmd {...} line 60 type source file EX}
	                               ;# 63
	 set method frame              ;# 64
	 puts [info $method 0]         ;# 65* - output: {cmd {info $method 0} line 65 type source file EX}
	                               ;# 66
	 proc trout {} {               ;# 67
	     puts [info $method 0]     ;# 68*
	 }                             ;# 69
	 trout                         ;# 70  - output: {cmd {info $method 0} line 68 type source file EX}

Another example showing how to query the whole stack of frames. It assumed
that the file is named EX. The output shown after the example was manually
reformatted to explicitly ordered the keys and the columns vertically aligned,
for readability and better comparability of the lines. The returned level
information was removed, and level numbers for **info frame** were added at
the beginning of the lines.

	 proc setRes {result} {               ;# 01
	   if {$result == "fail"} {           ;# 02
	      set level [info frame]          ;# 03
	      while {$level} {                ;# 04
	           puts [info frame $level]   ;# 05
	           incr level -1              ;# 06
	       } ;# end of while              ;# 07
	   } ;# end of if                     ;# 08
	 } ;# end of proc setRes              ;# 09
	 proc runTest {tc} {                  ;# 10
	      # run the testcase              ;# 11
	      uplevel 1  setRes fail          ;# 12
	 } ;# end of proc runTest             ;# 13
	 runTest TC0001                       ;# 14

**Output:**

	 4 {cmd {runTest TC0001}        line 14 type source file EX}
	 3 {cmd {uplevel 1 setRes fail} line 12 type source file EX proc runTest}
	 2 {cmd {setRes fail}           line  1 type eval}
	 1 {cmd {info frame $level}     line  5 type source file EX proc setRes}

To see the connection between the new feature and error stack traces replace
the **info frame** command on line 3 of _setRes_ with "**return** -code
error X". This will generate an error trace and with a bit of reformatting the
relationship can be seen easily:

**Stack trace:**


		X
		    while executing
		"setRes fail"
		    ("uplevel" body line 1)
		    invoked from within
		"uplevel 1  setRes fail"
		    (procedure "runTest" line 3)
		    invoked from within
		"runTest TC0001"
		    (file "EX.tcl" line 14)

Reformat the trace, with all output from a single command on one line, and
some noise removed.


		X
		"setRes fail" ("uplevel" body line 1)
		"uplevel 1  setRes fail" (procedure "runTest" line 3)
		"runTest TC0001" (file "EX.tcl" line 14)

Now revert the order of the lines, and add vertical alignment. Now have in
essence the ouput of the unmodified example, with same difference in the line
numbers. But that is only because the error stack trace always counts lines
relative to the script, and doesn't attempt to determine an absolute location
in a file.

		"runTest TC0001"         (file "EX.tcl" line 14)
		"uplevel 1  setRes fail" (procedure "runTest" line 3)
		"setRes fail"            ("uplevel" body line 1)

		X

## Child Interpreters

The current implementation of **info level** only returns levels up to the
top of the stack for the current interpreter. Such an approach puts
limitations on what information can be retrieved, but allows for a certain
level of "_security_" when running code in child interps, especially safe
interps.

Given the security considerations of safe interps, and consistancy with
regards to what information is returned across multiple circumstances, the
stack trace returned will only return information up to the top level of the
current interp, the same limit **info level** is bound by.

# Discussion

A point noted by Lars Hellstrom is that this TIP makes the builtin
**source** command special. It is not possible anymore to re-create
**source** purely in Tcl, doing so will loose the name of the file. We are
still tracking line numbers, but they are then relative to the start of the
eval'd script, withut a connection to the file.

In a similar way, user-defined control structures lose the ability of the
builtin _if_, etc. to track line numbers in a literal code block relative to
the enclosing file. The user-defined commands are again reduced to providing
line numbers relative to the start of the code block.

To bring user-defined commands back to the same level as the builtins we need:

 1. An extension of **info frame** which delivers the line information for
    all words of the command we are inside of. As each word can start on a
    different line \(because of continuation lines and preceding multi-line
    literals\).

	  > This information is actually already available internally. The current
    implementation needs it for the tracking into literals.

 1. Extensions to the _uplevel_ and _eval_ commands which allow a script
    to provide them with location information for the script they are
    evaluating.

For example:

	 proc newsource {foo script} {
	   ... preprocess whatever ...
	   set loc [info frame data for word 2]
	   uplevel -location $loc 1 $script

	 }

Internally we also need quite a bit more flexible data structures. The type
names for example are defined through a C enum, and can be checked quickly and
efficiently. The file information, i.e. path, is stored and used dependent on
that, only for type **source**.

To keep this TIP and its implementation reasonably small the actual detailed
specification and implementation of such extensibility is defered to a future
TIP.

# Reference Implementation

An implementation patch is available on
SourceForge<http://sourceforge.net/support/tracker.php?aid=1571568> .

# Copyright

This document has been placed in the public domain.

Please note that any correspondence to the author concerning this TIP is
considered in the public domain unless otherwise specifically requested by the
individual\(s\) authoring said correspondence. This is to allow information
about the TIP to be placed in a public forum for discussion.

Name change from tip/281.tip to tip/281.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

TIP:            281
Title:          Improvements in System Error Handling
Version:        $Revision: 1.7 $
Author:         David Gravereaux <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        08-Oct-2006
Post-History:   
Keywords:       POSIX,channel driver,errorCode
Tcl-Version:    8.7


~ Abstract

This TIP describes the need for better error codes and message handling of
system errors to be returned to scripts.

~Rationale

The current method for handling of system errors is done via the
''Tcl_PosixError()'' API call. Its job is to grab the value of ''errno'' and
format it for display to a script within the '''errorCode''' special variable.

Unfortunately, not all such system errors are left in ''errno'' and on
Windows, not all information can be translated effectively to a POSIX error
code without loss of valuable information to the user.

On UNIX, ''gethostbyname()'' for example, leaves its errors in ''h_errno''
[http://www.opengroup.org/onlinepubs/009695399/basedefs/netdb.h.html]. If we
look at our use of ''gethostbyname()'' in unix/tclUnixChan.c for the
''CreateSocketAddress()'' function, you'll see we are setting ''errno'' to a
wrong code rather than retrieving the proper error information defined in
''netdb.h''.

An example of the current mistranslation would be:

|% socket foo.example.com 1234
|couldn't open socket: host is unreachable
|% set errorCode
|POSIX EHOSTUNREACH {host is unreachable}

And on Windows:

|% socket foo.example.com 1234
|couldn't open socket: invalid argument
|% set errorCode
|POSIX EINVAL {invalid argument}

Notice that the two are different as well as wrong. EHOSTUNREACH is a routing
error at the IP level and is returned by connect(), send().. etc., not by
gethostbyname(). For windows, the error translation function
TclWinConvertWSAError() sets ''errno'' to EINVAL for a WSAHOST_NOT_FOUND even
though the code in CreateSocketAddress() appears to set errno to EHOSTUNREACH.
What I would like to see is the following (on all platforms):

|% socket foo.example.com 1234
|couldn't open socket: No such host is known
|% set errorCode
|NETDB HOST_NOT_FOUND {No such host is known}

If we could specify a place from where the error could be retrieved along with
the formatting functions for that type, Tcl's error information to the user
would be improved.

A facility to extend/add formatters would also help extension authors.

For example with the windows port of Expect, there are numerous specific
errors that Expect could return regarding how the Console API debugger was
unable to function, but the error path is only limited to POSIX pipe errors
rather than anything specific.

I tried to make a facility to manage these specific errors in a controlled way
using a message catalog
[http://www.pobox.com/~davygrvy/expect-src/win/expWinErr.mc] to compile into
the expect dll a "windows"-ish style of error management along with a specific
"EXPECT" formatter, see ExpWinError() [[last function in file]]
[http://www.pobox.com/~davygrvy/expect-src/win/expWinUtils.cpp]. I used the
"customer" bit in the '''errorCode''' as a key to forward to the "WINDOWS"
formatter and thought it was quite smart of me.

But alas... the POSIX restriction was not to be bypassed in a manageable
manner.

~Reference Implementation

A reference implementation is not done at this time. An experimental WINDOWS
'''errorCode''' formatter can be seen @
[http://iocpsock.cvs.sourceforge.net/iocpsock/iocpsock/tclWinError.c?revision=HEAD&view=markup]

~Copyright

This document is in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|


|
|

|



|
|
|
|

|



|
|
|
|



|
|
|
|


|
|
|
|
|

|
|
|
|














|

|
|
|





|


|
|

|


>

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

# TIP 281: Improvements in System Error Handling

	Author:         David Gravereaux <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        08-Oct-2006
	Post-History:   
	Keywords:       POSIX,channel driver,errorCode
	Tcl-Version:    8.7
-----

# Abstract

This TIP describes the need for better error codes and message handling of
system errors to be returned to scripts.

# Rationale

The current method for handling of system errors is done via the
_Tcl\_PosixError\(\)_ API call. Its job is to grab the value of _errno_ and
format it for display to a script within the **errorCode** special variable.

Unfortunately, not all such system errors are left in _errno_ and on
Windows, not all information can be translated effectively to a POSIX error
code without loss of valuable information to the user.

On UNIX, _gethostbyname\(\)_ for example, leaves its errors in _h\_errno_
<http://www.opengroup.org/onlinepubs/009695399/basedefs/netdb.h.html> . If we
look at our use of _gethostbyname\(\)_ in unix/tclUnixChan.c for the
_CreateSocketAddress\(\)_ function, you'll see we are setting _errno_ to a
wrong code rather than retrieving the proper error information defined in
_netdb.h_.

An example of the current mistranslation would be:

	% socket foo.example.com 1234
	couldn't open socket: host is unreachable
	% set errorCode
	POSIX EHOSTUNREACH {host is unreachable}

And on Windows:

	% socket foo.example.com 1234
	couldn't open socket: invalid argument
	% set errorCode
	POSIX EINVAL {invalid argument}

Notice that the two are different as well as wrong. EHOSTUNREACH is a routing
error at the IP level and is returned by connect\(\), send\(\).. etc., not by
gethostbyname\(\). For windows, the error translation function
TclWinConvertWSAError\(\) sets _errno_ to EINVAL for a WSAHOST\_NOT\_FOUND even
though the code in CreateSocketAddress\(\) appears to set errno to EHOSTUNREACH.
What I would like to see is the following \(on all platforms\):

	% socket foo.example.com 1234
	couldn't open socket: No such host is known
	% set errorCode
	NETDB HOST_NOT_FOUND {No such host is known}

If we could specify a place from where the error could be retrieved along with
the formatting functions for that type, Tcl's error information to the user
would be improved.

A facility to extend/add formatters would also help extension authors.

For example with the windows port of Expect, there are numerous specific
errors that Expect could return regarding how the Console API debugger was
unable to function, but the error path is only limited to POSIX pipe errors
rather than anything specific.

I tried to make a facility to manage these specific errors in a controlled way
using a message catalog
<http://www.pobox.com/~davygrvy/expect-src/win/expWinErr.mc>  to compile into
the expect dll a "windows"-ish style of error management along with a specific
"EXPECT" formatter, see ExpWinError\(\) [last function in file]
<http://www.pobox.com/~davygrvy/expect-src/win/expWinUtils.cpp> . I used the
"customer" bit in the **errorCode** as a key to forward to the "WINDOWS"
formatter and thought it was quite smart of me.

But alas... the POSIX restriction was not to be bypassed in a manageable
manner.

# Reference Implementation

A reference implementation is not done at this time. An experimental WINDOWS
**errorCode** formatter can be seen @
<http://iocpsock.cvs.sourceforge.net/iocpsock/iocpsock/tclWinError.c?revision=HEAD&view=markup> 

# Copyright

This document is in the public domain.

Name change from tip/282.tip to tip/282.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

TIP:            282
Title:          Enhanced Expression Syntax
Version:        $Revision: 1.4 $
Author:         Will Duquette <[email protected]>
Author:         Don Porter <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        13-Oct-2006
Post-History:   
Keywords:       expr,operator,assignment
Tcl-Version:    8.7


~ Abstract

This TIP extends the syntax of the '''expr''' command to allow a sequence of
mathematical computations to be expressed clearly and concisely.

~ Rationale

The ugliness of mathematical code written in Tcl is a perennial source of
complaint. Consider the following computation:

|    set x [expr {5*$y + 6*$z}]
|    set w [expr {$x**2 + $y**2}]
|    set v [expr {$w**2 + $y**2}]

The [['''expr {...}''']] constructs make the code considerably harder to read.
But suppose '''expr''' syntax included an assignment operator:

|    expr {x = 5*$y  + 6*$z}
|    expr {w = $x**2 + $y**2}
|    expr {v = $w**2 + $y**2}

Next, suppose that an '''expr''' expression could include subexpressions,
delimited by a ";" character:

|    expr {
|        x = 5*$y  + 6*$z;
|        w = $x**2 + $y**2;
|        v = $w**2 + $y**2
|    }


The sequence of computations is now much clearer.

~ Specification

~~ Assignment Operator

The '''expr''' syntax should be extended with an assignment operator which has
C-like semantics, i.e., the result of an assignment is the assigned value.
This operator shall be written as "'''='''". The term on the left side of the
operator shall be a variable name, and the term on the right side of the
operator shall be any expression. The result of the overall assignment
expression shall be the result of the subexpression on the right hand side of
the operator.

~~ Expression Separator Operator

An '''expr''' expression can be separated into subexpressions by the semicolon
("''';'''") character, which will have the same semantics as the "," operator
in C. Thus, the return value of a call to '''expr''' is the value of the final
subexpression, and the both sides of the expression shall be expressions.

~ Reference Implementation

See [http://sourceforge.net/tracker/?func=detail&aid=1969722&group_id=10894&atid=310894]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|




|
|
|

|
|

|
|
|

|


|
|
|
|
<
>



|

|

|

|





|

|
|
|


|

|

|


>

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

# TIP 282: Enhanced Expression Syntax

	Author:         Will Duquette <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        13-Oct-2006
	Post-History:   
	Keywords:       expr,operator,assignment
	Tcl-Version:    8.7
-----

# Abstract

This TIP extends the syntax of the **expr** command to allow a sequence of
mathematical computations to be expressed clearly and concisely.

# Rationale

The ugliness of mathematical code written in Tcl is a perennial source of
complaint. Consider the following computation:

	    set x [expr {5*$y + 6*$z}]
	    set w [expr {$x**2 + $y**2}]
	    set v [expr {$w**2 + $y**2}]

The [**expr {...}**] constructs make the code considerably harder to read.
But suppose **expr** syntax included an assignment operator:

	    expr {x = 5*$y  + 6*$z}
	    expr {w = $x**2 + $y**2}
	    expr {v = $w**2 + $y**2}

Next, suppose that an **expr** expression could include subexpressions,
delimited by a ";" character:

	    expr {
	        x = 5*$y  + 6*$z;
	        w = $x**2 + $y**2;
	        v = $w**2 + $y**2

	    }

The sequence of computations is now much clearer.

# Specification

## Assignment Operator

The **expr** syntax should be extended with an assignment operator which has
C-like semantics, i.e., the result of an assignment is the assigned value.
This operator shall be written as "**=**". The term on the left side of the
operator shall be a variable name, and the term on the right side of the
operator shall be any expression. The result of the overall assignment
expression shall be the result of the subexpression on the right hand side of
the operator.

## Expression Separator Operator

An **expr** expression can be separated into subexpressions by the semicolon
\("**;**"\) character, which will have the same semantics as the "," operator
in C. Thus, the return value of a call to **expr** is the value of the final
subexpression, and the both sides of the expression shall be expressions.

# Reference Implementation

See <http://sourceforge.net/tracker/?func=detail&aid=1969722&group_id=10894&atid=310894> 

# Copyright

This document has been placed in the public domain.

Name change from tip/283.tip to tip/283.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
136
137
138
139
140
141
142

143
144
145

146
147
148
149
150
151

152
153
154
155

156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

TIP:            283
Title:          Modify Ensemble Command Resolution Behaviour
Version:        $Revision: 1.22 $
Author:         Miguel Sofer <[email protected]>
Author:         Neil Madden <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        01-Oct-2006
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes that ensembles resolve all commands in their namespace.

~ Rationale

Ensembles as proposed in [112] cannot interoperate with the '''namespace
path''' and '''namespace unknown''' functionality: as they resolve all
commands in the caller's scope, it is necessary to define them using fully
qualified names to insure that they are found in the ensemble's namespace. But
fully qualified names bypass the namespace's '''path''' and '''unknown'''
redirectors.

As an example (and risking "uh-oo" reactions in the present context) I would
like to remark that this feature enables lightweight OO systems based on ensembles
to provide inheritance of methods via '''namespace path''' and '''namespace
unknown'''.

~ Proposed Change

This TIP proposes to fix this by changing the man page description of the
ensemble unknown handler from:

 > It is up to the unknown handler to supply all namespace qualifiers if the
   implementing subcommand is not in the namespace of the caller of the
   ensemble command.

to:

 > The implementing subcommand is looked up in the ensemble's namespace using
   normal command location rules.

The description of the ''-map'' option should change from:

 > When non-empty, this option supplies a dictionary that provides a mapping
   from subcommand names to a list of prefix words to substitute in place of
   the ensemble command and subcommand words (in a manner similar to an alias
   created with '''interp alias'''; the words are not reparsed after
   substitution).

to:

 > When non-empty, this option supplies a dictionary that provides a mapping
   from subcommand names to a list of prefix words to substitute in place of
   the ensemble command and subcommand words (in a manner similar to an alias
   created with '''interp alias'''; the words are not reparsed after
   substitution). The resulting command is invoked with the original arguments
   in the namespace of the ensemble, though no additional stack frames are
   pushed in the process.

~~ Compatability

All scripts that followed previous best-practice and placed fully qualified
command names in the command map or returned them from the unknown handler
will be unaffected by this change. Only ensembles whose behaviour was
undefined previously will be influenced, and then strictly in a positive
direction.

~ Reference Implementation and Documentation

[[RFE 1577282]]
[http://sourceforge.net/tracker/index.php?func=detail&aid=1577282&group_id=10894&atid=360894]
(which depends on committed [[Patch 1577278]]) provides an implementation,
with tests and docs.

~ Illustration

   * Consider the following script (without FQ names) stored in /tmp/test:

|   namespace eval a {
|       proc check args {return YES}
|   }

|   namespace eval b {
|       namespace path ::a
|       namespace ensemble create \
|           -command ::b \
|           -map {go check}
|   }

|   namespace eval c {
|       namespace path ::a
|       namespace ensemble create \
|           -command ::c \
|           -map {go check} \
|           -unknown u
|       proc u args {return check}
|   }

|   namespace eval d {
|       namespace unknown u
|       namespace ensemble create \
|           -command ::d \
|           -map {go check}
|       proc u args {::a::check}
|   }

|   array set res {}
|   foreach cmd {b c d} {
|       foreach scmd {foo go} {
|           catch {$cmd $scmd} msg
|           set res($cmd|$scmd) $msg
|       }
|   }


|   parray res

Currently the output is

|   mig@ice:~$ tclsh /tmp/test
|   res(b|foo) = unknown or ambiguous subcommand "foo": must be go
|   res(b|go)  = invalid command name "::b::check"
|   res(c|foo) = invalid command name "u"
|   res(c|go)  = invalid command name "::c::check"
|   res(d|foo) = unknown or ambiguous subcommand "foo": must be go
|   res(d|go)  = invalid command name "::d::check"

After this TIP, it should be

|   mig@ice:~$ tclsh /tmp/test
|   res(b|foo) = unknown or ambiguous subcommand "foo": must be go
|   res(b|go)  = YES
|   res(c|foo) = YES
|   res(c|go)  = YES
|   res(d|foo) = unknown or ambiguous subcommand "foo": must be go
|   res(d|go)  = YES

   * One commenter asked what the difference would be in the following code:

|   namespace eval ens {
|       proc foo {} {
|           puts "Caller namespace is: [uplevel 1 namespace current]"
|           puts "I am [namespace origin foo]"
|           puts "I am called as: [lindex [info level 0] 0]"
|       }

|       namespace export ens
|       namespace ensemble create -command ens -map {sub foo}
|   }

|   namespace eval caller {
|       proc foo {} {
|           puts "Caller namespace is: [uplevel 1 namespace current]"
|           puts "I am [namespace origin foo]"
|           puts "I am called as: [lindex [info level 0] 0]"
|       }

|       namespace import ::ens::ens
|       ens sub
|   }


Today (*) and after the patch this returns:

|   Caller namespace is: ::caller
|   I am ::ens::foo
|   I am called as: ens

(*) Today==2006-24-10, after making '''info level''' aware of ensemble
rewrites; prior to that date, only the last line would have changed from
''::ens::foo'' to ''foo''.

~ Remarks

   * See also [[Bug 1436096]]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|



|

|
|


|


|

|
|

|













|



|
|
|





|
|
|



|







|

|
|
|


|

|

|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
|
<
<
>
>
|



|
|
|
|
|
|
|



|
|
|
|
|
|
|



|
|
|
|
|
<
>
|
|
<
>
|
|
|
|
|
<
>
|
|
<
|
>
|

|
|
|

|

|

|

|

|


>

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
136
137
138
139
140

141
142
143

144
145
146
147
148
149

150
151
152

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

# TIP 283: Modify Ensemble Command Resolution Behaviour

	Author:         Miguel Sofer <[email protected]>
	Author:         Neil Madden <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        01-Oct-2006
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes that ensembles resolve all commands in their namespace.

# Rationale

Ensembles as proposed in [[112]](112.md) cannot interoperate with the **namespace
path** and **namespace unknown** functionality: as they resolve all
commands in the caller's scope, it is necessary to define them using fully
qualified names to insure that they are found in the ensemble's namespace. But
fully qualified names bypass the namespace's **path** and **unknown**
redirectors.

As an example \(and risking "uh-oo" reactions in the present context\) I would
like to remark that this feature enables lightweight OO systems based on ensembles
to provide inheritance of methods via **namespace path** and **namespace
unknown**.

# Proposed Change

This TIP proposes to fix this by changing the man page description of the
ensemble unknown handler from:

 > It is up to the unknown handler to supply all namespace qualifiers if the
   implementing subcommand is not in the namespace of the caller of the
   ensemble command.

to:

 > The implementing subcommand is looked up in the ensemble's namespace using
   normal command location rules.

The description of the _-map_ option should change from:

 > When non-empty, this option supplies a dictionary that provides a mapping
   from subcommand names to a list of prefix words to substitute in place of
   the ensemble command and subcommand words \(in a manner similar to an alias
   created with **interp alias**; the words are not reparsed after
   substitution\).

to:

 > When non-empty, this option supplies a dictionary that provides a mapping
   from subcommand names to a list of prefix words to substitute in place of
   the ensemble command and subcommand words \(in a manner similar to an alias
   created with **interp alias**; the words are not reparsed after
   substitution\). The resulting command is invoked with the original arguments
   in the namespace of the ensemble, though no additional stack frames are
   pushed in the process.

## Compatability

All scripts that followed previous best-practice and placed fully qualified
command names in the command map or returned them from the unknown handler
will be unaffected by this change. Only ensembles whose behaviour was
undefined previously will be influenced, and then strictly in a positive
direction.

# Reference Implementation and Documentation

[RFE 1577282]
<http://sourceforge.net/tracker/index.php?func=detail&aid=1577282&group_id=10894&atid=360894> 
\(which depends on committed [Patch 1577278]\) provides an implementation,
with tests and docs.

# Illustration

   * Consider the following script \(without FQ names\) stored in /tmp/test:

		   namespace eval a {
		       proc check args {return YES}

		   }
		   namespace eval b {
		       namespace path ::a
		       namespace ensemble create \
		           -command ::b \
		           -map {go check}

		   }
		   namespace eval c {
		       namespace path ::a
		       namespace ensemble create \
		           -command ::c \
		           -map {go check} \
		           -unknown u
		       proc u args {return check}

		   }
		   namespace eval d {
		       namespace unknown u
		       namespace ensemble create \
		           -command ::d \
		           -map {go check}
		       proc u args {::a::check}

		   }
		   array set res {}
		   foreach cmd {b c d} {
		       foreach scmd {foo go} {
		           catch {$cmd $scmd} msg
		           set res($cmd|$scmd) $msg


		       }
		   }
		   parray res

Currently the output is

	   mig@ice:~$ tclsh /tmp/test
	   res(b|foo) = unknown or ambiguous subcommand "foo": must be go
	   res(b|go)  = invalid command name "::b::check"
	   res(c|foo) = invalid command name "u"
	   res(c|go)  = invalid command name "::c::check"
	   res(d|foo) = unknown or ambiguous subcommand "foo": must be go
	   res(d|go)  = invalid command name "::d::check"

After this TIP, it should be

	   mig@ice:~$ tclsh /tmp/test
	   res(b|foo) = unknown or ambiguous subcommand "foo": must be go
	   res(b|go)  = YES
	   res(c|foo) = YES
	   res(c|go)  = YES
	   res(d|foo) = unknown or ambiguous subcommand "foo": must be go
	   res(d|go)  = YES

   * One commenter asked what the difference would be in the following code:

		   namespace eval ens {
		       proc foo {} {
		           puts "Caller namespace is: [uplevel 1 namespace current]"
		           puts "I am [namespace origin foo]"
		           puts "I am called as: [lindex [info level 0] 0]"

		       }
		       namespace export ens
		       namespace ensemble create -command ens -map {sub foo}

		   }
		   namespace eval caller {
		       proc foo {} {
		           puts "Caller namespace is: [uplevel 1 namespace current]"
		           puts "I am [namespace origin foo]"
		           puts "I am called as: [lindex [info level 0] 0]"

		       }
		       namespace import ::ens::ens
		       ens sub

		   }

Today \(\*\) and after the patch this returns:

	   Caller namespace is: ::caller
	   I am ::ens::foo
	   I am called as: ens

\(\*\) Today==2006-24-10, after making **info level** aware of ensemble
rewrites; prior to that date, only the last line would have changed from
_::ens::foo_ to _foo_.

# Remarks

   * See also [Bug 1436096]

# Copyright

This document has been placed in the public domain.

Name change from tip/284.tip to tip/284.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
136
137
138
139

TIP:            284
Title:          New 'invoke' and 'namespace invoke' Commands
Version:        $Revision: 1.23 $
Author:         Miguel Sofer <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        01-Oct-2006
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP exposes a Tcl script-level interface to the direct command invokation
engine already present in the Tcl library for years.

~ Proposed New Commands

This TIP proposes a new subcommand to '''namespace''', '''invoke''', with the
following syntax:

 > '''namespace invoke''' ''namespace'' ''cmd'' ?''arg'' ...?

This invokes the command called '''cmd''' in the caller's scope, as resolved
from namespace ''namespace'', with the supplied arguments. If ''namespace''
does not exist, the command returns an error.

This TIP also proposes a new command:

 > '''invoke''' ''level'' ''cmd'' ?''arg'' ...?

This invokes the command ''cmd'' in level ''level'' with the supplied
''arg''uments. The syntax of ''level'' is the same as that required by
'''uplevel'''.

~ Rationale

There is currently no script-level equivalent to ''Tcl_EvalObjv()'', though
the functionality is provided by one of:

|   eval [list cmd ?arg ...?]
|   {*}[list cmd ?arg ...?]

Note that the core tries to optimise the first case, but has to be careful to
only avoid reparsing when it is guaranteed safe to do so. The notation is
rather clumsy too.

The proposed new commands try to improve this situation, with the added
functionality of determining the namespace in which the command name is to be
resolved (functionality which was very difficult to use previously using the
script-level API). In this manner it is possible for the invocation to make
good use of '''namespace path''' and '''namespace unknown''' features.

The new command '''invoke''' could be implemented as:

|   proc invoke {level args} {
|       if {[llength $args] == 0} {
|           return -code error SomeMessage
|       }

|       if {[string is integer $level] && ($level >= 0)} {
|           incr level
|       }

|       uplevel $level $args
|   }]

~ Reference Implementation and Documentation

[[RFE 1577324]] (which depends on [[Patch 1577278]]) provides an
implementation of '''namespace invoke'''.
[https://sourceforge.net/support/tracker.php?aid=1577324]
[https://sourceforge.net/support/tracker.php?aid=1577278]

~ Differences to Other Commands

   1. Both these commands perform command invocation, as opposed to the script
      evaluation done by '''eval''', '''uplevel''', '''namespace eval''' and
      '''namespace inscope'''

   1. '''namespace inscope''' does a magic expansion of the first argument,
      '''namespace invoke''' takes the first argument as a command name. In
      other words, '''namespace inscope''' can be used with a command prefix.
      ''Feedback on the semantics suggest that this is a worthy feature, very
      useful for packing up command prefixes. This tip may yet be revised or
      withdrawn to take that into consideration.''

   1. Both '''namespace eval''' and '''namespace inscope''' add a call
      frame,'''namespace invoke''' does not - it invokes in the caller's
      frame.

~ Sample Usage

In tcllib's '''::math::calculus::romberg''' we see (edited for brevity):

|    # Replace f with a context-independent version
|
|    set fqname [uplevel 1 [list namespace which [lindex $f 0]]]
|    set f [lreplace $f 0 0 $fqname]
|    ...
|    set cmd $f
|    lappend cmd [expr {0.5 * ($a + $b)}]
|    set v [eval $cmd]

where the command name in the prefix ''f'' is replaced with its fully
qualified name. A further variable is lappended, and the result is sent to
'''eval'''.

With '''namespace invoke''' and '''invoke''' this would be coded as:

|    set ns [invoke 1 namespace current]
|    set f [list namespace invoke $ns {*}$f]
|    ...
|    set v [{*}$f [expr {0.5 * ($a + $b)}]]

If both new commands took the ''cmd'' argument as a prefix to be expanded (as
suggested by some early commenters), it would be even nicer for this usage:

|    set ns [invoke 1 [list namespace current]]
|    set f [list namespace invoke $ns $f]
|    ...
|    set v [invoke 0 $f [expr {0.5 * ($a + $b)}]]

The same thing (with slightly different semantics and a performance cost due
to script evaluation instead of command invocation) could be obtained today by
doing:

|    set f [uplevel 1 [list namespace code [list uplevel 1 $f]]]
|    ...
|    set v [eval [lappend f [expr {0.5 * ($a + $b)}]]]

In order to fully reproduce the semantics and performance it would have to be:

|    set f [uplevel 1 [list namespace code [list uplevel 1 $f]]]
|    ...
|    lset f end end [linsert [lindex $f end end] end [expr {0.5 * ($a + $b)}]]  
|    set v [eval $f]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|




|

|


|

|
|




|

|
|
|

|

|


|
|







|
|
|

|

|
|
|
<
>
|
|
<
>
|
|

|

|
|
|
|

|


|
|

|
|
|
|

|

|
|


|

|

|
|
|
|
|
|
|
|

|

|

|

|
|
|
|

|
|

|
|
|
|

|
|


|
|
|



|
|
|
|

|


>

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
136
137
138
139

# TIP 284: New 'invoke' and 'namespace invoke' Commands

	Author:         Miguel Sofer <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        01-Oct-2006
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP exposes a Tcl script-level interface to the direct command invokation
engine already present in the Tcl library for years.

# Proposed New Commands

This TIP proposes a new subcommand to **namespace**, **invoke**, with the
following syntax:

 > **namespace invoke** _namespace_ _cmd_ ?_arg_ ...?

This invokes the command called **cmd** in the caller's scope, as resolved
from namespace _namespace_, with the supplied arguments. If _namespace_
does not exist, the command returns an error.

This TIP also proposes a new command:

 > **invoke** _level_ _cmd_ ?_arg_ ...?

This invokes the command _cmd_ in level _level_ with the supplied
_arg_uments. The syntax of _level_ is the same as that required by
**uplevel**.

# Rationale

There is currently no script-level equivalent to _Tcl\_EvalObjv\(\)_, though
the functionality is provided by one of:

	   eval [list cmd ?arg ...?]
	   {*}[list cmd ?arg ...?]

Note that the core tries to optimise the first case, but has to be careful to
only avoid reparsing when it is guaranteed safe to do so. The notation is
rather clumsy too.

The proposed new commands try to improve this situation, with the added
functionality of determining the namespace in which the command name is to be
resolved \(functionality which was very difficult to use previously using the
script-level API\). In this manner it is possible for the invocation to make
good use of **namespace path** and **namespace unknown** features.

The new command **invoke** could be implemented as:

	   proc invoke {level args} {
	       if {[llength $args] == 0} {
	           return -code error SomeMessage

	       }
	       if {[string is integer $level] && ($level >= 0)} {
	           incr level

	       }
	       uplevel $level $args
	   }]

# Reference Implementation and Documentation

[RFE 1577324] \(which depends on [Patch 1577278]\) provides an
implementation of **namespace invoke**.
<https://sourceforge.net/support/tracker.php?aid=1577324> 
<https://sourceforge.net/support/tracker.php?aid=1577278> 

# Differences to Other Commands

   1. Both these commands perform command invocation, as opposed to the script
      evaluation done by **eval**, **uplevel**, **namespace eval** and
      **namespace inscope**

   1. **namespace inscope** does a magic expansion of the first argument,
      **namespace invoke** takes the first argument as a command name. In
      other words, **namespace inscope** can be used with a command prefix.
      _Feedback on the semantics suggest that this is a worthy feature, very
      useful for packing up command prefixes. This tip may yet be revised or
      withdrawn to take that into consideration._

   1. Both **namespace eval** and **namespace inscope** add a call
      frame,**namespace invoke** does not - it invokes in the caller's
      frame.

# Sample Usage

In tcllib's **::math::calculus::romberg** we see \(edited for brevity\):

	    # Replace f with a context-independent version
	
	    set fqname [uplevel 1 [list namespace which [lindex $f 0]]]
	    set f [lreplace $f 0 0 $fqname]
	    ...
	    set cmd $f
	    lappend cmd [expr {0.5 * ($a + $b)}]
	    set v [eval $cmd]

where the command name in the prefix _f_ is replaced with its fully
qualified name. A further variable is lappended, and the result is sent to
**eval**.

With **namespace invoke** and **invoke** this would be coded as:

	    set ns [invoke 1 namespace current]
	    set f [list namespace invoke $ns {*}$f]
	    ...
	    set v [{*}$f [expr {0.5 * ($a + $b)}]]

If both new commands took the _cmd_ argument as a prefix to be expanded \(as
suggested by some early commenters\), it would be even nicer for this usage:

	    set ns [invoke 1 [list namespace current]]
	    set f [list namespace invoke $ns $f]
	    ...
	    set v [invoke 0 $f [expr {0.5 * ($a + $b)}]]

The same thing \(with slightly different semantics and a performance cost due
to script evaluation instead of command invocation\) could be obtained today by
doing:

	    set f [uplevel 1 [list namespace code [list uplevel 1 $f]]]
	    ...
	    set v [eval [lappend f [expr {0.5 * ($a + $b)}]]]

In order to fully reproduce the semantics and performance it would have to be:

	    set f [uplevel 1 [list namespace code [list uplevel 1 $f]]]
	    ...
	    lset f end end [linsert [lindex $f end end] end [expr {0.5 * ($a + $b)}]]  
	    set v [eval $f]

# Copyright

This document has been placed in the public domain.

Name change from tip/285.tip to tip/285.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252

TIP:            285
Title:          Script Cancellation with [interp cancel] and Tcl_CancelEval
Version:        $Revision: 1.11 $
Author:         Joe Mistachkin <[email protected]>
Author:         Dawson Cowals <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        04-Jun-2006
Post-History:   
Keywords:       eval,cancel,unwind,terminate,runaway,async,thread,safe
Tcl-Version:    8.6


~ Abstract

This TIP introduces the ability to quickly and safely cancel a script within a
specified interpreter from any thread in the process.

~ Key Use-Case Scenario

When using Tcl inside a context such as a web-browser (e.g. as a plugin), it
is often necessary for the execution of a particular script to be terminated
cleanly without waiting for the script to get to a point where it is able to
respond to events. For example, if the user encounters a page that contains a
script that starts a long-running execution but then decides to navigate away
from the page, it's important to stop the script as soon as possible.

But we do not want to stop the script by means of just terminating the thread,
as this can result in various resources being still allocated, as browsers are
long-running applications. Some of the problems (e.g. memory waste) can be
worked around by running the script in a separate process, but there are other
resources that aren't cleaned up that way, such as locked files or shared
memory blocks, and it is always better to give the Tcl interpreter itself an
opportunity to clean up after itself. Furthermore, there are other possible
applications (such as using Tcl to implement COM objects on Windows) where the
separate-process method will not work so well.

Instead, what is needed is a way to programmatically make a script stop its
execution even when that script is otherwise determined to continue. This is
different from a resource limit in that the cancellation is not caused by the
exceeding of a predetermined value, but rather by some external event that is
possibly even not processed initially by Tcl at all.

~ Technical Rationale

Currently, once the evaluation of a script has been initiated it will do one
of the following:

 * run to completion,

 * run until it encounters an uncaught error,

 * run until it exceeds a pre-determined limit as specified in [143], or

 * run indefinitely.

In each of the cases above, neither the host application nor an interactive
user have any recourse to terminate the script prior to it running its course.

There are many situations for which it is absolutely necessary to be able to
cancel a running script without its cooperation and without setting an
arbitrary limit on the amount of time it can run ([143]). This is especially
true in a multi-threaded application embedding environment, or where a user
interface is present.

 1. In the case where the completion time for a script is unknown,
    non-existent, or non-deterministic a user may want or need to terminate
    the script prematurely.

 2. When evaluating an untrusted - or marginally trusted - script in either a
    safe or standard interpreter, there is a risk that the script might never
    terminate. In such a situation it is not reasonable to forcibly terminate
    the thread or the entire process.

 > 1. Forcibly terminating a thread prevents Tcl and Tk from cleaning up their
      thread-specific memory and resources.

 > 2. The host application may suffer similar memory and resource leaks as
      well as other serious side-effects that may corrupt data, prevent other
      threads from properly synchronizing, or leave the process in an unknown
      and unrecoverable state.

 > 3. For an interactive host application valuable work may be lost without
      providing an opportunity to save pending modifications. Even in the
      absence of modifications the host application might have been holding
      locks that left unreleased would prevent other processes and users from
      using important resources.

The basic building blocks needed for any scripting language to seamlessly
integrate with an enterprise-ready host application are:

 * Engine Initialization

 * Evaluation

 * Extensibility

 * Cancellation

 * Engine Finalization

Tcl now provides full support for all of the above except script cancellation.
[143] allows for scripts to be prematurely terminated after reaching resource
limits that were pre-arranged by the host application. However, this only
handles terminating scripts based on a narrow set of deterministic criteria.
Full support would require the ability to immediately and unconditionally
terminate the evaluation of a script without adversely affecting the execution
environment of the host application. In addition the following issues must be
addressed:

 * Scripts being evaluated in nested slave interpreters.

 * Interaction with third-party extensions.

 * Safely usable by arbitrary threads.

Several other mainstream scripting engines (e.g., JavaScript, Microsoft Active
Scripting, etc.) currently provide this capability to cancel the evaluation of
a script. This TIP proposes an implementation that would bring this necessary
aspect of application integration to Tcl. This must be implemented in the
core, because access to and modification of internal Tcl functions and data
structures is required.

~ Specification

A new '''interp cancel''' script command will be added, as follows:

 > '''interp cancel''' ?'''-unwind'''? ?'''--'''? ?''path''? ?''result''?

This command cancels the script being evaluated in the interpreter.

~~ Arguments

 > '''-unwind'''

This argument is optional. Without ''-unwind'', the evaluation stack for the
interpreter is unwound until an enclosing '''catch''' command is found or
there are no further invocations of the interpreter left on the call-stack.
With ''-unwind'', the evaluation stack for the interpreter is unwound without
regard to any intervening '''catch''' command until there are no further
invocations of the interpreter left on the call-stack.

 > '''--'''

This argument is optional, and marks the end of options. The argument
following this one will be treated as being the ''path'' argument even if it
starts with a "-".

 > ''path''

This argument is optional. If not supplied, the current interpreter is
assumed; otherwise, the interpreter specified by ''path'' is used.

 > ''result''

This argument is optional. If not supplied, a default error message is left in
the result of the interpreter; otherwise, the result specified by ''result''
is used.

~~ Behavior

When a script is canceled, the following occur:

 * The ''CANCELED'' flag, and possibly the ''TCL_CANCEL_UNWIND'' flag, are set
   in the interpreter to mark the evaluation in progress as having been
   canceled.

 * The currently executing command/script in the interpreter is made to return
   with code ''TCL_ERROR''. (This is superior to using a novel return code, as
   third-party extensions are usually far better at handling error cases!)

 * The '''catch''' command will only catch errors if the interpreter
   containing it does not have the ''TCL_CANCEL_UNWIND'' flag set.

 * Additional trips through the internal loops of the '''after''',
   '''vwait''', '''update''' and '''tkwait''' commands will not proceed with
   the ''CANCELED'' or ''TCL_CANCEL_UNWIND'' flags set.  (Extensions can find
   this information out by using ''Tcl_Canceled''; see below.)

 * Once the execution unwinds out of the interpreter, so that no further
   invocations of the interpreter are left on the call-stack, both of the
   script cancellation related flags are reset.

 * If there are no invocations of the interpreter on the call-stack when
   ''Tcl_CancelEval'' or '''interp cancel''' are called, then the next script to be
   evaluated will be preemptively canceled.

~~ Notes

 * Going forward, all "long running commands" in the Tcl/Tk core should make
   every effort to comply with the script cancellation functionality by
   calling ''Tcl_Canceled'' at times when it is appropriate to abort
   processing.

 * Extensions can optionally check if they should abort processing by calling
   ''Tcl_Canceled''.

~ C API

~~ Constants

 TCL_CANCEL_UNWIND: New eval-flag bit that applies to ''Tcl_CancelEval'' and
   ''Tcl_Canceled''.

 > When used in ''flags'' for ''Tcl_CancelEval'', the evaluation stack for
   ''interp'' is unwound without regard to any intervening '''catch''' command
   until there are no further invocations of ''interp'' left on the call
   stack. When not set, the evaluation stack for the interpreter is unwound
   until an enclosing '''catch''' command is found or there are no further
   invocations of ''interp'' left on the call-stack.

 > When used in ''flags'' for ''Tcl_Canceled'', checks if the script being
   evaluated has been canceled using the ''TCL_CANCEL_UNWIND'' flag (i.e., the
   evaluation stack for ''interp'' is being completely unwound).

 TCL_LEAVE_ERR_MSG: Existing variable-related flag bit that applies to
   ''Tcl_Canceled'' only.

 > When used in ''flags'' for ''Tcl_Canceled'', an error message will be left
   in the result of ''interp'' if the script being evaluated has been
   canceled.

~~ Functions

 > int '''Tcl_CancelEval'''(Tcl_Interp *''interp'', Tcl_Obj *''resultObjPtr'',
   ClientData ''clientData'', int ''flags'')

The '''Tcl_CancelEval''' function initiates cancellation of the script being
evaluated in ''interp''. It returns a standard Tcl result. If ''resultObjPtr''
is NULL, a default error message will be left in the result of ''interp''
indicating that the script was canceled or unwound. If ''resultObjPtr'' is not
NULL, it will be used verbatim to supply the result of ''interp''. The
''clientData'' is reserved for future use and must be zero. This function may
be called from any thread in the process, regardless of which thread created
''interp''.

 > int '''Tcl_Canceled'''(Tcl_Interp *''interp'', int ''flags'')

The '''Tcl_Canceled''' function checks whether the script being evaluated in
''interp'' has been canceled.  Returns a standard Tcl result (i.e.,
''TCL_ERROR'' if the script being evaluated has been canceled). This function
should only be called from the thread which created ''interp''; otherwise, its
behavior is undefined.

~ Reference Implementation

A reference implementation of this TIP is available
[http://sf.net/tracker/?func=detail&aid=1499394&group_id=10894&atid=310894].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|




|

|








|




|








|








|








|












|


|




|



















|













|
|





|

|

|



|

|

|
|

|
|


|


|


|


|

|


|


|



|




|
|

|
|

|
|
|
|






|


|



|



|

|

|

|
|

|
|
|

|
|

|
|
|

|
|

|
|


|

|
|

|
|
|
|
|
|

|

|

|
|
|
|


|


|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252

# TIP 285: Script Cancellation with [interp cancel] and Tcl_CancelEval

	Author:         Joe Mistachkin <[email protected]>
	Author:         Dawson Cowals <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        04-Jun-2006
	Post-History:   
	Keywords:       eval,cancel,unwind,terminate,runaway,async,thread,safe
	Tcl-Version:    8.6
-----

# Abstract

This TIP introduces the ability to quickly and safely cancel a script within a
specified interpreter from any thread in the process.

# Key Use-Case Scenario

When using Tcl inside a context such as a web-browser \(e.g. as a plugin\), it
is often necessary for the execution of a particular script to be terminated
cleanly without waiting for the script to get to a point where it is able to
respond to events. For example, if the user encounters a page that contains a
script that starts a long-running execution but then decides to navigate away
from the page, it's important to stop the script as soon as possible.

But we do not want to stop the script by means of just terminating the thread,
as this can result in various resources being still allocated, as browsers are
long-running applications. Some of the problems \(e.g. memory waste\) can be
worked around by running the script in a separate process, but there are other
resources that aren't cleaned up that way, such as locked files or shared
memory blocks, and it is always better to give the Tcl interpreter itself an
opportunity to clean up after itself. Furthermore, there are other possible
applications \(such as using Tcl to implement COM objects on Windows\) where the
separate-process method will not work so well.

Instead, what is needed is a way to programmatically make a script stop its
execution even when that script is otherwise determined to continue. This is
different from a resource limit in that the cancellation is not caused by the
exceeding of a predetermined value, but rather by some external event that is
possibly even not processed initially by Tcl at all.

# Technical Rationale

Currently, once the evaluation of a script has been initiated it will do one
of the following:

 * run to completion,

 * run until it encounters an uncaught error,

 * run until it exceeds a pre-determined limit as specified in [[143]](143.md), or

 * run indefinitely.

In each of the cases above, neither the host application nor an interactive
user have any recourse to terminate the script prior to it running its course.

There are many situations for which it is absolutely necessary to be able to
cancel a running script without its cooperation and without setting an
arbitrary limit on the amount of time it can run \([[143]](143.md)\). This is especially
true in a multi-threaded application embedding environment, or where a user
interface is present.

 1. In the case where the completion time for a script is unknown,
    non-existent, or non-deterministic a user may want or need to terminate
    the script prematurely.

 2. When evaluating an untrusted - or marginally trusted - script in either a
    safe or standard interpreter, there is a risk that the script might never
    terminate. In such a situation it is not reasonable to forcibly terminate
    the thread or the entire process.

	 > 1. Forcibly terminating a thread prevents Tcl and Tk from cleaning up their
      thread-specific memory and resources.

	 > 2. The host application may suffer similar memory and resource leaks as
      well as other serious side-effects that may corrupt data, prevent other
      threads from properly synchronizing, or leave the process in an unknown
      and unrecoverable state.

	 > 3. For an interactive host application valuable work may be lost without
      providing an opportunity to save pending modifications. Even in the
      absence of modifications the host application might have been holding
      locks that left unreleased would prevent other processes and users from
      using important resources.

The basic building blocks needed for any scripting language to seamlessly
integrate with an enterprise-ready host application are:

 * Engine Initialization

 * Evaluation

 * Extensibility

 * Cancellation

 * Engine Finalization

Tcl now provides full support for all of the above except script cancellation.
[[143]](143.md) allows for scripts to be prematurely terminated after reaching resource
limits that were pre-arranged by the host application. However, this only
handles terminating scripts based on a narrow set of deterministic criteria.
Full support would require the ability to immediately and unconditionally
terminate the evaluation of a script without adversely affecting the execution
environment of the host application. In addition the following issues must be
addressed:

 * Scripts being evaluated in nested slave interpreters.

 * Interaction with third-party extensions.

 * Safely usable by arbitrary threads.

Several other mainstream scripting engines \(e.g., JavaScript, Microsoft Active
Scripting, etc.\) currently provide this capability to cancel the evaluation of
a script. This TIP proposes an implementation that would bring this necessary
aspect of application integration to Tcl. This must be implemented in the
core, because access to and modification of internal Tcl functions and data
structures is required.

# Specification

A new **interp cancel** script command will be added, as follows:

 > **interp cancel** ?**-unwind**? ?**--**? ?_path_? ?_result_?

This command cancels the script being evaluated in the interpreter.

## Arguments

 > **-unwind**

This argument is optional. Without _-unwind_, the evaluation stack for the
interpreter is unwound until an enclosing **catch** command is found or
there are no further invocations of the interpreter left on the call-stack.
With _-unwind_, the evaluation stack for the interpreter is unwound without
regard to any intervening **catch** command until there are no further
invocations of the interpreter left on the call-stack.

 > **--**

This argument is optional, and marks the end of options. The argument
following this one will be treated as being the _path_ argument even if it
starts with a "-".

 > _path_

This argument is optional. If not supplied, the current interpreter is
assumed; otherwise, the interpreter specified by _path_ is used.

 > _result_

This argument is optional. If not supplied, a default error message is left in
the result of the interpreter; otherwise, the result specified by _result_
is used.

## Behavior

When a script is canceled, the following occur:

 * The _CANCELED_ flag, and possibly the _TCL\_CANCEL\_UNWIND_ flag, are set
   in the interpreter to mark the evaluation in progress as having been
   canceled.

 * The currently executing command/script in the interpreter is made to return
   with code _TCL\_ERROR_. \(This is superior to using a novel return code, as
   third-party extensions are usually far better at handling error cases!\)

 * The **catch** command will only catch errors if the interpreter
   containing it does not have the _TCL\_CANCEL\_UNWIND_ flag set.

 * Additional trips through the internal loops of the **after**,
   **vwait**, **update** and **tkwait** commands will not proceed with
   the _CANCELED_ or _TCL\_CANCEL\_UNWIND_ flags set.  \(Extensions can find
   this information out by using _Tcl\_Canceled_; see below.\)

 * Once the execution unwinds out of the interpreter, so that no further
   invocations of the interpreter are left on the call-stack, both of the
   script cancellation related flags are reset.

 * If there are no invocations of the interpreter on the call-stack when
   _Tcl\_CancelEval_ or **interp cancel** are called, then the next script to be
   evaluated will be preemptively canceled.

## Notes

 * Going forward, all "long running commands" in the Tcl/Tk core should make
   every effort to comply with the script cancellation functionality by
   calling _Tcl\_Canceled_ at times when it is appropriate to abort
   processing.

 * Extensions can optionally check if they should abort processing by calling
   _Tcl\_Canceled_.

# C API

## Constants

 TCL\_CANCEL\_UNWIND: New eval-flag bit that applies to _Tcl\_CancelEval_ and
   _Tcl\_Canceled_.

 > When used in _flags_ for _Tcl\_CancelEval_, the evaluation stack for
   _interp_ is unwound without regard to any intervening **catch** command
   until there are no further invocations of _interp_ left on the call
   stack. When not set, the evaluation stack for the interpreter is unwound
   until an enclosing **catch** command is found or there are no further
   invocations of _interp_ left on the call-stack.

 > When used in _flags_ for _Tcl\_Canceled_, checks if the script being
   evaluated has been canceled using the _TCL\_CANCEL\_UNWIND_ flag \(i.e., the
   evaluation stack for _interp_ is being completely unwound\).

 TCL\_LEAVE\_ERR\_MSG: Existing variable-related flag bit that applies to
   _Tcl\_Canceled_ only.

 > When used in _flags_ for _Tcl\_Canceled_, an error message will be left
   in the result of _interp_ if the script being evaluated has been
   canceled.

## Functions

 > int **Tcl\_CancelEval**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_resultObjPtr_,
   ClientData _clientData_, int _flags_\)

The **Tcl\_CancelEval** function initiates cancellation of the script being
evaluated in _interp_. It returns a standard Tcl result. If _resultObjPtr_
is NULL, a default error message will be left in the result of _interp_
indicating that the script was canceled or unwound. If _resultObjPtr_ is not
NULL, it will be used verbatim to supply the result of _interp_. The
_clientData_ is reserved for future use and must be zero. This function may
be called from any thread in the process, regardless of which thread created
_interp_.

 > int **Tcl\_Canceled**\(Tcl\_Interp \*_interp_, int _flags_\)

The **Tcl\_Canceled** function checks whether the script being evaluated in
_interp_ has been canceled.  Returns a standard Tcl result \(i.e.,
_TCL\_ERROR_ if the script being evaluated has been canceled\). This function
should only be called from the thread which created _interp_; otherwise, its
behavior is undefined.

# Reference Implementation

A reference implementation of this TIP is available
<http://sf.net/tracker/?func=detail&aid=1499394&group_id=10894&atid=310894> .

# Copyright

This document has been placed in the public domain.

Name change from tip/286.tip to tip/286.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

TIP:		286
Title:		Add 'xposition' Command to Menu Widgets
Version:	$Revision: 1.4 $
Author:		Schelte Bron <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Created:	18-Oct-2006
Post-History:	
Keywords:	Tk


~ Abstract

There has been a '''yposition''' subcommand for menu widgets for years, but
its counterpart in the x-direction does not currently exist. This TIP intends
to rectify that situation.

~ Rationale

There is currently no way to obtain the x-position of a menu entry while a
'''menu''' subcommand for obtaining the y-position does exist. Even though on
a normal menu the x-position will always be 1, there are a few circumstances
where the x-position may have some more interesting values. In particular,
this is the case for menubars and for menus with column-breaks.

~ Proposed New Command

This TIP proposes a new subcommand for '''menu''' widgets, '''xposition''',
with the following syntax:

 > ''pathName'' '''xposition''' ''index''

This returns an integer giving the x-coordinate within (i.e., relative to) the
menu window specified by ''pathName'' of the leftmost pixel in the entry
specified by ''index''. The ''index'' may take any of the normal forms for
identifying a menu entry.

~ Reference Implementation

Submitted to SourceForge as Patch #1152376.
[http://sf.net/tracker/?func=detail&aid=1152376&group_id=12997&atid=312997]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|


|




|

|


|

|
|
|


|

|
|

|


>

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

# TIP 286: Add 'xposition' Command to Menu Widgets

	Author:		Schelte Bron <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Created:	18-Oct-2006
	Post-History:	
	Keywords:	Tk
-----

# Abstract

There has been a **yposition** subcommand for menu widgets for years, but
its counterpart in the x-direction does not currently exist. This TIP intends
to rectify that situation.

# Rationale

There is currently no way to obtain the x-position of a menu entry while a
**menu** subcommand for obtaining the y-position does exist. Even though on
a normal menu the x-position will always be 1, there are a few circumstances
where the x-position may have some more interesting values. In particular,
this is the case for menubars and for menus with column-breaks.

# Proposed New Command

This TIP proposes a new subcommand for **menu** widgets, **xposition**,
with the following syntax:

 > _pathName_ **xposition** _index_

This returns an integer giving the x-coordinate within \(i.e., relative to\) the
menu window specified by _pathName_ of the leftmost pixel in the entry
specified by _index_. The _index_ may take any of the normal forms for
identifying a menu entry.

# Reference Implementation

Submitted to SourceForge as Patch \#1152376.
<http://sf.net/tracker/?func=detail&aid=1152376&group_id=12997&atid=312997> 

# Copyright

This document has been placed in the public domain.

Name change from tip/287.tip to tip/287.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

TIP:            287
Title:          Add a Commands for Determining Size of Buffered Data
Version:        $Revision: 1.12 $
Author:         Michael A. Cleverly <[email protected]>
State:          Final
Type:           Project
Vote:		Done
Created:        26-Oct-2006
Post-History:   
Keywords:       Tcl,channel,chan,pendinginput,pendingoutput
Tcl-Version:    8.5


~ Abstract

Many network servers programmed in Tcl (including the venerable tclhttpd) are
vulnerable to DoS (denial of service) attacks because they lack any way to
introspect the amount of buffered data on a non-blocking socket that is in
line buffering mode. This TIP proposes a new subcommand to '''chan''' to
allow the amount of buffered input and buffered output (for symmetry) to be
inspected from Tcl.

~ Rationale

Many network protocols are inherently line-oriented (HTTP, SMTP, etc.) and the
natural approach to implementing servers for these protocols in Tcl is to
configure the incoming client sockets to use non-blocking I/O and to have
''line'' buffering and then define a readable fileevent callback.

|    proc accept {sock addr port} {
|        fconfigure $sock -buffering line -blocking 0
|        fileevent $sock readable [list callback $sock ...]
|    }

|    socket -server accept $listenPort

Recall that a readable fileevent will be called even when there is an
incomplete line buffered. As the '''fileevent''' manual page states:

 > A channel is considered to be readable if there is unread data available on
   the underlying device. A channel is also considered to be readable if there
   is unread data in an input buffer, except in the special case where the
   most recent attempt to read from the channel was a gets call that could not
   find a complete line in the input buffer.

The '''fblocked''' (and in 8.5 '''chan blocked''') command provides the Tcl
programmer a means to test whether:

 > the most recent input operation ...  returned less information than
   requested because all available input was exhausted.

There is currently no way at the Tcl level to see how much data is buffered
and could be read safely (via '''read''' instead of '''gets''').

There is also no way to specify any kind of upper limit on the length of a
line; when in line-buffering mode all input is buffered until an end-of-line
sequence is encountered or the EOF on the channel is reached.

The practical result is that all network daemons written in Tcl using
line-oriented I/O ('''gets''') can be fed repeated input lacking an
end-of-line sequence until all physical memory is exhausted.

This vulnerability has been recognized since at least 2001. See, for example,
the discussion between George Peter Staplin and Donald Porter on the ''gets''
page on the Tcl'ers Wiki [http://wiki.tcl.tk/gets].

~ Proposed Change

At the C level Tcl already has a function, ''Tcl_InputBuffered'' which returns
the number of unread bytes buffered for a channel and a corresponding ''Tcl_OutputBuffered'' which returns the number of bytes buffered for output that have not yet been flushed out.

This TIP proposes to implement a new ''chan pending'' command which
will take two arguments: a ''mode'' and a ''channelId''.  The mode argument can be either ''input'' or ''output''.

When the mode is ''input'' the command returns the value of ''Tcl_InputBuffered()'' (if the channel was open for input or -1 otherwise).

When the mode is ''output'' the command returns the value of ''Tcl_OutputBuffered()'' (if the channel was output for output or -1 otherwise).

This allows a programmer developing network daemons at the Tcl level to
implement their own policy decisions based on the size of the unread line.
Potential DoS situations could be avoided (in an application specific manner)
long before all memory was exhausted.

| if {[chan blocked $sock] && [chan pending input $sock] > $limit} {
|     # Take application specific steps (i.e., [close $sock] or
|     # [read $sock] to process a partial line and drain the buffer, etc.)
| }


~ Rejected Alternatives

 * Adding a flag to '''fblocked''' to return the number of unread bytes
   instead of just 0 or 1 (since '''fblocked''' is now considered deprecated
   as per [208]).

 * Polluting the global namespace with a new '''favailable''', '''fpending'''
   or '''fqueued''' command.

 * A '''chan unread''' because of potential confusion as to whether it
   performed ''ungetch()'' type functionality (''un-reed'' vs ''un-red'').

 * Any sort of '''-maxchars''' or '''-maxbytes''' flag to '''gets''' in order
   to not complicate the semantics of '''gets'''.  Additionally without even
   further complicating '''gets''' semantics one could not distinguish input
   of exactly $limit characters from the case where only $limit characters
   were returned (with some input remaining unread).

 * The initial version of this TIP called for a ''chan available'' command.
   This was changed to ''pendinginput'' (and ''pendingoutput'' added for
   symmetry's sake) following suggestions on news:comp.lang.tcl from Donald
   Arseneau and Donal Fellows, and later to ''chan pending'' that takes a ''mode'' argument (''input'' or ''output'') based on suggestions from Donald Porter and Joe English.

~ Reference Implementation

[[RFE 1586860]] at SourceForge now contains a patch implementing '''chan
pendinginput''' and '''chan pendingoutput''' (including updated '''chan''' man
page and corresponding test cases)
[http://sourceforge.net/tracker/index.php?func=detail&aid=1586860&group_id=10894&atid=360894].

~ Copyright

This document is in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|

|
|


|

|


|

|
|
|
<
>
|


|







|






|






|



|
|

|

|
|

|
|

|

|



|


|
|
|
<
|
>
|

|
|
|

|
|

|
|

|
|
|

|

|
|
|
|

|

|
|
|
|

|


>

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

# TIP 287: Add a Commands for Determining Size of Buffered Data

	Author:         Michael A. Cleverly <[email protected]>
	State:          Final
	Type:           Project
	Vote:		Done
	Created:        26-Oct-2006
	Post-History:   
	Keywords:       Tcl,channel,chan,pendinginput,pendingoutput
	Tcl-Version:    8.5
-----

# Abstract

Many network servers programmed in Tcl \(including the venerable tclhttpd\) are
vulnerable to DoS \(denial of service\) attacks because they lack any way to
introspect the amount of buffered data on a non-blocking socket that is in
line buffering mode. This TIP proposes a new subcommand to **chan** to
allow the amount of buffered input and buffered output \(for symmetry\) to be
inspected from Tcl.

# Rationale

Many network protocols are inherently line-oriented \(HTTP, SMTP, etc.\) and the
natural approach to implementing servers for these protocols in Tcl is to
configure the incoming client sockets to use non-blocking I/O and to have
_line_ buffering and then define a readable fileevent callback.

	    proc accept {sock addr port} {
	        fconfigure $sock -buffering line -blocking 0
	        fileevent $sock readable [list callback $sock ...]

	    }
	    socket -server accept $listenPort

Recall that a readable fileevent will be called even when there is an
incomplete line buffered. As the **fileevent** manual page states:

 > A channel is considered to be readable if there is unread data available on
   the underlying device. A channel is also considered to be readable if there
   is unread data in an input buffer, except in the special case where the
   most recent attempt to read from the channel was a gets call that could not
   find a complete line in the input buffer.

The **fblocked** \(and in 8.5 **chan blocked**\) command provides the Tcl
programmer a means to test whether:

 > the most recent input operation ...  returned less information than
   requested because all available input was exhausted.

There is currently no way at the Tcl level to see how much data is buffered
and could be read safely \(via **read** instead of **gets**\).

There is also no way to specify any kind of upper limit on the length of a
line; when in line-buffering mode all input is buffered until an end-of-line
sequence is encountered or the EOF on the channel is reached.

The practical result is that all network daemons written in Tcl using
line-oriented I/O \(**gets**\) can be fed repeated input lacking an
end-of-line sequence until all physical memory is exhausted.

This vulnerability has been recognized since at least 2001. See, for example,
the discussion between George Peter Staplin and Donald Porter on the _gets_
page on the Tcl'ers Wiki <http://wiki.tcl.tk/gets> .

# Proposed Change

At the C level Tcl already has a function, _Tcl\_InputBuffered_ which returns
the number of unread bytes buffered for a channel and a corresponding _Tcl\_OutputBuffered_ which returns the number of bytes buffered for output that have not yet been flushed out.

This TIP proposes to implement a new _chan pending_ command which
will take two arguments: a _mode_ and a _channelId_.  The mode argument can be either _input_ or _output_.

When the mode is _input_ the command returns the value of _Tcl\_InputBuffered\(\)_ \(if the channel was open for input or -1 otherwise\).

When the mode is _output_ the command returns the value of _Tcl\_OutputBuffered\(\)_ \(if the channel was output for output or -1 otherwise\).

This allows a programmer developing network daemons at the Tcl level to
implement their own policy decisions based on the size of the unread line.
Potential DoS situations could be avoided \(in an application specific manner\)
long before all memory was exhausted.

	 if {[chan blocked $sock] && [chan pending input $sock] > $limit} {
	     # Take application specific steps (i.e., [close $sock] or
	     # [read $sock] to process a partial line and drain the buffer, etc.)

	 }

# Rejected Alternatives

 * Adding a flag to **fblocked** to return the number of unread bytes
   instead of just 0 or 1 \(since **fblocked** is now considered deprecated
   as per [[208]](208.md)\).

 * Polluting the global namespace with a new **favailable**, **fpending**
   or **fqueued** command.

 * A **chan unread** because of potential confusion as to whether it
   performed _ungetch\(\)_ type functionality \(_un-reed_ vs _un-red_\).

 * Any sort of **-maxchars** or **-maxbytes** flag to **gets** in order
   to not complicate the semantics of **gets**.  Additionally without even
   further complicating **gets** semantics one could not distinguish input
   of exactly $limit characters from the case where only $limit characters
   were returned \(with some input remaining unread\).

 * The initial version of this TIP called for a _chan available_ command.
   This was changed to _pendinginput_ \(and _pendingoutput_ added for
   symmetry's sake\) following suggestions on news:comp.lang.tcl from Donald
   Arseneau and Donal Fellows, and later to _chan pending_ that takes a _mode_ argument \(_input_ or _output_\) based on suggestions from Donald Porter and Joe English.

# Reference Implementation

[RFE 1586860] at SourceForge now contains a patch implementing **chan
pendinginput** and **chan pendingoutput** \(including updated **chan** man
page and corresponding test cases\)
<http://sourceforge.net/tracker/index.php?func=detail&aid=1586860&group_id=10894&atid=360894> .

# Copyright

This document is in the public domain.

Name change from tip/288.tip to tip/288.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

TIP:            288
Title:          Allow "args" Anywhere in Procedure Formal Arguments
Version:        $Revision: 1.14 $
Author:         Peter Spjuth <[email protected]>
Author:         Andreas Leitgeb <[email protected]>
Author:         Peter Spjuth <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        03-Oct-2006
Post-History:   
Keywords:       Tcl,proc
Tcl-Version:    8.7


~ Abstract

This TIP proposes to make ''args'' have its special meaning as a formal
'''proc'''edure argument anywhere in the argument list.

~ Rationale

Many commands, specially many of Tcl's built in commands, have their variadic arguments in the beginning of the argument list and their required arguments at the end. An example is [['''lsearch''' ?''options''? ''list string'']].

Writing tcl procedures in that style is currently a bit cumbersome since you need to do you own argument counting and assignment to variables from "args".

If "args" had its special meaning at any location in the argument list, it would help with such a task, and it would make things more consistent.

To get simple semantics, optional arguments are not allowed after "args".  Optional arguments that precede "args" will be handled as before.  This TIP does not, as of now, specify defaulted arguments directly preceding non-defaulte ones. This should be addressed in a separate TIP.

~ Specification

At most one proc argument may be named "args" and can be anywhere in the
argument list. Arguments after "args" may not be optional. Arguments are
assigned in the following order:

 1. Assign arguments right of "args" from the right.

 2. Assign arguments left of "args" from the left. Handling of defaulted parameters preceding "args" remains as it was (but disregarding the non-defaulted ones after "args").

 3. Remaining arguments are assigned to "args".

~ Compatiblity

Currently "args" is allowed anywhere in the argument list, and becomes a normal variable if not last. Most scripts probably don't use this since it would be rather confusing, but it might exist.

All such occurrances would need to be fixed.

Detecting such scripts in an automated way would be simple and fixing them is trivial.

~ Examples

New style:

|proc lgurka {args list item} {
|    array set opts {-apa 1 -bepa "" -cepa 0}
|    foreach {arg val} $args {
|        set opts([prefix match {-apa -bepa -cepa} $arg]) $val
|    }

|    # Do real stuff
|}


Old style:

|proc lgurka {args} {
|    if {[llength $args] < 2} {
|        return -code error "wrong # args: should be \"lgurka ?args? list item\""
|    }

|    set item [lindex $args end]
|    set list [lindex $args end-1]
|    set args [lrange $args 0 end-2]
|
|    array set opts {-apa 1 -bepa "" -cepa 0}
|    foreach {arg val} $args {
|        set opts([prefix match {-apa -bepa -cepa} $arg]) $val
|    }

|    # Do real stuff
| }


|proc x {a args b} { puts "a=$a, args=$args, b=$b" }

|x 1 2  ;# ->   a=1, args=, b=2

|x 1 2 3 ;# ->  a=1, args=2, b=3

|x 1 ;# -> error: wrong # args: should be "x a ?args? b"

|proc y {a {b x} args c} { ... }

|y 1 2 3 ;#   a=1 b=2 c=3  args is empty

|proc z {a {b x} c args} { ... }

|z 1 2  ;# -> error: wrong # args: should be "z a ?b? c ..."

To change "z" is not covered by this TIP.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|
|

|

|







|







|



|







|



|
|
|
|
<
>
|
<
>



|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
<
|
>
|

|

|

|

|

|

|

|



|


>

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

# TIP 288: Allow "args" Anywhere in Procedure Formal Arguments

	Author:         Peter Spjuth <[email protected]>
	Author:         Andreas Leitgeb <[email protected]>
	Author:         Peter Spjuth <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        03-Oct-2006
	Post-History:   
	Keywords:       Tcl,proc
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to make _args_ have its special meaning as a formal
**proc**edure argument anywhere in the argument list.

# Rationale

Many commands, specially many of Tcl's built in commands, have their variadic arguments in the beginning of the argument list and their required arguments at the end. An example is [**lsearch** ?_options_? _list string_].

Writing tcl procedures in that style is currently a bit cumbersome since you need to do you own argument counting and assignment to variables from "args".

If "args" had its special meaning at any location in the argument list, it would help with such a task, and it would make things more consistent.

To get simple semantics, optional arguments are not allowed after "args".  Optional arguments that precede "args" will be handled as before.  This TIP does not, as of now, specify defaulted arguments directly preceding non-defaulte ones. This should be addressed in a separate TIP.

# Specification

At most one proc argument may be named "args" and can be anywhere in the
argument list. Arguments after "args" may not be optional. Arguments are
assigned in the following order:

 1. Assign arguments right of "args" from the right.

 2. Assign arguments left of "args" from the left. Handling of defaulted parameters preceding "args" remains as it was \(but disregarding the non-defaulted ones after "args"\).

 3. Remaining arguments are assigned to "args".

# Compatiblity

Currently "args" is allowed anywhere in the argument list, and becomes a normal variable if not last. Most scripts probably don't use this since it would be rather confusing, but it might exist.

All such occurrances would need to be fixed.

Detecting such scripts in an automated way would be simple and fixing them is trivial.

# Examples

New style:

	proc lgurka {args list item} {
	    array set opts {-apa 1 -bepa "" -cepa 0}
	    foreach {arg val} $args {
	        set opts([prefix match {-apa -bepa -cepa} $arg]) $val

	    }
	    # Do real stuff

	}

Old style:

	proc lgurka {args} {
	    if {[llength $args] < 2} {
	        return -code error "wrong # args: should be \"lgurka ?args? list item\""

	    }
	    set item [lindex $args end]
	    set list [lindex $args end-1]
	    set args [lrange $args 0 end-2]
	
	    array set opts {-apa 1 -bepa "" -cepa 0}
	    foreach {arg val} $args {
	        set opts([prefix match {-apa -bepa -cepa} $arg]) $val

	    }
	    # Do real stuff

	 }

	proc x {a args b} { puts "a=$a, args=$args, b=$b" }

	x 1 2  ;# ->   a=1, args=, b=2

	x 1 2 3 ;# ->  a=1, args=2, b=3

	x 1 ;# -> error: wrong # args: should be "x a ?args? b"

	proc y {a {b x} args c} { ... }

	y 1 2 3 ;#   a=1 b=2 c=3  args is empty

	proc z {a {b x} c args} { ... }

	z 1 2  ;# -> error: wrong # args: should be "z a ?b? c ..."

To change "z" is not covered by this TIP.

# Copyright

This document has been placed in the public domain.

Name change from tip/289.tip to tip/289.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

TIP:            289
Title:          Revision of [lrepeat] Argument Order
Version:        $Revision: 1.5 $
Author:         Peter Spjuth <[email protected]>
Author:          <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        26-Oct-2006
Post-History:   
Keywords:       Tcl
Tcl-Version:    8.5


~ Abstract

This TIP proposes to alter the argument order of '''lrepeat''' to be similar
to '''string repeat'''.

~ Rationale

In [136], lrepeat is defined as:

 > '''lrepeat''' ''number element1'' ?''element2''? ?''element3''? ...

whereas the old string repeat command is:

 > '''string repeat''' ''string number''

This difference between similar commands is bound to cause confusion.
Consistency is good.

~ Specification

Change lrepeat's argument order to:

 > '''lrepeat''' ''element1'' ?''element2''? ?''element3''? ... '''number'''

~ Examples:

| lrepeat 0 100                - returns list of 100 zeros
| lrepeat [lrepeat 0 100] 100  - returns 100x100 matrix (list of lists) of zeros
| lrepeat a b c 3              - returns nine-element list {a b c a b c a b c}
| lrepeat a b c 1              - identical to [list a b c]

~ Discussion:

DGP: The main feature that appears to get lost in this change is the
ability to redirect aliases or subcommands of ensembles to '''lrepeat'''
calls with the number of repetitions already filled in.

PS: On the other hand, you get the ability to redirect aliases or
subcommands of ensembles to '''lrepeat''' calls with the elements already
filled in.

DGP: I skimmed the old TIP 136 messages in the TCLCORE archives. One
thing to note is that the existing '''lrepeat''' syntax in 8.5a5 was
chosen in part to be consistent with the existing '''struct::list
repeat''' syntax in the struct::list package.

DGP: I think it's fair to say that given a complete "do-over"
more of us would opt to change '''string repeat''' to agree
with '''lrepeat''' and '''struct::list repeat''' than the other
way around.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|
|

|

|

|



|




|



|

|

|
|
|
|

|


|



|



|
|
|


|
|


|


>

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

# TIP 289: Revision of [lrepeat] Argument Order

	Author:         Peter Spjuth <[email protected]>
	Author:          <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        26-Oct-2006
	Post-History:   
	Keywords:       Tcl
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to alter the argument order of **lrepeat** to be similar
to **string repeat**.

# Rationale

In [[136]](136.md), lrepeat is defined as:

 > **lrepeat** _number element1_ ?_element2_? ?_element3_? ...

whereas the old string repeat command is:

 > **string repeat** _string number_

This difference between similar commands is bound to cause confusion.
Consistency is good.

# Specification

Change lrepeat's argument order to:

 > **lrepeat** _element1_ ?_element2_? ?_element3_? ... **number**

# Examples:

	 lrepeat 0 100                - returns list of 100 zeros
	 lrepeat [lrepeat 0 100] 100  - returns 100x100 matrix (list of lists) of zeros
	 lrepeat a b c 3              - returns nine-element list {a b c a b c a b c}
	 lrepeat a b c 1              - identical to [list a b c]

# Discussion:

DGP: The main feature that appears to get lost in this change is the
ability to redirect aliases or subcommands of ensembles to **lrepeat**
calls with the number of repetitions already filled in.

PS: On the other hand, you get the ability to redirect aliases or
subcommands of ensembles to **lrepeat** calls with the elements already
filled in.

DGP: I skimmed the old TIP 136 messages in the TCLCORE archives. One
thing to note is that the existing **lrepeat** syntax in 8.5a5 was
chosen in part to be consistent with the existing **struct::list
repeat** syntax in the struct::list package.

DGP: I think it's fair to say that given a complete "do-over"
more of us would opt to change **string repeat** to agree
with **lrepeat** and **struct::list repeat** than the other
way around.

# Copyright

This document has been placed in the public domain.

Name change from tip/29.tip to tip/29.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182

183
184

185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200

201
202
203
204
205
206
207
208
209

210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467

TIP:            29
Title:          Allow array syntax for Tcl lists
Version:        $Revision: 1.8 $
Author:         Kevin Kenny <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        07-Mar-2001
Post-History:   
Discussions-To: news:comp.lang.tcl,mailto:[email protected]
Tcl-Version:    9.0


~ Abstract

Most popular programming languages provide some sort of indexed array
construct, where array subscripts are integers.  Tcl's lists are, in
fact, arrays, but the existing syntax obscures the fact.  Moreover,
the existing list commands make it difficult to manipulate lists as
arrays without running into peculiar performance issues.  This TIP
proposes that the syntax of ''variableName(value)'' be extended to
function as an array selector if ''variableName'' designates a list.
This change is upward compatible with existing Tcl scripts, because
the proposed syntax results in a runtime error in every extant Tcl
release.

~ Rationale

The implementation of lists in Tcl has evolved far beyond the original
conception.  While lists were originally conceived to be strings with
a particular syntax that allowed them to be parsed as lists, the
internal representation of a list is now an array of pointers to
''Tcl_Obj'' structures.

Tcl programmers, for the most part, have not taken advantage of this
evolution.  Code that uses hash tables for the purpose is still
extremely common.  Moreover, it is difficult to update lists in place,
even if their internal representations are known not to be shared.
One example of this difficulty is seen in the discussions
[http://purl.org/thecliff/tcl/wiki/941] of how best to shuffle a list
of items.  The discussion began with a na�ve implementation of Jon
Bentley's method of performing random swaps:

|  proc shuffle1 { list } {
|      set n [llength $list]
|      for { set i 0 } { $i < $n } { incr i } {
|          set j [expr {int(rand()*$n)}]
|          set temp [lindex $list $j]
|          set list [lreplace $list $j $j [lindex $list $i]]
|          set list [lreplace $list $i $i $temp]
|      }

|      return $list
|  }


Aside from the fact that the syntax obscures what the program is
doing, the implementation suffers from an obscure performance problem.
When the ''lreplace'' calls in the ''shuffle1'' procedure are
executed, the internal representation of ''list'' has two references:
the value of the variable, and the parameter passed to ''lreplace''.
The multiple references force ''lreplace'' to copy the list, leading
to quadratic performance when large lists are shuffled.

It is possible, albeit difficult, to alleviate this problem by careful
management of the lifetime of ''Tcl_Obj'' structures, but this change
complicates the code.  The simplest way to fix the performance is
probably to use Donal Fellows's implementation of the ''K''
combinator:

| proc K { x y } { set x }

which allows the caller of ''lreplace'' to extract the value of
''list'', change the value of ''list'' so that the extracted value is
unshared, and then pass the extracted value as a parameter to
''lreplace:''

|  proc shuffle1a { list } {
|      set n [llength $list]
|      for { set i 0 } { $i < $n } { incr i } {
|          set j [expr {int(rand()*$n)}]
|          set temp1 [lindex $list $j]
|          set temp2 [lindex $list $i]
|          set list [lreplace [K $list [set list {}]] $j $j $temp2]
|          set list [lreplace [K $list [set list {}]] $i $i $temp1]
|      }

|      return $list
|  }


Now the performance of the code is ''O(n)'' where ''n'' is the length
of the list, but the programmer's intent has been seriously obscured!

These drawbacks have led prominent individuals such as Richard
Stallman [http://www.vanderburg.org/Tcl/war/0000.html] to assert that
Tcl lacks arrays.

''This proposal includes the absolute minimum of functionality needed
to provide array-style indexing for variables containing Tcl list
objects.''  The reason for this limitation is that omitted
functionality can be added later without breaking existing scripts.
On the other hand, ill-considered extensions may turn into something
that we're doomed to support forever.

~ Specification

This TIP's proposed change can be stated succinctly:

 > Wherever the notation ''a(x)'' may be used to refer to an array
   element in the language, allow it also to refer to an element of a
   list, provided that the variable ''a'' is scalar and the value
   ''x'' is an index suitable for the ''lindex'' command.

   ''Exception:'' Traces, ''unset'' and ''upvar'' calls designating
   individual list elements shall not be supported.  (As a consequence
   of this rule, list elements may also not appear as linked variables
   in C code, implying that they also cannot appear as ''-variable''
   or ''-textvariable'' options on Tk widgets.)

Note that this change is backward compatible with existing Tcl
scripts!  If a notation like ''a(x)'' is used to refer to a scalar
variable in today's Tcl, the result is an error:

| % set a [list foo bar grill]
| foo bar grill
| % set a(2)
| can't read "a(2)": variable isn't array
| % puts $a(2)
| can't read "a(2)": variable isn't array
| % set a(2) zot
| can't set "a(2)": variable isn't array

The default behavior, if ''a'' is not set, and a script executes

| set a(2) zot

will still be to create an associative array.  If a script wishes to
perform such actions on a list, it will be necessary first to
initialize the variable:

| set a [list]
| set a(0) foo

Note that in the example above, there is no requirement that the
internal representation of ''a'' be a list; the line,

| set a [list]

could have been replaced with

| set a {}

with the only impact being the run-time cost of shimmering the empty
string into an empty list.  Nowhere does this proposal introduce
behavior that depends on a specific internal representation for any
variable.

This proposal the syntax of the subscript shall be precisely those
values that are accepted as the second argument to the ''lindex'' command.
In other words, the subscript may be an integer ''N'', or the string
''end'' or ''end-N''.  The value of ''N'' may not be less than zero
nor greater than nor equal to the length of the list on any usage that
reads a list element.  

A usage that writes a list element may use an integer equal to
 the length of the list, or the string ''end+1'', to designate
the element one past the end.  In other words,

|  set a(end+1) foo

will have the same effect as:

|  lappend a foo

With the proposed change in syntax, the procedure to shuffle a list
becomes much more straightforward:

|  proc shuffle1 { list } {
|      set n [llength $list]
|      for { set i 0 } { $i < $n } { incr i } {
|          set j [expr {int(rand()*$n)}]
|          set temp $list($j)
|          set list($j) $list($i)
|          set list($i) $temp
|      }

|      return $list
|  }


The given implementation copies the list only once, the first time
that the line:

|          set list($j) $list($i)

is executed.  Thereafter, the list is an unshared object, and the
replacements are performed in place.

It shall be illegal to pass a list element as the parameter to
''upvar;'' that is, the following usage:

|  proc increment { varName } {
|      upvar 1 $varName v
|      incr v
|  }

|  set x [list 1 2 3]
|  increment x(0)

will ''not'' be supported.  However, the commoner form:

|  proc incrementElement { arrayName index } {
|      upvar 1 $arrayName array
|      incr array($index)
|  }

|  set x [list 1 2 3]
|  incrementElement x 0

will, of course, work as expected.

~ Discussion

Several reviewers expressed concern about the reuse of array syntax.
In particular, the alternative syntax $a<$element> was proposed
repeatedly.  Alas, there is no good alternative syntax that will not
break at least some existing scripts.  The proposed syntax using
angle-brackets is a poor choice, because Tcl scripts that generate
Web pages frequently have code like:

|  puts "<$tag>$text</$tag>

that would be broken horribly by such a change.

There are several obvious extensions to the proposal that are not
addressed, and these omissions are intentional.

   * The proposal makes no attempt to deal with multiple subscripts
     as a means of accessing nested lists.

Use of multiple subscripts is closely related to the withdrawn [22]
(which the author of this TIP intends to revive).  If the related TIP
is accepted, the syntax for the subscript could readily be expanded
so that it could be a Tcl list giving the subscripts in lexicographic
sequence.  For example

| set a(2 3) foo

could be used to set the fourth element of the third sublist.

   * The proposal allows the ''set'' command (or any other use of
     ''Tcl_SetVar2Ex'') to set only the elements that are in the list
     already plus the one one beyond the end.

Tcl lists are fundamentally dense arrays.  Allowing non-contiguous
elements, that is, sparse arrays, is a fundamental change to their
semantics.  Such a change is not contemplated at this time.

   * The proposal does not allow the ''unset'' command (or any
     other command that arrives at ''Tcl_UnsetVar2'') to delete members
     of a list.

Earlier versions of the proposal had proposed to permit:

|  unset a([expr { [llength $a] - 1}])

or equivalently:

|  unset a(end)

to reduce the length of the list by one.  In subsequent discussions,
the reviewers found it distasteful that the proposed syntax did not
permit unsetting interior elements of a list.  Alas, the discussion
did not arrive at a consensus on what the precise semantics of such
an operation ought to be.  Some reviewers favored attempting to emulate
sparse arrays (again, a fundamental change to the semantics of
Tcl lists that is not contemplated at this time).  Others preferred
the semantics of shifting the remaining elements, so that

|   unset a($n)

would always be equivalent to

|   set a [lreplace $a $n $n]

except for performance.  Both camps found it overly restrictive to
limit the semantics of ''unset'' to those of the original proposal.
Because the two groups failed to achieve a consensus, the author of
this TIP finds it prudent to forbid ''unset'' altogether in the
initial implementation.

   * The ''array'' command continues to operate only on associative
     arrays.

Lists are a simple enough structure that the full power of the
''array'' command is not required to deal with them, and having it
work on lists as well as arrays seems like needless effort.  Moreover,
existing code may well depend on a combination of ''[array exists]''
and ''[info exists]'' to distinguish associative arrays from scalar
variables (including lists).

   * The ''upvar'' command cannot address individual list elements.

Extending the syntax in this fashion would make ''upvar'' more
consistent in its behavior, but appears to be expensive, in terms of
both performance (tracking down the linked references if a list is
rebuilt) and the effort required for implementation (the author of
this TIP is unlikely to have the time required to implement the
necessary changes to ''struct Var'' and the associated code).

   * No traces on list elements shall be supported.  List elements
     cannot function as linked variables in C code.

The original proposal had specified how write and unset, but not read,
traces could be implemented.  The original proposed functionality is
described in the Appendix.  The author of this TIP had proposed it
primarily so that list elements could function as linked variables
(for instance, in the ''-variable'' and ''-textvariable'' options
of Tk widgets).

Once again, this part of the original proposal failed for lack of
consensus among the reviewers.  Some felt that supporting read traces
in one context but not another would be overly confusing.  Moreover,
the proposal as written would cause write traces on the elements to fire
if the internal representation of a variable shimmered between a list
and something else.  Some reviewers found the excess trace callbacks
to be objectionable.  

At least one reviewer proposed a separate ''trace add element'' syntax
for list-element traces.  This syntax would address some of the
concerns about the lack of read traces (there's no reason that ''trace
add element'' should function the same as ''trace add variable'').
Alas, it would not address the problem of linked variables, which was
the main reason for having the traces in the first place.

Given the lack of consensus, the author of this TIP finds it prudent
to withdraw or postpone this portion of the proposal.

~ See Also

[22] - withdrawn.

~ Reference Implementation

No reference implementation has yet been developed; the author of this
TIP wishes to solicit the opinions of the Tcl community before
spending a lot of time implementing a possibly bad idea.

~ Change history

''12 March 2001:'' Added detailed discussion of the specific subscript
ranges supported by read, write and unset operations.  Changed the discussion
to reject the alternative of padding an array when setting an index beyond
the end.  Added discussion of the details of write and unset traces, and
rejecting read traces as being infeasible to implement.  Clarified the
example of creating an empty list so as to avoid any misapprehension that
these changes depend on list variables' having a particular representation
at any given time; in fact, every detail of this proposal is tolerant of
shimmering.

''13 March 2001:'' Fixed a copy-and-paste error in the 'incrementElement'
example, and added to the discussion the fact that all operations will
throw errors in the event of a malformed list.

''30 March 2001:'' Revised yet again, in an attempt to remove as
much controversial functionality as possible and reduce the TIP to the
minimum useful subset, on the grounds that it is prudent to avoid
supporting functionality that may later prove ill-considered.

~ Summary of objections

''DeJong,'' ''English'' (non-voting), ''Flynt'' (non-voting),
''Harrison,'' ''Ingham,'' ''Lehenbauer,'' ''Polster,'' (non-voting),
''Porter,'' and ''Sofer'' (non-voting), expressed concern that the
proposed syntax is confusing, since the target object could be either
an associative array or a linear array (that is, a Tcl list).
These objections varied in stridency from "yes, it is a risk, and
I'm prepared to accept it," to "this will just be too confusing, and I
can't countenance this proposal."

''Hobbs'' found the original proposal's omission of reverse indexing
distasteful.  The current version of the proposal embraces his
suggested change.

''Cuthbert'' (non-voting), ''Hobbs'', and ''Porter'' expressed concern
over the semantics of ''unset.'' Since consensus was not achieved, the
current version of the proposal defers implementation of ''unset.''

Several reviewers, most notably ''Ousterhout,'' found the proposed
''trace'' semantics distasteful.  The current version of the proposal
eliminates ''trace'' on list elements.

Several reviewers appeared to labor under the misconception that this
TIP introduces behavior that is dependent at run time upon the
internal representation of a Tcl object.  It does not; it is tolerant
of shimmering in all cases.

Several reviewers objected to the proposal on the grounds that it does
not specify a general object system and how such a system would allow
for generic containers with array syntax.  The author's intention in
writing it was not to propose such a system, but only to propose a
small piece of syntactic sugar, implementable here and now, that is
compatible with that broader vision.

~ Appendix: Possible implementation of read and unset traces.

The original proposal contained the following language, which could
be used as a guide if traces on list elements are contemplated at a
future time.

Write and unset traces on list elements shall be supported; it shall
be permissible to write:

|    trace add variable x(1) write writeCallback

or

|    trace add variable x(1) unset unsetCallback

The ''write'' callback shall be invoked whenever the given list
element changes value; the ''unset'' callback shall be invoked
whenever the variable is unset or when its length shrinks to the point
that it no longer has a member with the given index.

Read traces on list elements shall ''not'' be supported.  It is
too difficult at this point to define what their semantics should be.
For instance, if a program executes the following code:

|   trace add variable x(0) read readCallback
|   set x [list foo bar grill]
|   set y [string range $x 4 end]

should the callback fire?  By one argument, the program has not
read element zero of the list; by another, using the list as a string
has read every element, and all read traces should fire.  In any case,
the read trace on a variable fires before its usage is known; it appears
impossible in existing code to implement selective read tracing on list
elements.

The implementation of write and unset traces on list elements will be
done by establishing a C-level write trace on the variable as a whole.
The client data of the trace will designate a structure containing the
ordinal number of the element being traced, and a ''Tcl_Obj'' pointer
designating its old value.  The reference count of the ''Tcl_Obj''
will be incremented when this pointer is stored.  Note that this
increment operation makes the object shared.  Any change to the
designated element will thus need to copy the object.

When the write trace fires, the list representation of the variable
will be extracted, reconstituting it from the string representation if
necessary.  If extracting the list representation fails, the trace
will be considered to have failed as well, and the trace callback will
return ''TCL_ERROR''.  If extracting the list representation succeeds,
the list length will be compared with the ordinal number of the
element being traced.  If the element number is no longer within the
list, an unset trace fires if one exists.  If the element number is
within the list, the two ''Tcl_Obj'' pointers are compared.  If they
are identical, the list element in question is unchanged, and nothing
need be done.  Otherwise, the write trace fires.  

This behavior is conservative in that an operation that spoils the
list representation of the object is considered to have written every
element of the list.  This rule is consistent with the rule that write
traces on ordinary Tcl variables fire whenever the variable is set,
even if it is being set to an identical value.

In any event, after the conclusion of a trace callback, the saved
Tcl_Obj will have its reference count decremented and be replaced with
the current element of the list (with reference count appropriately
incremented, of course).

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|






|
|




|





|






|
|


|
|
|
|
|
|
|
<
>
|
<
|
>


|
|
|
|



|

|


|

|
|

|

|
|
|
|
|
|
|
|
<
>
|
<
|
>
|



|


|

|




|



|

|
|

|
|

|
|


|


|
|
|
|
|
|
|
|

|

|





|
|


|

|



|







|
|
|




|


|



|




|
|
|
|
|
|
|
<
>
|
<
>




|





|

|
|
|
<
>
|
|

|

|
|
|
<
>
|
|



|








|









|
|




|



|
|






|
|




|



|






|
|


|



|


|

|


|



|

|
|
|

|

|

|
|

|








|
|









|

|
|






|

|

|





|

|









|



|




|

|
|
|

|




|



|
|
|

|
|
|













|








|



|

|
|



|



|
|
|











|
|








|



|










|
|
|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

181
182

183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

199
200
201
202
203
204
205
206
207

208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467

# TIP 29: Allow array syntax for Tcl lists

	Author:         Kevin Kenny <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        07-Mar-2001
	Post-History:   
	Discussions-To: news:comp.lang.tcl,mailto:[email protected]
	Tcl-Version:    9.0
-----

# Abstract

Most popular programming languages provide some sort of indexed array
construct, where array subscripts are integers.  Tcl's lists are, in
fact, arrays, but the existing syntax obscures the fact.  Moreover,
the existing list commands make it difficult to manipulate lists as
arrays without running into peculiar performance issues.  This TIP
proposes that the syntax of _variableName\(value\)_ be extended to
function as an array selector if _variableName_ designates a list.
This change is upward compatible with existing Tcl scripts, because
the proposed syntax results in a runtime error in every extant Tcl
release.

# Rationale

The implementation of lists in Tcl has evolved far beyond the original
conception.  While lists were originally conceived to be strings with
a particular syntax that allowed them to be parsed as lists, the
internal representation of a list is now an array of pointers to
_Tcl\_Obj_ structures.

Tcl programmers, for the most part, have not taken advantage of this
evolution.  Code that uses hash tables for the purpose is still
extremely common.  Moreover, it is difficult to update lists in place,
even if their internal representations are known not to be shared.
One example of this difficulty is seen in the discussions
<http://purl.org/thecliff/tcl/wiki/941>  of how best to shuffle a list
of items.  The discussion began with a naïve implementation of Jon
Bentley's method of performing random swaps:

	  proc shuffle1 { list } {
	      set n [llength $list]
	      for { set i 0 } { $i < $n } { incr i } {
	          set j [expr {int(rand()*$n)}]
	          set temp [lindex $list $j]
	          set list [lreplace $list $j $j [lindex $list $i]]
	          set list [lreplace $list $i $i $temp]

	      }
	      return $list

	  }

Aside from the fact that the syntax obscures what the program is
doing, the implementation suffers from an obscure performance problem.
When the _lreplace_ calls in the _shuffle1_ procedure are
executed, the internal representation of _list_ has two references:
the value of the variable, and the parameter passed to _lreplace_.
The multiple references force _lreplace_ to copy the list, leading
to quadratic performance when large lists are shuffled.

It is possible, albeit difficult, to alleviate this problem by careful
management of the lifetime of _Tcl\_Obj_ structures, but this change
complicates the code.  The simplest way to fix the performance is
probably to use Donal Fellows's implementation of the _K_
combinator:

	 proc K { x y } { set x }

which allows the caller of _lreplace_ to extract the value of
_list_, change the value of _list_ so that the extracted value is
unshared, and then pass the extracted value as a parameter to
_lreplace:_

	  proc shuffle1a { list } {
	      set n [llength $list]
	      for { set i 0 } { $i < $n } { incr i } {
	          set j [expr {int(rand()*$n)}]
	          set temp1 [lindex $list $j]
	          set temp2 [lindex $list $i]
	          set list [lreplace [K $list [set list {}]] $j $j $temp2]
	          set list [lreplace [K $list [set list {}]] $i $i $temp1]

	      }
	      return $list

	  }

Now the performance of the code is _O\(n\)_ where _n_ is the length
of the list, but the programmer's intent has been seriously obscured!

These drawbacks have led prominent individuals such as Richard
Stallman <http://www.vanderburg.org/Tcl/war/0000.html>  to assert that
Tcl lacks arrays.

_This proposal includes the absolute minimum of functionality needed
to provide array-style indexing for variables containing Tcl list
objects._  The reason for this limitation is that omitted
functionality can be added later without breaking existing scripts.
On the other hand, ill-considered extensions may turn into something
that we're doomed to support forever.

# Specification

This TIP's proposed change can be stated succinctly:

 > Wherever the notation _a\(x\)_ may be used to refer to an array
   element in the language, allow it also to refer to an element of a
   list, provided that the variable _a_ is scalar and the value
   _x_ is an index suitable for the _lindex_ command.

   _Exception:_ Traces, _unset_ and _upvar_ calls designating
   individual list elements shall not be supported.  \(As a consequence
   of this rule, list elements may also not appear as linked variables
   in C code, implying that they also cannot appear as _-variable_
   or _-textvariable_ options on Tk widgets.\)

Note that this change is backward compatible with existing Tcl
scripts!  If a notation like _a\(x\)_ is used to refer to a scalar
variable in today's Tcl, the result is an error:

	 % set a [list foo bar grill]
	 foo bar grill
	 % set a(2)
	 can't read "a(2)": variable isn't array
	 % puts $a(2)
	 can't read "a(2)": variable isn't array
	 % set a(2) zot
	 can't set "a(2)": variable isn't array

The default behavior, if _a_ is not set, and a script executes

	 set a(2) zot

will still be to create an associative array.  If a script wishes to
perform such actions on a list, it will be necessary first to
initialize the variable:

	 set a [list]
	 set a(0) foo

Note that in the example above, there is no requirement that the
internal representation of _a_ be a list; the line,

	 set a [list]

could have been replaced with

	 set a {}

with the only impact being the run-time cost of shimmering the empty
string into an empty list.  Nowhere does this proposal introduce
behavior that depends on a specific internal representation for any
variable.

This proposal the syntax of the subscript shall be precisely those
values that are accepted as the second argument to the _lindex_ command.
In other words, the subscript may be an integer _N_, or the string
_end_ or _end-N_.  The value of _N_ may not be less than zero
nor greater than nor equal to the length of the list on any usage that
reads a list element.  

A usage that writes a list element may use an integer equal to
 the length of the list, or the string _end\+1_, to designate
the element one past the end.  In other words,

	  set a(end+1) foo

will have the same effect as:

	  lappend a foo

With the proposed change in syntax, the procedure to shuffle a list
becomes much more straightforward:

	  proc shuffle1 { list } {
	      set n [llength $list]
	      for { set i 0 } { $i < $n } { incr i } {
	          set j [expr {int(rand()*$n)}]
	          set temp $list($j)
	          set list($j) $list($i)
	          set list($i) $temp

	      }
	      return $list

	  }

The given implementation copies the list only once, the first time
that the line:

	          set list($j) $list($i)

is executed.  Thereafter, the list is an unshared object, and the
replacements are performed in place.

It shall be illegal to pass a list element as the parameter to
_upvar;_ that is, the following usage:

	  proc increment { varName } {
	      upvar 1 $varName v
	      incr v

	  }
	  set x [list 1 2 3]
	  increment x(0)

will _not_ be supported.  However, the commoner form:

	  proc incrementElement { arrayName index } {
	      upvar 1 $arrayName array
	      incr array($index)

	  }
	  set x [list 1 2 3]
	  incrementElement x 0

will, of course, work as expected.

# Discussion

Several reviewers expressed concern about the reuse of array syntax.
In particular, the alternative syntax $a<$element> was proposed
repeatedly.  Alas, there is no good alternative syntax that will not
break at least some existing scripts.  The proposed syntax using
angle-brackets is a poor choice, because Tcl scripts that generate
Web pages frequently have code like:

	  puts "<$tag>$text</$tag>

that would be broken horribly by such a change.

There are several obvious extensions to the proposal that are not
addressed, and these omissions are intentional.

   * The proposal makes no attempt to deal with multiple subscripts
     as a means of accessing nested lists.

Use of multiple subscripts is closely related to the withdrawn [[22]](22.md)
\(which the author of this TIP intends to revive\).  If the related TIP
is accepted, the syntax for the subscript could readily be expanded
so that it could be a Tcl list giving the subscripts in lexicographic
sequence.  For example

	 set a(2 3) foo

could be used to set the fourth element of the third sublist.

   * The proposal allows the _set_ command \(or any other use of
     _Tcl\_SetVar2Ex_\) to set only the elements that are in the list
     already plus the one one beyond the end.

Tcl lists are fundamentally dense arrays.  Allowing non-contiguous
elements, that is, sparse arrays, is a fundamental change to their
semantics.  Such a change is not contemplated at this time.

   * The proposal does not allow the _unset_ command \(or any
     other command that arrives at _Tcl\_UnsetVar2_\) to delete members
     of a list.

Earlier versions of the proposal had proposed to permit:

	  unset a([expr { [llength $a] - 1}])

or equivalently:

	  unset a(end)

to reduce the length of the list by one.  In subsequent discussions,
the reviewers found it distasteful that the proposed syntax did not
permit unsetting interior elements of a list.  Alas, the discussion
did not arrive at a consensus on what the precise semantics of such
an operation ought to be.  Some reviewers favored attempting to emulate
sparse arrays \(again, a fundamental change to the semantics of
Tcl lists that is not contemplated at this time\).  Others preferred
the semantics of shifting the remaining elements, so that

	   unset a($n)

would always be equivalent to

	   set a [lreplace $a $n $n]

except for performance.  Both camps found it overly restrictive to
limit the semantics of _unset_ to those of the original proposal.
Because the two groups failed to achieve a consensus, the author of
this TIP finds it prudent to forbid _unset_ altogether in the
initial implementation.

   * The _array_ command continues to operate only on associative
     arrays.

Lists are a simple enough structure that the full power of the
_array_ command is not required to deal with them, and having it
work on lists as well as arrays seems like needless effort.  Moreover,
existing code may well depend on a combination of _[array exists]_
and _[info exists]_ to distinguish associative arrays from scalar
variables \(including lists\).

   * The _upvar_ command cannot address individual list elements.

Extending the syntax in this fashion would make _upvar_ more
consistent in its behavior, but appears to be expensive, in terms of
both performance \(tracking down the linked references if a list is
rebuilt\) and the effort required for implementation \(the author of
this TIP is unlikely to have the time required to implement the
necessary changes to _struct Var_ and the associated code\).

   * No traces on list elements shall be supported.  List elements
     cannot function as linked variables in C code.

The original proposal had specified how write and unset, but not read,
traces could be implemented.  The original proposed functionality is
described in the Appendix.  The author of this TIP had proposed it
primarily so that list elements could function as linked variables
\(for instance, in the _-variable_ and _-textvariable_ options
of Tk widgets\).

Once again, this part of the original proposal failed for lack of
consensus among the reviewers.  Some felt that supporting read traces
in one context but not another would be overly confusing.  Moreover,
the proposal as written would cause write traces on the elements to fire
if the internal representation of a variable shimmered between a list
and something else.  Some reviewers found the excess trace callbacks
to be objectionable.  

At least one reviewer proposed a separate _trace add element_ syntax
for list-element traces.  This syntax would address some of the
concerns about the lack of read traces \(there's no reason that _trace
add element_ should function the same as _trace add variable_\).
Alas, it would not address the problem of linked variables, which was
the main reason for having the traces in the first place.

Given the lack of consensus, the author of this TIP finds it prudent
to withdraw or postpone this portion of the proposal.

# See Also

[[22]](22.md) - withdrawn.

# Reference Implementation

No reference implementation has yet been developed; the author of this
TIP wishes to solicit the opinions of the Tcl community before
spending a lot of time implementing a possibly bad idea.

# Change history

_12 March 2001:_ Added detailed discussion of the specific subscript
ranges supported by read, write and unset operations.  Changed the discussion
to reject the alternative of padding an array when setting an index beyond
the end.  Added discussion of the details of write and unset traces, and
rejecting read traces as being infeasible to implement.  Clarified the
example of creating an empty list so as to avoid any misapprehension that
these changes depend on list variables' having a particular representation
at any given time; in fact, every detail of this proposal is tolerant of
shimmering.

_13 March 2001:_ Fixed a copy-and-paste error in the 'incrementElement'
example, and added to the discussion the fact that all operations will
throw errors in the event of a malformed list.

_30 March 2001:_ Revised yet again, in an attempt to remove as
much controversial functionality as possible and reduce the TIP to the
minimum useful subset, on the grounds that it is prudent to avoid
supporting functionality that may later prove ill-considered.

# Summary of objections

_DeJong,_ _English_ \(non-voting\), _Flynt_ \(non-voting\),
_Harrison,_ _Ingham,_ _Lehenbauer,_ _Polster,_ \(non-voting\),
_Porter,_ and _Sofer_ \(non-voting\), expressed concern that the
proposed syntax is confusing, since the target object could be either
an associative array or a linear array \(that is, a Tcl list\).
These objections varied in stridency from "yes, it is a risk, and
I'm prepared to accept it," to "this will just be too confusing, and I
can't countenance this proposal."

_Hobbs_ found the original proposal's omission of reverse indexing
distasteful.  The current version of the proposal embraces his
suggested change.

_Cuthbert_ \(non-voting\), _Hobbs_, and _Porter_ expressed concern
over the semantics of _unset._ Since consensus was not achieved, the
current version of the proposal defers implementation of _unset._

Several reviewers, most notably _Ousterhout,_ found the proposed
_trace_ semantics distasteful.  The current version of the proposal
eliminates _trace_ on list elements.

Several reviewers appeared to labor under the misconception that this
TIP introduces behavior that is dependent at run time upon the
internal representation of a Tcl object.  It does not; it is tolerant
of shimmering in all cases.

Several reviewers objected to the proposal on the grounds that it does
not specify a general object system and how such a system would allow
for generic containers with array syntax.  The author's intention in
writing it was not to propose such a system, but only to propose a
small piece of syntactic sugar, implementable here and now, that is
compatible with that broader vision.

# Appendix: Possible implementation of read and unset traces.

The original proposal contained the following language, which could
be used as a guide if traces on list elements are contemplated at a
future time.

Write and unset traces on list elements shall be supported; it shall
be permissible to write:

	    trace add variable x(1) write writeCallback

or

	    trace add variable x(1) unset unsetCallback

The _write_ callback shall be invoked whenever the given list
element changes value; the _unset_ callback shall be invoked
whenever the variable is unset or when its length shrinks to the point
that it no longer has a member with the given index.

Read traces on list elements shall _not_ be supported.  It is
too difficult at this point to define what their semantics should be.
For instance, if a program executes the following code:

	   trace add variable x(0) read readCallback
	   set x [list foo bar grill]
	   set y [string range $x 4 end]

should the callback fire?  By one argument, the program has not
read element zero of the list; by another, using the list as a string
has read every element, and all read traces should fire.  In any case,
the read trace on a variable fires before its usage is known; it appears
impossible in existing code to implement selective read tracing on list
elements.

The implementation of write and unset traces on list elements will be
done by establishing a C-level write trace on the variable as a whole.
The client data of the trace will designate a structure containing the
ordinal number of the element being traced, and a _Tcl\_Obj_ pointer
designating its old value.  The reference count of the _Tcl\_Obj_
will be incremented when this pointer is stored.  Note that this
increment operation makes the object shared.  Any change to the
designated element will thus need to copy the object.

When the write trace fires, the list representation of the variable
will be extracted, reconstituting it from the string representation if
necessary.  If extracting the list representation fails, the trace
will be considered to have failed as well, and the trace callback will
return _TCL\_ERROR_.  If extracting the list representation succeeds,
the list length will be compared with the ordinal number of the
element being traced.  If the element number is no longer within the
list, an unset trace fires if one exists.  If the element number is
within the list, the two _Tcl\_Obj_ pointers are compared.  If they
are identical, the list element in question is unchanged, and nothing
need be done.  Otherwise, the write trace fires.  

This behavior is conservative in that an operation that spoils the
list representation of the object is considered to have written every
element of the list.  This rule is consistent with the rule that write
traces on ordinary Tcl variables fire whenever the variable is set,
even if it is being set to an identical value.

In any event, after the conclusion of a trace callback, the saved
Tcl\_Obj will have its reference count decremented and be replaced with
the current element of the list \(with reference count appropriately
incremented, of course\).

# Copyright

This document has been placed in the public domain.

Name change from tip/290.tip to tip/290.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
136
137
138

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

159
160
161
162
163
164
165
166



167
168
169
170
171
172
173
174
175
176
177
178
179

TIP:            290
Title:          Registration of Custom Error Handler Scripts
Version:        $Revision: 1.13 $
Author:         Eckhard Lehmann <[email protected]>
Author:         Larry W. Virden <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        29-Oct-2006
Post-History:   
Keywords:       Tcl,error,trap
Tcl-Version:    8.7


~ Abstract

This TIP proposes the possibility to register a custom command as error and exception handler.

~ Rationale

Errors are thrown in the Tcl interpreter through the '''error''' command or
from a C extension that returns TCL_ERROR. When an error is thrown, the global
''errorInfo'' variable is filled with rudimentary stacktrace information and
the error message itself. The global ''errorCode'' variable can contain an
error code if this is provided by the command that has thrown the error.

Errors can be caught with the '''catch''' command. In this case, the
''errorInfo'' variable is still filled with the information mentioned above,
but the error is not presented to the interpreter. If the error is not caught,
it is presented to the interpreter and the execution of the current code is
aborted immediately

The information in ''errorInfo'' is, in some simple cases, useful for
reproducing and tracking down the error source and fixing the problem. In more
complicated cases however, ''errorInfo'' does not include enough information to
successfully reproduce the error - information about the application's state is missing.

In other languages such as LISP, this problem is addressed by
stopping the execution at the position where the error was thrown (preserving the current callframe) and presenting the developer with a console that
enables him to introspect the running program. Although Tcl has very good
introspection capabilities, it is not possible to use them in an error case,
because the execution just aborts and the stacktrace is unwound at once. For
errors generated with the '''error''' command, it is possible to overwrite
this command and provide more advanced functionality, but this is not
possible if errors are generated in C code by ''return TCL_ERROR''.

The proposed implementation addresses this problem by a custom error command
that is executed whenever an error occurs in the execution of Tcl code. This
opens a range of implementation possibilities for error handling, for
instance:

    * registering a ''breakpoint'' command that stops execution at the error
      position and opens a console for introspection

    * registering a more advanced (Tk) debugger that opens on error for
      introspection.

    * registering a command that captures the state of each call-frame up to
      the one where the error was thrown and writes that state to a file. This
      file can later be debugged (with an appropriate tool).

~ Alternatives

 1. Overwriting of the '''error''' command
As stated abovem, this works only for errors generated from Tcl code, whereas it does not work for errors from C extensions.

 2. Leavestep execution traces
In Tcl >=8.4 it is possible to register execution traces on ''leavestep'' to commands. To implement part of the proposed functionality it would be possible to add a leavestep trace procedure, which - after each command - checks for the return code and acts accordingly. The problem with this approach is, that the procedure is called after ''each'' command, independent from whether it returned an error or not. This can slow down the program execution more or less significantly. Furthermore, it is not easy if at all possible to capture occurences of '''catch''' by this way, so it is complicated or impossible to react on caught errors.

It might be possible to get part or most of the proposed functionality by ''trace add execution leavestep'' or overwriting of '''error'''. But it is the responsibility of the core language (even more when it is a dynamic language) to provide customizable and advanced error handling. The TIP proposes in this direction.

~ Specification

The implementation consists of two parts: a registration command for the custom command and a place where the handler is called. For this to work, there are some minor changes necessary to the Tcl execution engine and to the Interp structure. For running the handler on caught and or uncaught errors (depending on how the user wants to have it) it is necessary to capture the current level of "catch"es that occure during execution.

The registration command is responsible for:

    * register the command for caught and/or uncaught exceptions

    * retrieve the currently registered command

    * change the execution details (caught and/or uncaught errors) and the command

    * unregister the command and thus get back to the current behaviour in error cases

Since the functionality is very similar to the family of '''trace''' commands, the proposed registration command is an extension to trace:

'''trace set exception ?-caught? ?-uncaught? ?command?''': Registration and modification

The arguments ''-caught'' and/or ''-uncaught'' to ''trace set exception'' modify the run conditions for the currently registered handler (run on caught/uncaught errors). With the ''command'' argument, this is set as the new handler. The return code and result of the command that was executing is appended to the registered ''command''. So, the real call is: ''command code result''.

'''trace info exception''': Information about the current handler

This command returns a list with the elements {-caught y/n -uncaught y/n script}, where caught and uncaught flags are specified and script is the currently registered handler.

'''trace unset exception''': Remove registerred handler

Any previously set error handler is unregistered.

The ''command'' that is registered will quell the error if it returns normal (return code 0). If the script returns abnormal, it's return code is returned to the interpreter. Errors inside the handler are not trapped by the script again, rather they are presented to the interpreter as usual - otherwise this would result in an endless loop.

The changes in the execution engine should be done so that:

    * existing functionality is not disturbed

    * the call frame is preserved after the error occured - thus the custom command is run in the same level as where the error was thrown

    * the ''::errorInfo'' and ''::errorCode'' variables are updated to contain the error information '''that is available in the current callframe'''. This information must be updated before the custom command is run, so that it is accessible from there.

The innermost function that is called on Tcl code execution is ''TclEvalObjvInternal()''. It is called from others to execute a command and returns the code that the executed command returned. It's the best place to trigger the error handler execution, but whether errors are catched (catchLevel) must be present at this time. Therefore, this level is stored in the current Interp* from within the callers of ''TclEvalObjvInternal()''. The catch level can be determined either from ''TclExecuteByteCode()'' or from ''Tcl_CatchObjCmd()'' directly.

The errorInfo and errorCode variables are set directly before the handler is run. This ensures that they are updated properly. Eventually registerred traces on this variable are handled as usual, before the custom error command is executed.

~ Reference Implementation

A reference implementation is available from sourceforge as a patch against Tcl 8.5a5 [http://sourceforge.net/support/tracker.php?aid=1587317].

~ Usage Example

Here is a sample procedure that can be used to stop execution on error (return code 1) and
introspect the program using stdin/stdout. Other return codes are returned together with the previous result. The procedure was mainly implemented by Neil Madden as '''debug-repl''' and is available (with a short discussion on the topic) on 
[http://lambda-the-ultimate.org/node/1544#comment-18446]:

|package provide debug 1.0
|
|proc up {} {
|    uplevel 2 {
|        breakpoint
|    }
|}


|
|proc down {} {
|    return -code continue
|}

|
|proc breakpoint {code result} {
|    if {$code > 1} {
|        return -code $code $result
|    }

|    set cmd ""
|    set level [expr {[info level]-1}]
|    set prompt "Debug ($level) % "
|    while {1} {
|        puts -nonewline $prompt
|        flush stdout
|        gets stdin line
|        append cmd $line\n
|        if {[info complete $cmd]} {
|            set code [catch {uplevel #$level $cmd} result]
|            if {$code == 0 && [string length $result]} {
|                puts stdout $result
|            } elseif {$code == 3} {
|                break
|            } elseif {$code == 4} {
|                # continue
|                return
|            } else {
|                puts stderr $result
|            }

|            set prompt "Debug ($level) % "
|            set cmd ""
|        } else {
|            set prompt "    "
|        }
|    }
|}




To use it for uncaught errors, the ''breakpoint'' procedure can be registered
as error command:

|package re debug
|trace set exception -uncaught breakpoint

When an error raises, ''breakpoint'' is called in the current callframe and
Tcl introspection commands like '''info vars''' etc. can be used to get
information about the program state.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|



|

|
|
|
|


|
|




|

|



|



|

|






|


|




|

|

|



|

|

|

|







|



|

|

|

|

|

|



|







|

|



|

|

|

|
|
|

|
|
|
|
|
<
<
>
>
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
<
<
|
>
>
>
|


|
|

|
|


|


>

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
136

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

157
158
159
160
161



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179

# TIP 290: Registration of Custom Error Handler Scripts

	Author:         Eckhard Lehmann <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        29-Oct-2006
	Post-History:   
	Keywords:       Tcl,error,trap
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes the possibility to register a custom command as error and exception handler.

# Rationale

Errors are thrown in the Tcl interpreter through the **error** command or
from a C extension that returns TCL\_ERROR. When an error is thrown, the global
_errorInfo_ variable is filled with rudimentary stacktrace information and
the error message itself. The global _errorCode_ variable can contain an
error code if this is provided by the command that has thrown the error.

Errors can be caught with the **catch** command. In this case, the
_errorInfo_ variable is still filled with the information mentioned above,
but the error is not presented to the interpreter. If the error is not caught,
it is presented to the interpreter and the execution of the current code is
aborted immediately

The information in _errorInfo_ is, in some simple cases, useful for
reproducing and tracking down the error source and fixing the problem. In more
complicated cases however, _errorInfo_ does not include enough information to
successfully reproduce the error - information about the application's state is missing.

In other languages such as LISP, this problem is addressed by
stopping the execution at the position where the error was thrown \(preserving the current callframe\) and presenting the developer with a console that
enables him to introspect the running program. Although Tcl has very good
introspection capabilities, it is not possible to use them in an error case,
because the execution just aborts and the stacktrace is unwound at once. For
errors generated with the **error** command, it is possible to overwrite
this command and provide more advanced functionality, but this is not
possible if errors are generated in C code by _return TCL\_ERROR_.

The proposed implementation addresses this problem by a custom error command
that is executed whenever an error occurs in the execution of Tcl code. This
opens a range of implementation possibilities for error handling, for
instance:

    * registering a _breakpoint_ command that stops execution at the error
      position and opens a console for introspection

    * registering a more advanced \(Tk\) debugger that opens on error for
      introspection.

    * registering a command that captures the state of each call-frame up to
      the one where the error was thrown and writes that state to a file. This
      file can later be debugged \(with an appropriate tool\).

# Alternatives

 1. Overwriting of the **error** command
As stated abovem, this works only for errors generated from Tcl code, whereas it does not work for errors from C extensions.

 2. Leavestep execution traces
In Tcl >=8.4 it is possible to register execution traces on _leavestep_ to commands. To implement part of the proposed functionality it would be possible to add a leavestep trace procedure, which - after each command - checks for the return code and acts accordingly. The problem with this approach is, that the procedure is called after _each_ command, independent from whether it returned an error or not. This can slow down the program execution more or less significantly. Furthermore, it is not easy if at all possible to capture occurences of **catch** by this way, so it is complicated or impossible to react on caught errors.

It might be possible to get part or most of the proposed functionality by _trace add execution leavestep_ or overwriting of **error**. But it is the responsibility of the core language \(even more when it is a dynamic language\) to provide customizable and advanced error handling. The TIP proposes in this direction.

# Specification

The implementation consists of two parts: a registration command for the custom command and a place where the handler is called. For this to work, there are some minor changes necessary to the Tcl execution engine and to the Interp structure. For running the handler on caught and or uncaught errors \(depending on how the user wants to have it\) it is necessary to capture the current level of "catch"es that occure during execution.

The registration command is responsible for:

    * register the command for caught and/or uncaught exceptions

    * retrieve the currently registered command

    * change the execution details \(caught and/or uncaught errors\) and the command

    * unregister the command and thus get back to the current behaviour in error cases

Since the functionality is very similar to the family of **trace** commands, the proposed registration command is an extension to trace:

**trace set exception ?-caught? ?-uncaught? ?command?**: Registration and modification

The arguments _-caught_ and/or _-uncaught_ to _trace set exception_ modify the run conditions for the currently registered handler \(run on caught/uncaught errors\). With the _command_ argument, this is set as the new handler. The return code and result of the command that was executing is appended to the registered _command_. So, the real call is: _command code result_.

**trace info exception**: Information about the current handler

This command returns a list with the elements \{-caught y/n -uncaught y/n script\}, where caught and uncaught flags are specified and script is the currently registered handler.

**trace unset exception**: Remove registerred handler

Any previously set error handler is unregistered.

The _command_ that is registered will quell the error if it returns normal \(return code 0\). If the script returns abnormal, it's return code is returned to the interpreter. Errors inside the handler are not trapped by the script again, rather they are presented to the interpreter as usual - otherwise this would result in an endless loop.

The changes in the execution engine should be done so that:

    * existing functionality is not disturbed

    * the call frame is preserved after the error occured - thus the custom command is run in the same level as where the error was thrown

    * the _::errorInfo_ and _::errorCode_ variables are updated to contain the error information **that is available in the current callframe**. This information must be updated before the custom command is run, so that it is accessible from there.

The innermost function that is called on Tcl code execution is _TclEvalObjvInternal\(\)_. It is called from others to execute a command and returns the code that the executed command returned. It's the best place to trigger the error handler execution, but whether errors are catched \(catchLevel\) must be present at this time. Therefore, this level is stored in the current Interp\* from within the callers of _TclEvalObjvInternal\(\)_. The catch level can be determined either from _TclExecuteByteCode\(\)_ or from _Tcl\_CatchObjCmd\(\)_ directly.

The errorInfo and errorCode variables are set directly before the handler is run. This ensures that they are updated properly. Eventually registerred traces on this variable are handled as usual, before the custom error command is executed.

# Reference Implementation

A reference implementation is available from sourceforge as a patch against Tcl 8.5a5 <http://sourceforge.net/support/tracker.php?aid=1587317> .

# Usage Example

Here is a sample procedure that can be used to stop execution on error \(return code 1\) and
introspect the program using stdin/stdout. Other return codes are returned together with the previous result. The procedure was mainly implemented by Neil Madden as **debug-repl** and is available \(with a short discussion on the topic\) on 
<http://lambda-the-ultimate.org/node/1544#comment-18446> :

	package provide debug 1.0
	
	proc up {} {
	    uplevel 2 {
	        breakpoint


	    }
	}
	
	proc down {} {
	    return -code continue

	}
	
	proc breakpoint {code result} {
	    if {$code > 1} {
	        return -code $code $result

	    }
	    set cmd ""
	    set level [expr {[info level]-1}]
	    set prompt "Debug ($level) % "
	    while {1} {
	        puts -nonewline $prompt
	        flush stdout
	        gets stdin line
	        append cmd $line\n
	        if {[info complete $cmd]} {
	            set code [catch {uplevel #$level $cmd} result]
	            if {$code == 0 && [string length $result]} {
	                puts stdout $result
	            } elseif {$code == 3} {
	                break
	            } elseif {$code == 4} {
	                # continue
	                return
	            } else {
	                puts stderr $result

	            }
	            set prompt "Debug ($level) % "
	            set cmd ""
	        } else {
	            set prompt "    "



	        }
	    }
	}

To use it for uncaught errors, the _breakpoint_ procedure can be registered
as error command:

	package re debug
	trace set exception -uncaught breakpoint

When an error raises, _breakpoint_ is called in the current callframe and
Tcl introspection commands like **info vars** etc. can be used to get
information about the program state.

# Copyright

This document has been placed in the public domain.

Name change from tip/291.tip to tip/291.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

TIP:            291
Title:          Add the 'platform' Package to Tcl
Version:        $Revision: 1.9 $
Author:         Steve Landers <[email protected]>
Author:         Andreas Kupries <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        26-Oct-2006
Post-History:   
Keywords:       Tcl,Critcl,TEApot
Tcl-Version:    8.5


~ Abstract

This TIP proposes adding the '''platform''' package to the Tcl core sources
and to install it automatically, similar to what is currently done with the
'''tcltest''' package.

~ Rationale

It has been shown by the current users of the '''platform''' package - the
'''Critcl''' (C Runtime in Tcl) and the '''TEApot''' repository system - that
it is useful to not only be able to identify the architecture of a machine
running Tcl, but to condense this information into a single identifier,
standardized across platforms.

Whilst Tcl provides the ''tcl_platform'' array for identifying the current
architecture (in particular, the platform and machine elements) this is not
always sufficient. This is because (on Unix machines) ''tcl_platform''
reflects the values returned by the '''uname''' command and these aren't
standardized across platforms and architectures. In addition, on at least one
platform (AIX) the ''tcl_platform(machine)'' contains the CPU serial number.

Consequently, individual applications need to manipulate the values in
''tcl_platform'' (along with the output of system specific utilities) - which
is both inconvenient for developers, and introduces the potential for
inconsistencies in identifying architectures and in naming conventions.

Placing the '''platform''' package into the core in the same manner as
'''tcltest''' will prevent such fragmentation - i.e., it will establish a
standard naming convention for architectures running Tcl - and will make it
more convenient for developers to identify the current architecture a Tcl
program is running on.

~ Specification of the proposed Change

~~ Tcl Level API

Two new packages, '''platform''' and '''platform::shell''' are made available,
and can be loaded into Tcl via '''package require'''.

The package '''platform''' provides three commands:

 1. '''::platform::identify'''

  > This command returns an identifier describing the platform the Tcl core is
    running on.

 1. '''::platform::generic'''

  > This command returns a simplified identifier, leaving out details like
    kernel version, libc version, etc.

 1. '''::platform::patterns''' ''id''

  > This command takes an identifier as returned by '''::platform::identify'''
    and returns a list of identifiers for compatible architectures.

All identifiers have the general format ''OS''-''CPU''. The CPU part will not
contain dashes anymore, whereas the OS part may contain dashes.

The package '''platform::shell''' provides three commands as well, two of
which are wrappers around commands provided by '''platform'''.

 1. '''::platform::shell::generic'''  ''shell''

  > This command returns the generic identification of the specified ''shell''.
    The shell has to be executable on the host machine, but does not have to
    have the package '''platform''' itself. This is supplied by the caller.

 1. '''::platform::shell::identify''' ''shell''

  > This command returns the exact identification of the specified ''shell''.
    The shell has to be executable on the host machine, but does not have to
    have the package '''platform''' itself. This is supplied by the caller.

 1. '''::platform::shell::platform''' ''shell''

  > This command returns the contents of ''tcl_platform(platform)'' for the
    specified ''shell''. The shell has to be executable on the host machine.

~~ Public C API

One deficiency in the current implementation of the package ''platform'' is
the difficulty of distinguishing 64bit and 32bit systems. To remove this
deficiency the variable ''tcl_platform'' of the Tcl core is extended to
contain an entry ''pointerSize''. The value associated with this entry is the
number of bytes needed by the machine to store a ''void *'' pointer.

~ Discussion

When choosing the format for platform identifiers we had two contenders, i.e. ''OS''-''CPU'' vs. ''CPU''-''OS'', the second of which is used by GCC. However for developers using a scripting language like Tcl the OS is of more importance than the CPU architecture. Because of this the first form was chosen.

~ Reference Implementation

This is available on SourceForge [http://sourceforge.net/support/tracker.php?aid=1600701].

~ Copyright

This document has been placed in the public domain.

Please note that any correspondence to the author concerning this TIP is
considered in the public domain unless otherwise specifically requested by the
individual(s) authoring said correspondence. This is to allow information
about the TIP to be placed in a public forum for discussion.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|

|

|

|
|




|
|
|
|

|


|



|
|




|

|

|
|

|

|

|


|

|


|

|


|


|
|

|

|

|

|

|

|

|

|
|

|

|

|
|
|

|

|

|

|

|





|

>

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

# TIP 291: Add the 'platform' Package to Tcl

	Author:         Steve Landers <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        26-Oct-2006
	Post-History:   
	Keywords:       Tcl,Critcl,TEApot
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes adding the **platform** package to the Tcl core sources
and to install it automatically, similar to what is currently done with the
**tcltest** package.

# Rationale

It has been shown by the current users of the **platform** package - the
**Critcl** \(C Runtime in Tcl\) and the **TEApot** repository system - that
it is useful to not only be able to identify the architecture of a machine
running Tcl, but to condense this information into a single identifier,
standardized across platforms.

Whilst Tcl provides the _tcl\_platform_ array for identifying the current
architecture \(in particular, the platform and machine elements\) this is not
always sufficient. This is because \(on Unix machines\) _tcl\_platform_
reflects the values returned by the **uname** command and these aren't
standardized across platforms and architectures. In addition, on at least one
platform \(AIX\) the _tcl\_platform\(machine\)_ contains the CPU serial number.

Consequently, individual applications need to manipulate the values in
_tcl\_platform_ \(along with the output of system specific utilities\) - which
is both inconvenient for developers, and introduces the potential for
inconsistencies in identifying architectures and in naming conventions.

Placing the **platform** package into the core in the same manner as
**tcltest** will prevent such fragmentation - i.e., it will establish a
standard naming convention for architectures running Tcl - and will make it
more convenient for developers to identify the current architecture a Tcl
program is running on.

# Specification of the proposed Change

## Tcl Level API

Two new packages, **platform** and **platform::shell** are made available,
and can be loaded into Tcl via **package require**.

The package **platform** provides three commands:

 1. **::platform::identify**

	  > This command returns an identifier describing the platform the Tcl core is
    running on.

 1. **::platform::generic**

	  > This command returns a simplified identifier, leaving out details like
    kernel version, libc version, etc.

 1. **::platform::patterns** _id_

	  > This command takes an identifier as returned by **::platform::identify**
    and returns a list of identifiers for compatible architectures.

All identifiers have the general format _OS_-_CPU_. The CPU part will not
contain dashes anymore, whereas the OS part may contain dashes.

The package **platform::shell** provides three commands as well, two of
which are wrappers around commands provided by **platform**.

 1. **::platform::shell::generic**  _shell_

	  > This command returns the generic identification of the specified _shell_.
    The shell has to be executable on the host machine, but does not have to
    have the package **platform** itself. This is supplied by the caller.

 1. **::platform::shell::identify** _shell_

	  > This command returns the exact identification of the specified _shell_.
    The shell has to be executable on the host machine, but does not have to
    have the package **platform** itself. This is supplied by the caller.

 1. **::platform::shell::platform** _shell_

	  > This command returns the contents of _tcl\_platform\(platform\)_ for the
    specified _shell_. The shell has to be executable on the host machine.

## Public C API

One deficiency in the current implementation of the package _platform_ is
the difficulty of distinguishing 64bit and 32bit systems. To remove this
deficiency the variable _tcl\_platform_ of the Tcl core is extended to
contain an entry _pointerSize_. The value associated with this entry is the
number of bytes needed by the machine to store a _void \*_ pointer.

# Discussion

When choosing the format for platform identifiers we had two contenders, i.e. _OS_-_CPU_ vs. _CPU_-_OS_, the second of which is used by GCC. However for developers using a scripting language like Tcl the OS is of more importance than the CPU architecture. Because of this the first form was chosen.

# Reference Implementation

This is available on SourceForge <http://sourceforge.net/support/tracker.php?aid=1600701> .

# Copyright

This document has been placed in the public domain.

Please note that any correspondence to the author concerning this TIP is
considered in the public domain unless otherwise specifically requested by the
individual\(s\) authoring said correspondence. This is to allow information
about the TIP to be placed in a public forum for discussion.

Name change from tip/292.tip to tip/292.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

TIP:		292
Title:		Allow Unquoted Strings in Expressions
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Post-History:	
Version:	$Revision: 1.3 $
Author:		Brian Griffin <[email protected]>
Created:	01-Nov-2006
Keywords:	Tcl, expr


~ Abstract

This TIP proposes allowing unquoted words to be recognized as strings in
expressions ('''expr''', '''if''', '''while''').

~ Rationale

Currently the following fails with a syntax error:

|    set foo bar
|    expr {$foo eq bar}

This seems antithetical to the EIAS Tao of Tcl. The '''set''' command does not
require the quotes, so why should '''expr''', especially since the operands of
the '''eq''' and '''ne''' operators are treated as strings. It also seems
reasonable for the '''==''' and '''!=''' operators to reject unquoted strings
as not a valid operand. This provides some enforcement for numerical vs.
string comparison by forcing the use of quotes to convert the numeric '''=='''
to a string equality test.

The rationale for making such a change is it will make complex code a bit
easier to read.  For example, I can:

|        set var ENUM_VALUE_ONE
|
|        switch $var {
|                ENUM_VALUE_ZERO { ... }
|                ENUM_VALUE_ONE  { ... }
|                default { ... }
|        }

|
|        if {[lsearch $supplied_values ENUM_VALUE_ONE] >= 0} { ... }
|
|        if {[string equals $var ENUM_VALUE_ONE]} { ... }

but I must:

|        if {$var eq "ENUM_VALUE_ONE"} { ... }

which could lead someone reading the code to incorrectly conclude that
ENUM_VALUE_ONE is not the same thing as "ENUM_VALUE_ONE" or miss the fact that
they are the same, especially when using a syntax highlighting editor.

~ Proposed Change

Change the expression parser to accept unquoted words that are not function
names as strings. Modify ''EqualityExpr'' to reject unqoted strings for
"'''=='''", but allow them for "'''eq'''".

~ Draft Implementation

None, at the moment.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|


|

|



|
|

|
|
|
|

|





|
|
|
|
|
|
<
>
|
|
|
|



|


|


|


|
|

|



|


>

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

# TIP 292: Allow Unquoted Strings in Expressions
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Post-History:	

	Author:		Brian Griffin <[email protected]>
	Created:	01-Nov-2006
	Keywords:	Tcl, expr
-----

# Abstract

This TIP proposes allowing unquoted words to be recognized as strings in
expressions \(**expr**, **if**, **while**\).

# Rationale

Currently the following fails with a syntax error:

	    set foo bar
	    expr {$foo eq bar}

This seems antithetical to the EIAS Tao of Tcl. The **set** command does not
require the quotes, so why should **expr**, especially since the operands of
the **eq** and **ne** operators are treated as strings. It also seems
reasonable for the **==** and **!=** operators to reject unquoted strings
as not a valid operand. This provides some enforcement for numerical vs.
string comparison by forcing the use of quotes to convert the numeric **==**
to a string equality test.

The rationale for making such a change is it will make complex code a bit
easier to read.  For example, I can:

	        set var ENUM_VALUE_ONE
	
	        switch $var {
	                ENUM_VALUE_ZERO { ... }
	                ENUM_VALUE_ONE  { ... }
	                default { ... }

	        }
	
	        if {[lsearch $supplied_values ENUM_VALUE_ONE] >= 0} { ... }
	
	        if {[string equals $var ENUM_VALUE_ONE]} { ... }

but I must:

	        if {$var eq "ENUM_VALUE_ONE"} { ... }

which could lead someone reading the code to incorrectly conclude that
ENUM\_VALUE\_ONE is not the same thing as "ENUM\_VALUE\_ONE" or miss the fact that
they are the same, especially when using a syntax highlighting editor.

# Proposed Change

Change the expression parser to accept unquoted words that are not function
names as strings. Modify _EqualityExpr_ to reject unqoted strings for
"**==**", but allow them for "**eq**".

# Draft Implementation

None, at the moment.

# Copyright

This document has been placed in the public domain.

Name change from tip/293.tip to tip/293.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

TIP:		293
Title:		Argument Expansion with Leading {*}
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Post-History:	
Version:	$Revision: 1.4 $
Author:		Miguel Sofer <[email protected]>
Created:	02-Nov-2006
Obsoletes:	157


~ Abstract

Tcl shall use '''{*}''' to denote argument expansion, replacing the current
'''{expand}'''.

~ Rationale

There seems to be a consensus that the functionality of '''{expand}''' is
exactly what was needed, but the syntax could be nicer. The problem, both back
in 2003 and today, is that there is no general agreement on which is the best
one. However, the issue of ugliness is regularly revived in the mailing lists
so it is not going away soon. Moreover, an alpha release in a popular
distribution allows the use of '''{}''' instead of '''{expand}'''.

A compromise solution, '''{*}''', is less verbose and "ugly" than
'''{expand}''', and less prone to typographical errors than plain '''{}'''.
It is inspired using the mnemonic that the character "*" is already used to
denote "all items" in other contexts.

~ Detailed Proposal

After two years experience with '''{expand}''', this TIP proposes the
following amendment to [157]:

 1. The officially sanctioned expansion syntax will henceforth be '''{*}''',
    in replacement of the previous '''{expand}'''.

 2. The usage of both '''{expand}''' and '''{}''' will be deprecated.

 3. This is a syntax-only change.

~ Compatibility

Note that this TIP removes '''{expand}''' and '''{}''' as prefix-syntax, which
will break code that users might already have in production based off earlier
alpha release of 8.5.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|

|
|

|

|




|

|
|
|


|

|
|

|
|

|



|

|



|


>

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

# TIP 293: Argument Expansion with Leading {*}
	State:		Final
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Done
	Post-History:	

	Author:		Miguel Sofer <[email protected]>
	Created:	02-Nov-2006
	Obsoletes:	157
-----

# Abstract

Tcl shall use **\{\*\}** to denote argument expansion, replacing the current
**\{expand\}**.

# Rationale

There seems to be a consensus that the functionality of **\{expand\}** is
exactly what was needed, but the syntax could be nicer. The problem, both back
in 2003 and today, is that there is no general agreement on which is the best
one. However, the issue of ugliness is regularly revived in the mailing lists
so it is not going away soon. Moreover, an alpha release in a popular
distribution allows the use of **\{\}** instead of **\{expand\}**.

A compromise solution, **\{\*\}**, is less verbose and "ugly" than
**\{expand\}**, and less prone to typographical errors than plain **\{\}**.
It is inspired using the mnemonic that the character "\*" is already used to
denote "all items" in other contexts.

# Detailed Proposal

After two years experience with **\{expand\}**, this TIP proposes the
following amendment to [[157]](157.md):

 1. The officially sanctioned expansion syntax will henceforth be **\{\*\}**,
    in replacement of the previous **\{expand\}**.

 2. The usage of both **\{expand\}** and **\{\}** will be deprecated.

 3. This is a syntax-only change.

# Compatibility

Note that this TIP removes **\{expand\}** and **\{\}** as prefix-syntax, which
will break code that users might already have in production based off earlier
alpha release of 8.5.

# Copyright

This document has been placed in the public domain.

Name change from tip/294.tip to tip/294.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

TIP:            294
Title:          The "entier" Function: It's Spelt "entire"
Version:        $Revision: 1.4 $
Author:         Lars Hellstr�m <[email protected]>
Author:         Richard Suchenwirth <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        03-Nov-2006
Post-History:   
Keywords:       Tcl,number,cast,rename
Tcl-Version:    8.5


~ Abstract

It is proposed that the '''expr''' function '''entier'''() introduced by [237]
is renamed to '''entire'''().

~ Rationale

This appears to be a typo. Even though American English differs from British
English in that many words which in the latter end in "-re" are spelt "-er",
this is not one of these. Neither ''Merriam-Webster Online'' nor
''dictionary.com'' recognises "entier", whereas both list "entire". A Google
search for "entier" reports 61400000 pages, but if one narrows it down to
pages in English the count drops to 943000, and even then most of these are in
fact written in French. Within the first 60 matches, only 3 show "entier"
occurring in English text, and in all these cases it is part of a
trademark/product name.

Googling for "entier function" shows however that it is a concept discussed in
English texts. entier() was one of the standard functions in Algol 60.

~ Alternatives

While the term "entire" meaning "whole" is known in mathematics, it is rarely
applied to numbers. The typical thing to be entire is instead a function
[http://planetmath.org/encyclopedia/Entire.html], and that is quite unrelated
to integers. Better names could be:

 * '''whole''' ("whole number" sounds a bit childish, but unlike "entire
   number", it would probably be recognised as meaning "integer")

 * '''integer''' (this is the proper name for the concept in question)

It could also be argued that the function is rather silly, since "coercing to
integer" (which seems to be the same as truncation, i.e., rounding towards
zero) is mathematically a rather useless operation. More useful operations are
rounding to the nearest integer (available as round), floor (rounding
downwards), and ceiling (rounding upwards), since these admit tight
inequalities that do not depend on the sign of the number.  Currently the two
latter have to be had by combining '''round''' and '''floor'''/'''ceil''',
whereas separate functions '''ifloor''' and '''iceil''' would have been more
appropriate. Getting them would however require actually implementing
something new.

~ Implementation

This TIP can be implemented by applying the following command prefix to the
contents of the files of the Tcl source tree:

| string map {entier entire Entier Entire}

(It may of course be more convenient to use the search and replace
functionality of a text editor.) Grepping indicates that the only C file
affected would be ''generic/tclBasic.c''', the only Tcl files affected would
be ''tests/expr.test'' and ''tests/info.test'', and the only documentation
file affected would be ''doc/mathfunc.n''.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|
|

|



|
|







|

|



|


|
|

|


|
|
|
|

|
|



|




|

|
|
|
|
|

|


>

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

# TIP 294: The "entier" Function: It's Spelt "entire"

	Author:         Lars Hellström <[email protected]>
	Author:         Richard Suchenwirth <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        03-Nov-2006
	Post-History:   
	Keywords:       Tcl,number,cast,rename
	Tcl-Version:    8.5
-----

# Abstract

It is proposed that the **expr** function **entier**\(\) introduced by [[237]](237.md)
is renamed to **entire**\(\).

# Rationale

This appears to be a typo. Even though American English differs from British
English in that many words which in the latter end in "-re" are spelt "-er",
this is not one of these. Neither _Merriam-Webster Online_ nor
_dictionary.com_ recognises "entier", whereas both list "entire". A Google
search for "entier" reports 61400000 pages, but if one narrows it down to
pages in English the count drops to 943000, and even then most of these are in
fact written in French. Within the first 60 matches, only 3 show "entier"
occurring in English text, and in all these cases it is part of a
trademark/product name.

Googling for "entier function" shows however that it is a concept discussed in
English texts. entier\(\) was one of the standard functions in Algol 60.

# Alternatives

While the term "entire" meaning "whole" is known in mathematics, it is rarely
applied to numbers. The typical thing to be entire is instead a function
<http://planetmath.org/encyclopedia/Entire.html> , and that is quite unrelated
to integers. Better names could be:

 * **whole** \("whole number" sounds a bit childish, but unlike "entire
   number", it would probably be recognised as meaning "integer"\)

 * **integer** \(this is the proper name for the concept in question\)

It could also be argued that the function is rather silly, since "coercing to
integer" \(which seems to be the same as truncation, i.e., rounding towards
zero\) is mathematically a rather useless operation. More useful operations are
rounding to the nearest integer \(available as round\), floor \(rounding
downwards\), and ceiling \(rounding upwards\), since these admit tight
inequalities that do not depend on the sign of the number.  Currently the two
latter have to be had by combining **round** and **floor**/**ceil**,
whereas separate functions **ifloor** and **iceil** would have been more
appropriate. Getting them would however require actually implementing
something new.

# Implementation

This TIP can be implemented by applying the following command prefix to the
contents of the files of the Tcl source tree:

	 string map {entier entire Entier Entire}

\(It may of course be more convenient to use the search and replace
functionality of a text editor.\) Grepping indicates that the only C file
affected would be _generic/tclBasic.c**, the only Tcl files affected would
be _tests/expr.test_ and _tests/info.test_, and the only documentation
file affected would be _doc/mathfunc.n_.

# Copyright

This document has been placed in the public domain.

Name change from tip/295.tip to tip/295.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

TIP:            295
Title:          Enhance Arguments to lrange
Version:        $Revision: 1.7 $
Author:         Andreas Leitgeb <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        06-Nov-2006
Post-History:   
Keywords:       Tcl,lrange
Tcl-Version:    8.7


~ Abstract

This TIP proposes an enhancement to '''lrange''' and '''string range''' that lets them take more than one start-end index pair.

~ Rationale

Sometimes you need to extract a non-continuous selection of elements from some
list and build a new list from them. This requires the use of multiple calls
to '''lrange''' and a surrounding '''concat''' to build the final list.
However, since the following fails with a syntax error:

|    lrange {a b c d e f}  1 3  5 5

It would seem a reasonable extension for such a usage of '''lrange''' to
return "b c d f". This would also make following pattern of usage feasible:

| lassign [lrange $someList 0 2  10 12]  var0 var1 var2 var10 var11 var12

The indices should ''not'' be required to be in ascending order.
This is meant such that the ranges may be overlapping at will. E.g.:

| [lrange $list 0 end 0 end] == [lrepeat 2 {*}$list]

This TIP does NOT change the way each range is interpreted.
Reversing lists is not in the scope of this TIP.

~ Proposed Change

Change the implementation of '''lrange''' to accept any odd number of
arguments, with semantics (upon supply of a correct number of arguments)
equivalent to:

| proc lrange-new {list args} {
|    set result [list]
|    foreach {start end} $args {
|       lappend result {*}[lrange $list $start $end]
|    }

|    return $result
| }


~ Draft Implementation

Just the above mentioned procedure, at the moment.

~ Further Thoughts

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|

|



|


|

|


|

|


|




|

|
|


|
|
|
|
<
>
|
<
|
>
|



|

|


>

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

# TIP 295: Enhance Arguments to lrange

	Author:         Andreas Leitgeb <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        06-Nov-2006
	Post-History:   
	Keywords:       Tcl,lrange
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes an enhancement to **lrange** and **string range** that lets them take more than one start-end index pair.

# Rationale

Sometimes you need to extract a non-continuous selection of elements from some
list and build a new list from them. This requires the use of multiple calls
to **lrange** and a surrounding **concat** to build the final list.
However, since the following fails with a syntax error:

	    lrange {a b c d e f}  1 3  5 5

It would seem a reasonable extension for such a usage of **lrange** to
return "b c d f". This would also make following pattern of usage feasible:

	 lassign [lrange $someList 0 2  10 12]  var0 var1 var2 var10 var11 var12

The indices should _not_ be required to be in ascending order.
This is meant such that the ranges may be overlapping at will. E.g.:

	 [lrange $list 0 end 0 end] == [lrepeat 2 {*}$list]

This TIP does NOT change the way each range is interpreted.
Reversing lists is not in the scope of this TIP.

# Proposed Change

Change the implementation of **lrange** to accept any odd number of
arguments, with semantics \(upon supply of a correct number of arguments\)
equivalent to:

	 proc lrange-new {list args} {
	    set result [list]
	    foreach {start end} $args {
	       lappend result {*}[lrange $list $start $end]

	    }
	    return $result

	 }

# Draft Implementation

Just the above mentioned procedure, at the moment.

# Further Thoughts

# Copyright

This document has been placed in the public domain.

Name change from tip/296.tip to tip/296.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

TIP:            296
Title:          Enhanced Syntax for Pair-Wise Indices
Version:        $Revision: 1.7 $
Author:         Andreas Leitgeb <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        06-Nov-2006
Post-History:   
Keywords:       Tcl,lrange,lreplace
Tcl-Version:    8.7


~ Abstract

This TIP proposes adding another anchor '''s''' (for usage exclusively in
end-indices) that refers to the respective start-index.

~ Rationale

Currently, most commands that accept an index also accept the local keyword '''end''' as well as simple arithmetics involving this keyword.

Commands that accept a pair of indices for a range, require an explicit start and (inclusive)end index for the requested subrange.

In other languages (C++/stl, java, ...) it appears to be more common to specify ranges by start and length. Since the length has a higher tendency of being constant, this seems actually the better idea, anyway. For compatibility reasons, we just cannot simply change all the commands to take offset/length pairs rather than start/end.

However we could add a new anchor '''s''' to be used in the end-index, and allow simple arithmetic on it just like on the other index forms.

Specifying a subrange of length 1, one would then simply specify '''s''' as end-index.  For a pair, "s+1" as end index does it.

If the start position of a subrange is obtained as result of a command, currently one typically does in tcl:

| set offs [...]
| ... [lrange $list $offs [expr {$offs+1}]] ...

A previous TIP has added support to do the following instead:

| set offs [...]
| ... [lrange $list $offs $offs+1] ...

This TIP aims at making this the new idiom:

| ... [lrange $list [...] s+1]

~ Proposed Change

Currently there is a function TclGetIntForIndex, which deals with the current '''end''' anchor. It could be accompanied with a second function (e.g., TclGetIntForIndex2) that would accept another argument for the previously calculated index (from the range-start argument), and use that in case the new anchor '''s''' occurs in the range-end index.

No change at all is proposed for each range's start index.

~ Draft Implementation

None, at the moment.

For a sketch see previous section. In bytecode, it could be done such, that if an '''s'''-prefix is seen for an (eventually bytecoded range-related command), then the current stack-top (the corresponding start-index) is dup'ed and then incremented or decremented according to
any offset (s+#, s-#).

~ Further Thoughts

For '''lreplace''', '''s-1''' as an end-index would actually make it an '''linsert''' operation.

This TIP covers all tcl commands that accept a pair of indices to specify a range, including (but not limited to)  lrange, lreplace, string range,  plus any third-party command written such as to use the proposed '''TclGetIntForIndex2''' function for parsing end-indices.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|

|

|

|

|

|

|



|
|



|
|



|

|

|



|



|
|

|

|

|

|


>

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

# TIP 296: Enhanced Syntax for Pair-Wise Indices

	Author:         Andreas Leitgeb <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        06-Nov-2006
	Post-History:   
	Keywords:       Tcl,lrange,lreplace
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes adding another anchor **s** \(for usage exclusively in
end-indices\) that refers to the respective start-index.

# Rationale

Currently, most commands that accept an index also accept the local keyword **end** as well as simple arithmetics involving this keyword.

Commands that accept a pair of indices for a range, require an explicit start and \(inclusive\)end index for the requested subrange.

In other languages \(C\+\+/stl, java, ...\) it appears to be more common to specify ranges by start and length. Since the length has a higher tendency of being constant, this seems actually the better idea, anyway. For compatibility reasons, we just cannot simply change all the commands to take offset/length pairs rather than start/end.

However we could add a new anchor **s** to be used in the end-index, and allow simple arithmetic on it just like on the other index forms.

Specifying a subrange of length 1, one would then simply specify **s** as end-index.  For a pair, "s\+1" as end index does it.

If the start position of a subrange is obtained as result of a command, currently one typically does in tcl:

	 set offs [...]
	 ... [lrange $list $offs [expr {$offs+1}]] ...

A previous TIP has added support to do the following instead:

	 set offs [...]
	 ... [lrange $list $offs $offs+1] ...

This TIP aims at making this the new idiom:

	 ... [lrange $list [...] s+1]

# Proposed Change

Currently there is a function TclGetIntForIndex, which deals with the current **end** anchor. It could be accompanied with a second function \(e.g., TclGetIntForIndex2\) that would accept another argument for the previously calculated index \(from the range-start argument\), and use that in case the new anchor **s** occurs in the range-end index.

No change at all is proposed for each range's start index.

# Draft Implementation

None, at the moment.

For a sketch see previous section. In bytecode, it could be done such, that if an **s**-prefix is seen for an \(eventually bytecoded range-related command\), then the current stack-top \(the corresponding start-index\) is dup'ed and then incremented or decremented according to
any offset \(s\+\#, s-\#\).

# Further Thoughts

For **lreplace**, **s-1** as an end-index would actually make it an **linsert** operation.

This TIP covers all tcl commands that accept a pair of indices to specify a range, including \(but not limited to\)  lrange, lreplace, string range,  plus any third-party command written such as to use the proposed **TclGetIntForIndex2** function for parsing end-indices.

# Copyright

This document has been placed in the public domain.

Name change from tip/297.tip to tip/297.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

TIP:            297
Title:          Integer Type Introspection and Conversion
Version:        $Revision: 1.3 $
Author:         Don Porter <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        20-Nov-2006
Post-History:
Tcl-Version:    8.7
Keywords:	Tcl, number, expression


~ Abstract

This TIP proposes changes to complete the set of commands to test and convert
among Tcl's integer types.

~ Background

There are four integer types that appear in Tcl's C API. They are ''int'',
''long'', ''Tcl_WideInt'', and ''mp_int''. The corresponding routines to pull
a value of each of those types from a ''Tcl_Obj'' are '''Tcl_GetIntFromObj''',
'''Tcl_GetLongFromObj''', '''Tcl_GetWideIntFromObj''', and
'''Tcl_GetBignumFromObj'''. These integer types form increasing sets. That is,
every ''Tcl_Obj'' that can return an ''int'' can also return a ''long'',
''Tcl_WideInt'', or ''mp_int''.

Strictly speaking, the set of ''Tcl_Obj'' values that can successfully return
either and ''int'', ''long'', or ''Tcl_WideInt'' is platform-dependent,
because the size of these types is platform dependent.
'''Tcl_GetIntFromObj''' accepts integer values in any format (decimal, binary,
octal, hexadecimal, etc., see '''TCL_PARSE_INTEGER_ONLY''' in [249]) that are
within the inclusive platform-dependent range ('''-UINT_MAX''',
'''UINT_MAX'''). '''Tcl_GetLongFromObj''' accepts integer values in any format
that are within the inclusive platform-dependent range ('''-ULONG_MAX''',
'''ULONG_MAX'''). '''Tcl_GetWideIntFromObj''' accepts integer values in any
format that are within the inclusive platform-dependent range
('''-ULLONG_MAX''', '''ULLONG_MAX'''), or the appropriate equivalent for the
platform. '''Tcl_GetBignumFromObj''' accepts integer values in any format with
(effectively) no limit on range.

The most common example of platform dependence of results seen at the script
level is the different results of '''[[expr int(.)]]''' on most 32-bit
systems,

| % set tcl_platform(wordSize)
| 4

| % expr int(1<<31)
| -2147483648

compared with LP64 systems.

| % set tcl_platform(wordSize)
| 8

| % expr int(1<<31)
| 2147483648

These differences show up most unfortunately when implementing algorithms
designed to operate explicitly on 32-bit buffers, where the only portable way
to do the operations in Tcl is with careful application of masking (''&
0xffffffff''). For one well-known example, see the ''sha1'' package in tcllib.
The additional operations in Tcl expressions harm performance.

There are other Tcl routines that pull values from ''Tcl_Obj'' that accept
supersets of one of the integer types. An example is '''Tcl_GetIndexFromObj'''
which will accept anything that '''Tcl_GetIntFromObj''' accepts, as well as
other string values. There are also Tcl built-in commands that accept
arguments that are supersets of one of the integer types. An example is
'''uplevel''' which accepts as its level argument anything that
'''Tcl_GetIntFromObj''' accepts, as well as other string values.

All Tcl commands are ultimately defined by the C command procedures that run
to implement them, and when those command procedures use the routines
mentioned above to pull values from command arguments, the result is that the
Tcl commands will succeed or fail depending on whether or not an integer value
of the right type has been provided by the caller. As a simple example:

| % lindex {} 0xffffffff
| % lindex {} 0x100000000
| bad index "0x100000000": must be integer or end?-integer?

In order to avoid errors from commands, a cautious programmer may wish to test
whether a value is of an acceptable type before passing it to a command. The
'''string is integer''' command has long offered this facility for commands
that require (a superset of) an ''int''.

| % string is integer 0xffffffff
| 1

| % string is integer 0x100000000
| 0


Most of Tcl's built-in commands that accept an integer valued argument require
that argument to be acceptable to '''Tcl_GetIntFromObj''' and the existing
'''string is integer''' command provides sufficient introspection.

[188] created the new command '''string is wideinteger''', and that is
suitable for testing values for the small number of Tcl commands that strictly
require a value acceptable to '''Tcl_GetWideIntFromObj'''. Those commands
are:

| after $wide
| binary format w $wide
| chan seek $chan $wide
| chan truncate $chan $wide
| clock add $wide
| clock format $wide

There are some built-in Tcl commands that require an argument that is
acceptable to '''Tcl_GetBignumFromObj'''. That is, the argument must be an
integer, but no range limit is imposed. Currently there is no test command
appropriate for argument checking for these commands.

| dict incr $dictVar $bignumkey $bignum
| expr srand($bignum)
| expr ~$bignum
| expr $bignum % $bignum
| expr $bignum << $int
| expr $bignum >> $bignum
| expr $bignum & $bignum
| expr $bignum ^ $bignum
| expr $bignum | $bignum
| incr $bignumVar $bignum
| format $integerSpecifier $bignum

There are some built-in Tcl commands that require an argument that is
acceptable to '''Tcl_GetLongFromObj'''. Currently there is no test command
appropriate for argument checking for these commands.

| binary format i $long
| binary format s $long
| binary format c $long
| file atime $path $long
| file attributes $path -permissions $long
| file mtime $path $long

Note that the accepted ranges of the '''Tcl_GetFooFromObj''' routines can lead
to surprising results. For example, '''Tcl_GetIntFromObj''' accepts values
from '''-UINT_MAX''' to '''UINT_MAX'''. For some things this is good, since it
supports

| binary format i 0x80000000

on 32-bit platforms, which is a common coding style. However the same range
acceptance leads to surprising (and arguably incorrect, in the presence of
bignum support) things like:

| % string repeat a -4294967290
| aaaaaa

It seems there are good uses for both strict and liberal routines for pulling
integer ranges from a ''Tcl_Obj''. Compatibility concerns would favor keeping
the existing routines liberal, and adding strict counterparts. If this is
pursued, however, another collection of '''string is''' test commands would be
needed as well.

~ Proposed Changes

Still pondering how best to react to this background. Discussion invited on
TCLCORE.

~ Compatibility

~ Reference Implementation

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|

|
|
|
|
|
|
|

|
|

|
|
|
|
|
|

|
|
|


|


|
<
>
|
|



|
<
>
|
|



|
|


|
|
|


|
|







|
|
|



|
|

|
<
>
|
<
|
>

|
|

|

|


|
|
|
|
|
|


|



|
|
|
|
|
|
|
|
|
|
|


|


|
|
|
|
|
|

|
|
|


|


|
|

|
|


|

|


|




|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

# TIP 297: Integer Type Introspection and Conversion

	Author:         Don Porter <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        20-Nov-2006
	Post-History:
	Tcl-Version:    8.7
	Keywords:	Tcl, number, expression
-----

# Abstract

This TIP proposes changes to complete the set of commands to test and convert
among Tcl's integer types.

# Background

There are four integer types that appear in Tcl's C API. They are _int_,
_long_, _Tcl\_WideInt_, and _mp\_int_. The corresponding routines to pull
a value of each of those types from a _Tcl\_Obj_ are **Tcl\_GetIntFromObj**,
**Tcl\_GetLongFromObj**, **Tcl\_GetWideIntFromObj**, and
**Tcl\_GetBignumFromObj**. These integer types form increasing sets. That is,
every _Tcl\_Obj_ that can return an _int_ can also return a _long_,
_Tcl\_WideInt_, or _mp\_int_.

Strictly speaking, the set of _Tcl\_Obj_ values that can successfully return
either and _int_, _long_, or _Tcl\_WideInt_ is platform-dependent,
because the size of these types is platform dependent.
**Tcl\_GetIntFromObj** accepts integer values in any format \(decimal, binary,
octal, hexadecimal, etc., see **TCL\_PARSE\_INTEGER\_ONLY** in [[249]](249.md)\) that are
within the inclusive platform-dependent range \(**-UINT\_MAX**,
**UINT\_MAX**\). **Tcl\_GetLongFromObj** accepts integer values in any format
that are within the inclusive platform-dependent range \(**-ULONG\_MAX**,
**ULONG\_MAX**\). **Tcl\_GetWideIntFromObj** accepts integer values in any
format that are within the inclusive platform-dependent range
\(**-ULLONG\_MAX**, **ULLONG\_MAX**\), or the appropriate equivalent for the
platform. **Tcl\_GetBignumFromObj** accepts integer values in any format with
\(effectively\) no limit on range.

The most common example of platform dependence of results seen at the script
level is the different results of **[expr int(.)]** on most 32-bit
systems,

	 % set tcl_platform(wordSize)

	 4
	 % expr int(1<<31)
	 -2147483648

compared with LP64 systems.

	 % set tcl_platform(wordSize)

	 8
	 % expr int(1<<31)
	 2147483648

These differences show up most unfortunately when implementing algorithms
designed to operate explicitly on 32-bit buffers, where the only portable way
to do the operations in Tcl is with careful application of masking \(_&
0xffffffff_\). For one well-known example, see the _sha1_ package in tcllib.
The additional operations in Tcl expressions harm performance.

There are other Tcl routines that pull values from _Tcl\_Obj_ that accept
supersets of one of the integer types. An example is **Tcl\_GetIndexFromObj**
which will accept anything that **Tcl\_GetIntFromObj** accepts, as well as
other string values. There are also Tcl built-in commands that accept
arguments that are supersets of one of the integer types. An example is
**uplevel** which accepts as its level argument anything that
**Tcl\_GetIntFromObj** accepts, as well as other string values.

All Tcl commands are ultimately defined by the C command procedures that run
to implement them, and when those command procedures use the routines
mentioned above to pull values from command arguments, the result is that the
Tcl commands will succeed or fail depending on whether or not an integer value
of the right type has been provided by the caller. As a simple example:

	 % lindex {} 0xffffffff
	 % lindex {} 0x100000000
	 bad index "0x100000000": must be integer or end?-integer?

In order to avoid errors from commands, a cautious programmer may wish to test
whether a value is of an acceptable type before passing it to a command. The
**string is integer** command has long offered this facility for commands
that require \(a superset of\) an _int_.

	 % string is integer 0xffffffff

	 1
	 % string is integer 0x100000000

	 0

Most of Tcl's built-in commands that accept an integer valued argument require
that argument to be acceptable to **Tcl\_GetIntFromObj** and the existing
**string is integer** command provides sufficient introspection.

[[188]](188.md) created the new command **string is wideinteger**, and that is
suitable for testing values for the small number of Tcl commands that strictly
require a value acceptable to **Tcl\_GetWideIntFromObj**. Those commands
are:

	 after $wide
	 binary format w $wide
	 chan seek $chan $wide
	 chan truncate $chan $wide
	 clock add $wide
	 clock format $wide

There are some built-in Tcl commands that require an argument that is
acceptable to **Tcl\_GetBignumFromObj**. That is, the argument must be an
integer, but no range limit is imposed. Currently there is no test command
appropriate for argument checking for these commands.

	 dict incr $dictVar $bignumkey $bignum
	 expr srand($bignum)
	 expr ~$bignum
	 expr $bignum % $bignum
	 expr $bignum << $int
	 expr $bignum >> $bignum
	 expr $bignum & $bignum
	 expr $bignum ^ $bignum
	 expr $bignum | $bignum
	 incr $bignumVar $bignum
	 format $integerSpecifier $bignum

There are some built-in Tcl commands that require an argument that is
acceptable to **Tcl\_GetLongFromObj**. Currently there is no test command
appropriate for argument checking for these commands.

	 binary format i $long
	 binary format s $long
	 binary format c $long
	 file atime $path $long
	 file attributes $path -permissions $long
	 file mtime $path $long

Note that the accepted ranges of the **Tcl\_GetFooFromObj** routines can lead
to surprising results. For example, **Tcl\_GetIntFromObj** accepts values
from **-UINT\_MAX** to **UINT\_MAX**. For some things this is good, since it
supports

	 binary format i 0x80000000

on 32-bit platforms, which is a common coding style. However the same range
acceptance leads to surprising \(and arguably incorrect, in the presence of
bignum support\) things like:

	 % string repeat a -4294967290
	 aaaaaa

It seems there are good uses for both strict and liberal routines for pulling
integer ranges from a _Tcl\_Obj_. Compatibility concerns would favor keeping
the existing routines liberal, and adding strict counterparts. If this is
pursued, however, another collection of **string is** test commands would be
needed as well.

# Proposed Changes

Still pondering how best to react to this background. Discussion invited on
TCLCORE.

# Compatibility

# Reference Implementation

# Copyright

This document has been placed in the public domain.

Name change from tip/298.tip to tip/298.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

TIP:            298
Title:          Revise Shared Value Rules for Tcl_GetBignumAndClearObj
Version:        $Revision: 1.6 $
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        22-Nov-2006
Post-History:   
Keywords:       Tcl,Tcl_Obj
Tcl-Version:    8.5


~ Abstract

This TIP proposes a revision to '''Tcl_GetBignumAndClearObj''' to make it
easier to use.

~ Background

'''Tcl_GetBignumAndClearObj''' was added by [237]. Because ''mp_int'' values
can be big, the interface is offered to avoid making a copy when the value
already in the internal representation of an unshared ''Tcl_Obj'' will no
longer be needed and can be moved instead of copied.

The basic intent was fine, but in practice, callers must go through these
gymnastics to use it:

| if (Tcl_IsShared(objPtr)) {
|     Tcl_GetBignumFromObj(interp, objPtr, &bigValue);
| } else {
|     Tcl_GetBignumAndClearObj(interp, objPtr, &bigValue);
| }


It would make for a much more pleasant interface to move the test for a shared
value into the routine itself.

~ Proposed Change

When passed a shared ''objPtr'', '''Tcl_GetBignumAndClearObj''' will no longer
panic, but will fall back to the copying behavior of
'''Tcl_GetBignumFromObj'''. The use of the '''Tcl_GetBignumAndClearObj'''
interface by a caller no longer means an assertion that ''objPtr'' is
unshared, and no longer guarantees that ''objPtr'' will in fact be cleared,
but merely indicates the caller will not be using the value anymore, and does
not mind if it is cleared. That's all the caller should care about anyway.

Because of these changes in the implications and guarantees,
the function is also renamed to '''Tcl_TakeBignumFromObj'''.

With these changes, the code above may be simplified to:

| Tcl_TakeBignumFromObj(interp, objPtr, &bigValue);

~ Compatibility

This is a incompatible change only with 8.5 alpha releases.

~ Reference Implementation

Available from
[http://sourceforge.net/tracker/index.php?func=detail&aid=1601243&group_id=10894&atid=360894].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|

|





|
|
|
|
<
>




|

|

|
|
|




|



|

|



|


|

|


>

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

# TIP 298: Revise Shared Value Rules for Tcl_GetBignumAndClearObj

	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        22-Nov-2006
	Post-History:   
	Keywords:       Tcl,Tcl_Obj
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes a revision to **Tcl\_GetBignumAndClearObj** to make it
easier to use.

# Background

**Tcl\_GetBignumAndClearObj** was added by [[237]](237.md). Because _mp\_int_ values
can be big, the interface is offered to avoid making a copy when the value
already in the internal representation of an unshared _Tcl\_Obj_ will no
longer be needed and can be moved instead of copied.

The basic intent was fine, but in practice, callers must go through these
gymnastics to use it:

	 if (Tcl_IsShared(objPtr)) {
	     Tcl_GetBignumFromObj(interp, objPtr, &bigValue);
	 } else {
	     Tcl_GetBignumAndClearObj(interp, objPtr, &bigValue);

	 }

It would make for a much more pleasant interface to move the test for a shared
value into the routine itself.

# Proposed Change

When passed a shared _objPtr_, **Tcl\_GetBignumAndClearObj** will no longer
panic, but will fall back to the copying behavior of
**Tcl\_GetBignumFromObj**. The use of the **Tcl\_GetBignumAndClearObj**
interface by a caller no longer means an assertion that _objPtr_ is
unshared, and no longer guarantees that _objPtr_ will in fact be cleared,
but merely indicates the caller will not be using the value anymore, and does
not mind if it is cleared. That's all the caller should care about anyway.

Because of these changes in the implications and guarantees,
the function is also renamed to **Tcl\_TakeBignumFromObj**.

With these changes, the code above may be simplified to:

	 Tcl_TakeBignumFromObj(interp, objPtr, &bigValue);

# Compatibility

This is a incompatible change only with 8.5 alpha releases.

# Reference Implementation

Available from
<http://sourceforge.net/tracker/index.php?func=detail&aid=1601243&group_id=10894&atid=360894> .

# Copyright

This document has been placed in the public domain.

Name change from tip/299.tip to tip/299.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

TIP:            299
Title:          Add isqrt() Math Function
Version:        $Revision: 1.3 $
Author:         Kevin B. Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        24-Nov-2006
Post-History:   
Tcl-Version:    8.5
Keywords:	Tcl, expression, integer, square root


~ Abstract

This TIP proposes a new '''expr''' math function '''isqrt()'''.

~ Background

With the advent of large integers, Tcl supports taking the square roots of
arguments that lie outside the native floating-point range of the machine.
The square roots are returned as floating point numbers if possible. This
behaviour is correct when floating-point calculations are intended. There are
times, however, when an arbitrary-precision square root is wanted. This root
cannot be obtained by evaluating ''entier(sqrt($n))'', because ''sqrt($n)''
has already lost precision.

~ Proposed Change

This TIP proposes adding a new math function, ''isqrt($n)'', that will return
the integer part of the square root of ''$n'' to arbitrary precision. The
argument ''$n'' must be numeric and non-negative; it may be either integer or
floating-point.

~ Reference Implementation

Tcl Feature Request #1602534 contains a complete reference implementation for
the ''isqrt'' function.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|

|






|


|

|
|
|


|

|
|

|


>

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

# TIP 299: Add isqrt() Math Function

	Author:         Kevin B. Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        24-Nov-2006
	Post-History:   
	Tcl-Version:    8.5
	Keywords:	Tcl, expression, integer, square root
-----

# Abstract

This TIP proposes a new **expr** math function **isqrt\(\)**.

# Background

With the advent of large integers, Tcl supports taking the square roots of
arguments that lie outside the native floating-point range of the machine.
The square roots are returned as floating point numbers if possible. This
behaviour is correct when floating-point calculations are intended. There are
times, however, when an arbitrary-precision square root is wanted. This root
cannot be obtained by evaluating _entier\(sqrt\($n\)\)_, because _sqrt\($n\)_
has already lost precision.

# Proposed Change

This TIP proposes adding a new math function, _isqrt\($n\)_, that will return
the integer part of the square root of _$n_ to arbitrary precision. The
argument _$n_ must be numeric and non-negative; it may be either integer or
floating-point.

# Reference Implementation

Tcl Feature Request \#1602534 contains a complete reference implementation for
the _isqrt_ function.

# Copyright

This document has been placed in the public domain.

Name change from tip/3.tip to tip/3.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585

TIP:            3
Title:          TIP Format
Version:        $Revision: 1.8 $
Author:         Andreas Kupries <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Accepted
Type:           Process
Vote:           Done
Created:        14-Sep-2000
Post-History:


~ Abstract

This TIP is a companion document to the TIP Guidelines [2] and
describes the structure and formatting to use when writing a TIP.


~ Rationale

The major goals of this document are to define a format that is

   * easy to write,

   * easy to read,

   * easy to search, and

   * acceptable to the community at large.

The latter is important because non-acceptance essentially means that
the TIP process will be stillborn. This not only means basically plain
text without much markup but also that we should reuse formats with
which people are already acquainted.

As the concept of TIPs borrows heavily from Python's PEPs
[http://python.sourceforge.net/peps/] their definition on how to
structure and format a PEP was reviewed for its suitability of use by
the TCT and the community at large.

The major points of the format are:

   * Plain ASCII text without special markup for references or
     highlighting of important parts.

   * Mail-like header section containing the meta-information.

   * Uses indentation to distinguish section headers from section
     text.

A header section like is used in mail or news is something people are
acquainted with and fulfils the other criteria too. In addition it is
extendable. Using indentation to convey semantic and syntactic
information on the other hand is something Pythonistas are used to but
here in the Tcl world we are not to the same extent.

Looking at bit closer to home we find the Tcl'ers Wiki [http://wiki.tcl.tk/]

It does use a plain text format with some very light formatting
conventions to allow things like links, images, enumerated and
itemized lists.

Given the rather high acceptance of this site by the community using
its format should be beneficiary to the acceptance of TIPs too.

It is therefore proposed to use a combination of a header in mail/news
style together with a body employing a slightly extended/modified Wiki
format (mostly backward compatible) as the format for TIPs. This
proposed format is specified in detail below.

''Note'' that the use of TAB characters within a TIP is discouraged
(but permitted) as some mailers (notably Outlook Express) make a mess
of them.  Please be considerate and avoid their use...

~ Rejected Alternatives

But before we specify the format a (short) discussion of possible
alternatives and why they where rejected.

There were three primary competitors to the format specified below,
these are SGML/XML, HTML and a markup based upon plain text with
embedded tcl-commands, for example like ... [[section Abstract]] ...

   * The main disadvantage of SGML and XML based solutions is that
     they require a much more heavyweight infrastructure for editing
     and processing documents using them, like specialized editors and
     extensions for parsing. The format below on the other hand can be
     processed using pure tcl without extensions. with respect to the
     specialized editors it should be said that an editor operating on
     plain ASCII is possible too, but then the text will be difficult
     to read for humans because of the many occurrences of < and >,
     conflicting with the requirement to have an 'easy to read'
     format.

   > While there are commercial products which can gloss over this,
     making the editing of XML fairly easy, not everyone currently has
     access to one or the desire to spend what might be quite a lot of
     money to acquire one.  It is far better to let everyone continue
     to use their current favourite plain-text editor.

   * The main problem of HTML is that it is focused on visual and
     not logical markup. This will make it, although not impossible,
     but very difficult to parse documents for automatic handling.  It
     is also a poor format for producing printed versions of the
     documentation from.  Experience has also shown that different
     people have widely different ideas about how the content of TIP
     documents should be rendered into HTML, an indication that using
     the language would prove problematic!  We can still use HTML as a
     generated format, but we should not write the documents
     themselves in it.

   * The approach of embedding tcl commands into the text of a TIP is
     (at least) as powerful as XML when it comes to automatic
     processing of documents but much more lightweight. Because of
     this it is seen as the best of the three rejected alternatives.
     It was rejected in the end because it was still seen as too
     heavyweight/demanding for the casual user with respect to
     learning, easy writing and reading.


~ Header Format

The general format of the header for a TIP is specified in RFC 822
[http://www.rfc-editor.org/rfc/rfc822.txt]. This leaves us to define
and explain the keywords, their meaning and their values.  The
following keywords are ''required'', and unless otherwise stated,
should occur exactly once:

   TIP:
	The number of the TIP as assigned by the TIP editor.
	Unchangeable later on.

   Title:
	Defines the title of the document using plain text. May change
	during the discussion and review phases.

   Version:
	Specifies the version of the document.  Usually something like
	$Revision: 1.8 $. (Initially $Revision: 1.8 $ should be used, which
	is then changed by the version control to contain the actual
	revision number.

   Author:
	Contact information (email address) for each author. The email
	address has to contain the real name of the author.  If there
	are multiple authors of the document, this header may occur
	multiple times (once per author.)  The format should be
	approximately like this:  ''Firstname Lastname <emailaddress>''

   State:
	Defines the state the TIP is currently in. Allowed values are
	''Draft'', ''Active'', ''Accepted'', ''Deferred'', ''Final'',
	''Rejected'' and ''Withdrawn''.  This list will be influenced
	by the finalization of the workflow in [2].

   Type:
	The type of the TIP.  Allowed values are ''Process'',
	''Project'' and ''Informative''. See [2] for more explanations
	about the various types.

   Vote:
	The current state of voting for the TIP.  Allowed values are
	''Pending'', ''In progress'', ''Done'' and ''No voting''. The
	latter is used to indicate a TIP which doesn't require a vote,
	for example [1].

   Created:
	The date the TIP was created, in the format dd-mmm-yyyy.
	''mmm'' is the (English) short name of the month. The other
	information is numerical. Example: 14-Sep-2000

   >    All numeric dates, though more easily internationalised, are
        not used because the ordering of particularly the month and
        day is ambiguous and subject to some confusion between
        different locales.  Unix-style timestamps are unreadable to
        the majority of people (as well as being over-precise,) and I
        (<[email protected]>) don't know ISO 8601 well enough to
        be able to comment on it.

   Post-History:
	A list of the dates the document was posted to the mailing list
	for discussion.

   Tcl-Version:
	This indicates the version of Tcl that a Project TIP depends
	upon (where it is required.)  Process and Informative TIPs
	''must not'' have this keyword.

The following headers are ''optional'' and should (unless otherwise
stated) occur at most once:

   Discussions-To:
	While a TIP is in private discussions (usually during the
	initial Draft phase), this header will indicate the mailing
	list or URL where the TIP is being discussed.

   Obsoletes:
	Indicates a TIP number that this TIP renders obsolete.
	(Thanks to Joel Saunier <[email protected]> for
	suggesting this!)

   Obsoleted-By:
	Indicates a TIP number that renders this TIP obsolete.
	(Thanks to Joel Saunier <[email protected]> for
	suggesting this!)

   Keywords:
	A comma-separated list of keywords relating to this TIP, to
	facilitate automated indexing and improve search engine
	results.

The following headers are ''proposed'' (by Donald G. Porter
<[email protected]>) but not currently supported:

   Sponsor:
	A TCT member that is sponsoring this TIP.  May occur multiple
	times, once per sponsor.

   Supporter:
	A person (not necessarily a TCT member) who is supporting this
	TIP.  May occur multiple times, once per supporter.

   Objector:
	A person (not necessarily a TCT member) who is opposed to this
	TIP.  May occur multiple times, once per objector.

~ Body Format

The body of a TIP is split by visually blank lines (i.e. lines
containing nothing other than conventional whitespace) into units that
will be called paragraphs.  Each paragraph is in one of the following
forms.

If the paragraph consists of exactly four minus symbols "----" then it
is a separator paragraph and should be rendered as a horizonal rule.

If the paragraph consists of a vertical bar "|" followed by text, then
it is a verbatim paragraph.  The bar will be stripped from the front
of each line and the rest of the text will be formatted literally.
Tab characters will be expanded to 8-character boundaries.  (''Note
that this is completely incompatible with the Tcl'ers Wiki.'')

If the paragraph consists of one or more tildes "~" (which may be
space-separated) followed by text, then it is
a section heading.  The text following is the name of the section.  In
the name of good style, the section heading should have its
significant words capitalised.  The number of tildes indicates whether
this is a section heading, a subsection heading or a subsubsection
heading (one, two or three tildes respectively.)

If the paragraph consists of the sequence "#index:" followed by some
optional text, then it is a request to insert an index.  The text
following (after trimming spaces) indicates the kind of index desired.
The default is a "medium" index, and fully compliant implementations
should support "short" (expected to contain less detail) and "long"
(expected to contain all header details plus the abstract) as well.
Support for other kinds of indices is optional.

If the paragraph consists of the sequence "#image:" followed by some
text, then it is a request to insert an image.  The first word of the
following text is a reference to the image, and the other words are
an optional caption for the image (in plain text.)  Image references
that consist of just letters, numbers, hyphens and underscores are
handled specially by the current implementation, which can map them to
the correct media type for its current output format (assuming it has
a suitable image in its repository.)

All other paragraphs that start with a non-whitespace character are
ordinary paragraphs.

If a paragraph starts with a whitespace character sequence (use three
spaces and keep the whole paragraph on a single line if you want
compatability with the Tcl'ers Wiki,) a star "*" and another
whitespace character, it is an item in a bulleted list.

If a paragraph starts with a whitespace character sequence, a number,
a full stop "." and another whitespace character, it is an item in an
enumerated list.  If the number is 1 then the number of the item is
guessed from the current list context, and any other value sets the
number explicitly.  If you want compatability with the Tcl'ers Wiki,
make the initial whitespace sequence be three spaces, the number be 1,
and keep the whole paragraph on a single line.

If a paragraph starts with a whitespace character sequence, some text
(that includes no tabs or newlines but can include spaces), a colon
and another whitespace character, then it is an item in a descriptive
(a.k.a. definition) list.  The item being described cannot contain
advanced formatting (including any kind of emphasis) because this is
not supported by all formats that a TIP may be viewed in.

If a paragraph does not start with a whitespace character sequence, a
greater than symbol ">", and then another whitespace character, it is
also an ordinary paragraph.  (''Note that this is completely
incompatible with the Tcl'ers Wiki.'')

Where a paragraph does begin with the sequence described in the
preceding paragraph, it is a nested list item (if the paragraph
contained is a list item) or a subsequent paragraph (if the paragraph
contained is an ordinary paragraph.)  If there's no suitable
"enclosing" list context (i.e. if the preceding paragraph was not part
of a list) the paragraph will be a quotation instead.  (The rules for
these continuation paras seem complex at first glance, but seem to
work out fairly well in practise, especially since they are only
rarely used.)

Within the body text of a (non-verbatim) paragraph, there are two
styles of emphasis:

 * italicised emphasis is indicated by enclosing the text within
   inside double apostrophes "''"

 * emboldened emphasis is indicated by enclosing the text within
   inside triple apostrophes "'''".

The two emphasis styles should not be nested. Special URLs of
the form tip:tipnumber are expanded into full URLs to the given TIP
through the current formatting engine (where applicable.)  References
of the form [tipnumber] are also expanded as links to the given TIP,
but are not displayed as URLs (the expansion is format dependent, of
course.)  Doubled up square brackets are converted into matching
single square brackets.  Email addresses (of the form <email@address>)
and ordinary URLs in single square brackets might also be treated specially.

The first paragraph of the body of any TIP must be an abstract section
title ("~Abstract" or "~ Abstract"), and the second must be an
ordinary paragraph (and should normally be just plain text, to make
processing by tools easier.)

You can compare these rules with those for the Tcl'ers Wiki which are
described at http://wiki.tcl.tk/14.html, with the
following modifications:

   1. The text for an item in an itemized, enumerated or tagged list
      can be split over multiple physical lines. The text of the item
      will reach until the next empty line.

   1. All paragraphs ''must'' be split with whitespace.  This is a
      corollary of the above item.

   1. A paragraph starting with the character ~ is interpreted as a
      section heading.  Consequently it should be very short so that
      it renders onto a single line under most circumstances.

   1. A full verbatim mode is added. Any line starting with the bar
      character is reproduced essentially verbatim (the bar character
      is removed). This allows embedding of code or other texts
      containing formatting usually recognized as special by the
      formatter without triggering this special processing. This
      applies especially to brackets and the hyperlinking they provide
      and their role in tcl code.  This is used in preference to the
      whitespace rule of the Tcl'ers Wiki which is potentially far
      more sensitive.  Our rule makes it extremely obvious what lines
      are verbatim, and what those lines will be rendered as.

   1. Only one style of emphasis within paragraphs is supported.
      Having multiple emphasis styles (italic and bold) not only fails
      to carry across well in all media, but also makes for confusion
      on the part of authors and is more difficult to write renderers
      for too.

   1. Images are only supported in a limited way, since under HTML the
      support for images varies a lot more than most people would like
      to think, and the concept of an inline image can vary quite a
      lot between different rendered formats too.

~ Reference Implementation

A reference renderer was created by Donal Fellows
<[email protected]> and is installed (as a behind-the-scenes
rendering engine) on a set of TIP documents
[http://www.cs.man.ac.uk/fellowsd-bin/TIP] with the source code to the
rendering engine being available
[http://sf.net/projects/tiprender/]

Note that this code does support nested lists and multi-paragraph
items, but this is experimental right now. Examples are presented
behind the code itself.

----

~ Examples

This document itself is an example of the new format.

''Examples for nested lists, multi-paragraph items in list's, and
quotations.''

Here is the source (itself a demonstration of verbatim text)

| * This is a paragraph
|
| > * This is an inner paragraph
|     that goes onto two lines.
|
| > > * This one's even further in!
|
| > > * So's this one.
|
| > * Out again
|
| > > And a second paragraph here...
|
| > * Yet another item.
|
| * Outermost level once more.
|
| 1. Enumerate?
|
| > 1. Deeper?
|
| 2. Out again?
|
| list item: body text that is relatively long so that we can tell
|   that it laps round properly as a paragraph even though this takes a
|   ridiculous amount of text on my browser...
|
|| VERB IN LIST?
|
| > nested: body
|
|Top-level paragraph once more.
|
| > A quotation from someone famous might be rendered something like
|   this.  As you can see, it is inset somewhat from the surrounding
|   text. - ''Donal K. Fellows <[email protected]>''
|
|And back to the top-level yet again.  Now we show off both ''italic''
|and '''bold''' text.
|
|----

and the rendered result

 * This is a paragraph

 > * This is an inner paragraph
     that goes onto two lines.

 > > * This one's even further in!

 > > * So's this one.

 > * Out again

 > > And a second paragraph here...

 > * Yet another item.

 * Outermost level once more.

 1. Enumerate?

 > 1. Deeper?

 2. Out again?

 list item: body text that is relatively long so that we can tell
   that it laps round properly as a paragraph even though this takes a
   ridiculous amount of text on my browser...

| VERB IN LIST?

 > nested: body

Top-level paragraph once more.

 > A quotation from someone famous might be rendered something like
   this.  As you can see, it is inset somewhat from the surrounding
   text.  - ''Donal K. Fellows <[email protected]>''

And back to the top-level yet again.  Now we show off both ''italic''
and '''bold''' text.

----

''Examples of index generation and image paragraphs.''

Here is the code

|#index:
|
|#index:short
|
|#index: long
|
|#image:3example This is a test caption
|
|This is an example long TIP reference tip:3 that should be expanded in
|a renderer-specific way...
|
|This is an example non-reference - ''index[[3]]'' - that should not
|be rendered as a link (to this document or anywhere else) at all.
|Note that the dashes in the previous sentence (with whitespace on
|each side) are candidates for rendering as long dashes (em-dashes) on
|output-media which support this.
|
| Supported URLs: should be http, https, mailto, news, newsrc, ftp and
|   gopher.  Test here...
|
| > HTTP URL - http://purl.org/thecliff/tcl/wiki/
|
| > HTTP URL in brackets - [http://wiki.tcl.tk]
|
| > HTTPS URL - https://sourceforge.net/
|
| > FTP URL - ftp://src.doc.ic.ac.uk/packages/tcl/tcl/
|
| > NEWS URL - news:comp.lang.tcl
|
| > MAILTO URL - mailto:[email protected]?subject=TIP3
| 
| > Others (might not be valid links!) - gopher://info.mcc.ac.uk,
|   newsrc:2845823825

and here is the rendered result.

#index:

#index:short

#index: long

#image:3example This is a test caption

This is an example long TIP reference tip:3 that should be expanded in
a renderer-specific way...

This is an example non-reference - ''index[[3]]'' - that should not
be rendered as a link (to this document or anywhere else) at all.
Note that the dashes in the previous sentence (with whitespace on
each side) are candidates for rendering as long dashes (em-dashes) on
output-media which support this.

 Supported URLs: should be http, https, mailto, news, newsrc, ftp and
   gopher.  Test here...

 > HTTP URL - http://purl.org/thecliff/tcl/wiki/

 > HTTP URL in brackets - [http://wiki.tcl.tk]

 > HTTPS URL - https://sourceforge.net/

 > FTP URL - ftp://src.doc.ic.ac.uk/packages/tcl/tcl/

 > NEWS URL - news:comp.lang.tcl

 > MAILTO URL - mailto:[email protected]?subject=TIP3
 
 > Others (might not be valid links!) - gopher://info.mcc.ac.uk,
   newsrc:2845823825

----

''Examples of sections and subsections''

|~Section Heading
|
|Section text
|
|~~Subsection Heading
|
|Subsection text
|
|~~~Subsubsection Heading
|
|Subsubsection text

which renders as...

~Section Heading

Section text

~~Subsection Heading

Subsection text

~~~Subsubsection Heading

Subsubsection text

----

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|



|

















|



















|










|


|
|


|

|




|












|

















|







|


|

|












|




|


|
|



|
|
|


|
|




|

|



|






|
|








|
|

|
|


|
|




|
|



|
|






|
|






|



|


|

|
|






|


|
|

|
|




|

|

|

|
|


|


|


|
|




|

|











|

|
|




|
|


|
|
|
|
|


|

|



|


|



|

|
|
|



|
|
|


|






|







|
|









|









|


|
|
|

|







|



|
|

|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|





|


|

|

|

|

|





|







|

|





|

|
|



|



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|



|

|

|

|




|
|
|
|





|

|

|







|




|

|
|
|
|
|
|
|
|
|
|
|



|



|



|





|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585

# TIP 3: TIP Format

	Author:         Andreas Kupries <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Accepted
	Type:           Process
	Vote:           Done
	Created:        14-Sep-2000
	Post-History:
-----

# Abstract

This TIP is a companion document to the TIP Guidelines [[2]](2.md) and
describes the structure and formatting to use when writing a TIP.


# Rationale

The major goals of this document are to define a format that is

   * easy to write,

   * easy to read,

   * easy to search, and

   * acceptable to the community at large.

The latter is important because non-acceptance essentially means that
the TIP process will be stillborn. This not only means basically plain
text without much markup but also that we should reuse formats with
which people are already acquainted.

As the concept of TIPs borrows heavily from Python's PEPs
<http://python.sourceforge.net/peps/>  their definition on how to
structure and format a PEP was reviewed for its suitability of use by
the TCT and the community at large.

The major points of the format are:

   * Plain ASCII text without special markup for references or
     highlighting of important parts.

   * Mail-like header section containing the meta-information.

   * Uses indentation to distinguish section headers from section
     text.

A header section like is used in mail or news is something people are
acquainted with and fulfils the other criteria too. In addition it is
extendable. Using indentation to convey semantic and syntactic
information on the other hand is something Pythonistas are used to but
here in the Tcl world we are not to the same extent.

Looking at bit closer to home we find the Tcl'ers Wiki <http://wiki.tcl.tk/> 

It does use a plain text format with some very light formatting
conventions to allow things like links, images, enumerated and
itemized lists.

Given the rather high acceptance of this site by the community using
its format should be beneficiary to the acceptance of TIPs too.

It is therefore proposed to use a combination of a header in mail/news
style together with a body employing a slightly extended/modified Wiki
format \(mostly backward compatible\) as the format for TIPs. This
proposed format is specified in detail below.

_Note_ that the use of TAB characters within a TIP is discouraged
\(but permitted\) as some mailers \(notably Outlook Express\) make a mess
of them.  Please be considerate and avoid their use...

# Rejected Alternatives

But before we specify the format a \(short\) discussion of possible
alternatives and why they where rejected.

There were three primary competitors to the format specified below,
these are SGML/XML, HTML and a markup based upon plain text with
embedded tcl-commands, for example like ... [section Abstract] ...

   * The main disadvantage of SGML and XML based solutions is that
     they require a much more heavyweight infrastructure for editing
     and processing documents using them, like specialized editors and
     extensions for parsing. The format below on the other hand can be
     processed using pure tcl without extensions. with respect to the
     specialized editors it should be said that an editor operating on
     plain ASCII is possible too, but then the text will be difficult
     to read for humans because of the many occurrences of < and >,
     conflicting with the requirement to have an 'easy to read'
     format.

	   > While there are commercial products which can gloss over this,
     making the editing of XML fairly easy, not everyone currently has
     access to one or the desire to spend what might be quite a lot of
     money to acquire one.  It is far better to let everyone continue
     to use their current favourite plain-text editor.

   * The main problem of HTML is that it is focused on visual and
     not logical markup. This will make it, although not impossible,
     but very difficult to parse documents for automatic handling.  It
     is also a poor format for producing printed versions of the
     documentation from.  Experience has also shown that different
     people have widely different ideas about how the content of TIP
     documents should be rendered into HTML, an indication that using
     the language would prove problematic!  We can still use HTML as a
     generated format, but we should not write the documents
     themselves in it.

   * The approach of embedding tcl commands into the text of a TIP is
     \(at least\) as powerful as XML when it comes to automatic
     processing of documents but much more lightweight. Because of
     this it is seen as the best of the three rejected alternatives.
     It was rejected in the end because it was still seen as too
     heavyweight/demanding for the casual user with respect to
     learning, easy writing and reading.


# Header Format

The general format of the header for a TIP is specified in RFC 822
<http://www.rfc-editor.org/rfc/rfc822.txt> . This leaves us to define
and explain the keywords, their meaning and their values.  The
following keywords are _required_, and unless otherwise stated,
should occur exactly once:

   TIP:
	The number of the TIP as assigned by the TIP editor.
	Unchangeable later on.

   Title:
	Defines the title of the document using plain text. May change
	during the discussion and review phases.

   Version:
	Specifies the version of the document.  Usually something like
	$Revision: 1.8 $. \(Initially $Revision: 1.8 $ should be used, which
	is then changed by the version control to contain the actual
	revision number.

   Author:
	Contact information \(email address\) for each author. The email
	address has to contain the real name of the author.  If there
	are multiple authors of the document, this header may occur
	multiple times \(once per author.\)  The format should be
	approximately like this:  _Firstname Lastname <emailaddress>_

   State:
	Defines the state the TIP is currently in. Allowed values are
	_Draft_, _Active_, _Accepted_, _Deferred_, _Final_,
	_Rejected_ and _Withdrawn_.  This list will be influenced
	by the finalization of the workflow in [[2]](2.md).

   Type:
	The type of the TIP.  Allowed values are _Process_,
	_Project_ and _Informative_. See [[2]](2.md) for more explanations
	about the various types.

   Vote:
	The current state of voting for the TIP.  Allowed values are
	_Pending_, _In progress_, _Done_ and _No voting_. The
	latter is used to indicate a TIP which doesn't require a vote,
	for example [[1]](1.md).

   Created:
	The date the TIP was created, in the format dd-mmm-yyyy.
	_mmm_ is the \(English\) short name of the month. The other
	information is numerical. Example: 14-Sep-2000

   >    All numeric dates, though more easily internationalised, are
        not used because the ordering of particularly the month and
        day is ambiguous and subject to some confusion between
        different locales.  Unix-style timestamps are unreadable to
        the majority of people \(as well as being over-precise,\) and I
        \(<[email protected]>\) don't know ISO 8601 well enough to
        be able to comment on it.

   Post-History:
	A list of the dates the document was posted to the mailing list
	for discussion.

   Tcl-Version:
	This indicates the version of Tcl that a Project TIP depends
	upon \(where it is required.\)  Process and Informative TIPs
	_must not_ have this keyword.

The following headers are _optional_ and should \(unless otherwise
stated\) occur at most once:

   Discussions-To:
	While a TIP is in private discussions \(usually during the
	initial Draft phase\), this header will indicate the mailing
	list or URL where the TIP is being discussed.

   Obsoletes:
	Indicates a TIP number that this TIP renders obsolete.
	\(Thanks to Joel Saunier <[email protected]> for
	suggesting this!\)

   Obsoleted-By:
	Indicates a TIP number that renders this TIP obsolete.
	\(Thanks to Joel Saunier <[email protected]> for
	suggesting this!\)

   Keywords:
	A comma-separated list of keywords relating to this TIP, to
	facilitate automated indexing and improve search engine
	results.

The following headers are _proposed_ \(by Donald G. Porter
<[email protected]>\) but not currently supported:

   Sponsor:
	A TCT member that is sponsoring this TIP.  May occur multiple
	times, once per sponsor.

   Supporter:
	A person \(not necessarily a TCT member\) who is supporting this
	TIP.  May occur multiple times, once per supporter.

   Objector:
	A person \(not necessarily a TCT member\) who is opposed to this
	TIP.  May occur multiple times, once per objector.

# Body Format

The body of a TIP is split by visually blank lines \(i.e. lines
containing nothing other than conventional whitespace\) into units that
will be called paragraphs.  Each paragraph is in one of the following
forms.

If the paragraph consists of exactly four minus symbols "----" then it
is a separator paragraph and should be rendered as a horizonal rule.

If the paragraph consists of a vertical bar "\|" followed by text, then
it is a verbatim paragraph.  The bar will be stripped from the front
of each line and the rest of the text will be formatted literally.
Tab characters will be expanded to 8-character boundaries.  \(_Note
that this is completely incompatible with the Tcl'ers Wiki._\)

If the paragraph consists of one or more tildes "~" \(which may be
space-separated\) followed by text, then it is
a section heading.  The text following is the name of the section.  In
the name of good style, the section heading should have its
significant words capitalised.  The number of tildes indicates whether
this is a section heading, a subsection heading or a subsubsection
heading \(one, two or three tildes respectively.\)

If the paragraph consists of the sequence "\#index:" followed by some
optional text, then it is a request to insert an index.  The text
following \(after trimming spaces\) indicates the kind of index desired.
The default is a "medium" index, and fully compliant implementations
should support "short" \(expected to contain less detail\) and "long"
\(expected to contain all header details plus the abstract\) as well.
Support for other kinds of indices is optional.

If the paragraph consists of the sequence "\#image:" followed by some
text, then it is a request to insert an image.  The first word of the
following text is a reference to the image, and the other words are
an optional caption for the image \(in plain text.\)  Image references
that consist of just letters, numbers, hyphens and underscores are
handled specially by the current implementation, which can map them to
the correct media type for its current output format \(assuming it has
a suitable image in its repository.\)

All other paragraphs that start with a non-whitespace character are
ordinary paragraphs.

If a paragraph starts with a whitespace character sequence \(use three
spaces and keep the whole paragraph on a single line if you want
compatability with the Tcl'ers Wiki,\) a star "\*" and another
whitespace character, it is an item in a bulleted list.

If a paragraph starts with a whitespace character sequence, a number,
a full stop "." and another whitespace character, it is an item in an
enumerated list.  If the number is 1 then the number of the item is
guessed from the current list context, and any other value sets the
number explicitly.  If you want compatability with the Tcl'ers Wiki,
make the initial whitespace sequence be three spaces, the number be 1,
and keep the whole paragraph on a single line.

If a paragraph starts with a whitespace character sequence, some text
\(that includes no tabs or newlines but can include spaces\), a colon
and another whitespace character, then it is an item in a descriptive
\(a.k.a. definition\) list.  The item being described cannot contain
advanced formatting \(including any kind of emphasis\) because this is
not supported by all formats that a TIP may be viewed in.

If a paragraph does not start with a whitespace character sequence, a
greater than symbol ">", and then another whitespace character, it is
also an ordinary paragraph.  \(_Note that this is completely
incompatible with the Tcl'ers Wiki._\)

Where a paragraph does begin with the sequence described in the
preceding paragraph, it is a nested list item \(if the paragraph
contained is a list item\) or a subsequent paragraph \(if the paragraph
contained is an ordinary paragraph.\)  If there's no suitable
"enclosing" list context \(i.e. if the preceding paragraph was not part
of a list\) the paragraph will be a quotation instead.  \(The rules for
these continuation paras seem complex at first glance, but seem to
work out fairly well in practise, especially since they are only
rarely used.\)

Within the body text of a \(non-verbatim\) paragraph, there are two
styles of emphasis:

 * italicised emphasis is indicated by enclosing the text within
   inside double apostrophes "_"

 * emboldened emphasis is indicated by enclosing the text within
   inside triple apostrophes "**".

The two emphasis styles should not be nested. Special URLs of
the form tip:tipnumber are expanded into full URLs to the given TIP
through the current formatting engine \(where applicable.\)  References
of the form [tipnumber] are also expanded as links to the given TIP,
but are not displayed as URLs \(the expansion is format dependent, of
course.\)  Doubled up square brackets are converted into matching
single square brackets.  Email addresses \(of the form <email@address>\)
and ordinary URLs in single square brackets might also be treated specially.

The first paragraph of the body of any TIP must be an abstract section
title \("~Abstract" or "~ Abstract"\), and the second must be an
ordinary paragraph \(and should normally be just plain text, to make
processing by tools easier.\)

You can compare these rules with those for the Tcl'ers Wiki which are
described at <http://wiki.tcl.tk/14.html,> with the
following modifications:

   1. The text for an item in an itemized, enumerated or tagged list
      can be split over multiple physical lines. The text of the item
      will reach until the next empty line.

   1. All paragraphs _must_ be split with whitespace.  This is a
      corollary of the above item.

   1. A paragraph starting with the character ~ is interpreted as a
      section heading.  Consequently it should be very short so that
      it renders onto a single line under most circumstances.

   1. A full verbatim mode is added. Any line starting with the bar
      character is reproduced essentially verbatim \(the bar character
      is removed\). This allows embedding of code or other texts
      containing formatting usually recognized as special by the
      formatter without triggering this special processing. This
      applies especially to brackets and the hyperlinking they provide
      and their role in tcl code.  This is used in preference to the
      whitespace rule of the Tcl'ers Wiki which is potentially far
      more sensitive.  Our rule makes it extremely obvious what lines
      are verbatim, and what those lines will be rendered as.

   1. Only one style of emphasis within paragraphs is supported.
      Having multiple emphasis styles \(italic and bold\) not only fails
      to carry across well in all media, but also makes for confusion
      on the part of authors and is more difficult to write renderers
      for too.

   1. Images are only supported in a limited way, since under HTML the
      support for images varies a lot more than most people would like
      to think, and the concept of an inline image can vary quite a
      lot between different rendered formats too.

# Reference Implementation

A reference renderer was created by Donal Fellows
<[email protected]> and is installed \(as a behind-the-scenes
rendering engine\) on a set of TIP documents
<http://www.cs.man.ac.uk/fellowsd-bin/TIP>  with the source code to the
rendering engine being available
<http://sf.net/projects/tiprender/> 

Note that this code does support nested lists and multi-paragraph
items, but this is experimental right now. Examples are presented
behind the code itself.

----

# Examples

This document itself is an example of the new format.

_Examples for nested lists, multi-paragraph items in list's, and
quotations._

Here is the source \(itself a demonstration of verbatim text\)

	 * This is a paragraph
	
	 > * This is an inner paragraph
	     that goes onto two lines.
	
	 > > * This one's even further in!
	
	 > > * So's this one.
	
	 > * Out again
	
	 > > And a second paragraph here...
	
	 > * Yet another item.
	
	 * Outermost level once more.
	
	 1. Enumerate?
	
	 > 1. Deeper?
	
	 2. Out again?
	
	 list item: body text that is relatively long so that we can tell
	   that it laps round properly as a paragraph even though this takes a
	   ridiculous amount of text on my browser...
	
	| VERB IN LIST?
	
	 > nested: body
	
	Top-level paragraph once more.
	
	 > A quotation from someone famous might be rendered something like
	   this.  As you can see, it is inset somewhat from the surrounding
	   text. - ''Donal K. Fellows <[email protected]>''
	
	And back to the top-level yet again.  Now we show off both ''italic''
	and '''bold''' text.
	
	----

and the rendered result

 * This is a paragraph

	 > \* This is an inner paragraph
     that goes onto two lines.

	 > > \* This one's even further in!

	 > > \* So's this one.

	 > \* Out again

	 > > And a second paragraph here...

	 > \* Yet another item.

 * Outermost level once more.

 1. Enumerate?

	 > 1. Deeper?

 2. Out again?

 list item: body text that is relatively long so that we can tell
   that it laps round properly as a paragraph even though this takes a
   ridiculous amount of text on my browser...

		 VERB IN LIST?

	 > nested: body

Top-level paragraph once more.

 > A quotation from someone famous might be rendered something like
   this.  As you can see, it is inset somewhat from the surrounding
   text.  - _Donal K. Fellows <[email protected]>_

And back to the top-level yet again.  Now we show off both _italic_
and **bold** text.

----

_Examples of index generation and image paragraphs._

Here is the code

	#index:
	
	#index:short
	
	#index: long
	
	#image:3example This is a test caption
	
	This is an example long TIP reference tip:3 that should be expanded in
	a renderer-specific way...
	
	This is an example non-reference - ''index[[3]]'' - that should not
	be rendered as a link (to this document or anywhere else) at all.
	Note that the dashes in the previous sentence (with whitespace on
	each side) are candidates for rendering as long dashes (em-dashes) on
	output-media which support this.
	
	 Supported URLs: should be http, https, mailto, news, newsrc, ftp and
	   gopher.  Test here...
	
	 > HTTP URL - http://purl.org/thecliff/tcl/wiki/
	
	 > HTTP URL in brackets - [http://wiki.tcl.tk]
	
	 > HTTPS URL - https://sourceforge.net/
	
	 > FTP URL - ftp://src.doc.ic.ac.uk/packages/tcl/tcl/
	
	 > NEWS URL - news:comp.lang.tcl
	
	 > MAILTO URL - mailto:[email protected]?subject=TIP3
	 
	 > Others (might not be valid links!) - gopher://info.mcc.ac.uk,
	   newsrc:2845823825

and here is the rendered result.

\#index:

\#index:short

\#index: long

![This is a test caption](../assets/3example.gif)

This is an example long TIP reference tip:3 that should be expanded in
a renderer-specific way...

This is an example non-reference - _index[[3]](3.md)_ - that should not
be rendered as a link \(to this document or anywhere else\) at all.
Note that the dashes in the previous sentence \(with whitespace on
each side\) are candidates for rendering as long dashes \(em-dashes\) on
output-media which support this.

 Supported URLs: should be http, https, mailto, news, newsrc, ftp and
   gopher.  Test here...

 > HTTP URL - <http://purl.org/thecliff/tcl/wiki/>

 > HTTP URL in brackets - <http://wiki.tcl.tk> 

 > HTTPS URL - <https://sourceforge.net/>

 > FTP URL - ftp://src.doc.ic.ac.uk/packages/tcl/tcl/

 > NEWS URL - news:comp.lang.tcl

 > MAILTO URL - mailto:[email protected]?subject=TIP3
 
 > Others \(might not be valid links!\) - gopher://info.mcc.ac.uk,
   newsrc:2845823825

----

_Examples of sections and subsections_

	~Section Heading
	
	Section text
	
	~~Subsection Heading
	
	Subsection text
	
	~~~Subsubsection Heading
	
	Subsubsection text

which renders as...

# Section Heading

Section text

## Subsection Heading

Subsection text

### Subsubsection Heading

Subsubsection text

----

# Copyright

This document has been placed in the public domain.

Name change from tip/30.tip to tip/30.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324

TIP:            30
Title:          Tk Toolkit Maintainer Assignments
Version:        $Revision: 1.46 $
Author:         Don Porter <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         Jan Nijtmans <[email protected]>
Author:         Todd M. Helfter <[email protected]>
Author:         Chengye Mao <[email protected]>
Author:         George B. Smith <[email protected]>
Author:         Miguel Ba��n <[email protected]>
Author:         Daniel Steffen <[email protected]>
Author:         Peter Spjuth <[email protected]>
Author:         Jeff Hobbs <[email protected]>
Author:         Vince Darley <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         Benjamin Riefenstahl <[email protected]>
Author:         Pat Thoyts <[email protected]>
Author:         Vince Darley <[email protected]>
Author:         Peter Spjuth <[email protected]>
State:          Draft
Type:           Informative
Vote:           Pending
Created:        09-Mar-2001
Post-History:   


~ Abstract

This document keeps a record of who maintains each functional area
of Tk ([23]).

~ Assignments

Listed below are Tk's functional units, in the same order as in
[23].  See [23] for the precise definition of what code belongs to
what area, and how maintainers designate their support for
platform-specific portions of the code.  The area names listed below
are also the Categories in the SourceForge Tracker for the Tk Toolkit
[http://sourceforge.net/tracker/?group_id=12997].

For each of Tk's functional units, the following maintainers are 
assigned:

   1. ''Bindings'' - Jeff Hobbs <[email protected]>

   2. ''Appearance'' - Jeff Hobbs <[email protected]>,
                       Daniel Steffen <[email protected]> (Mac OS X),
                       Jim Ingham <[email protected]> (Mac OS X)

   3. ''[*button] and [label]'' - Allen Flick <[email protected]>,
				  Jeff Hobbs <[email protected]>,
                                  Daniel Steffen <[email protected]> (Mac OS X),
                                  Jim Ingham <[email protected]> (Mac OS X),
                                  Vincent Darley <[email protected]> (Mac OS X)

   4. ''Canvas Basics'' - Jeff Hobbs <[email protected]>,
			  Jan Nijtmans <[email protected]>

   5. ''Canvas Items'' - Jeff Hobbs <[email protected]>,
			 Jan Nijtmans <[email protected]>

   6. ''Canvas PostScript'' - Jeff Hobbs <[email protected]>

   7. ''[entry]'' - Allen Flick <[email protected]>,
		    Jeff Hobbs <[email protected]>

   8. ''[frame] and [toplevel]'' - Jeff Hobbs <[email protected]>,
			Peter Spjuth <[email protected]>

   9. ''[listbox]'' - Allen Flick <[email protected]>,
		      Jeff Hobbs <[email protected]>

   10. ''Generic Menus'' - Jeff Hobbs <[email protected]>,
			   Todd Helfter <[email protected]>

   11. ''AquaMac OS X Menus'' - George B. Smith <[email protected]>,
                       Daniel Steffen <[email protected]>,
                       Jim Ingham <[email protected]>,
                       Vincent Darley <[email protected]>

   12. ''Unix Menus'' - Jeff Hobbs <[email protected]>,
			Todd Helfter <[email protected]>

   13. ''Win Menus'' - Jeff Hobbs <[email protected]>,
		       Todd Helfter <[email protected]>

   14. ''[message]'' - Jeff Hobbs <[email protected]>

   15. ''[scale]'' - Jeff Hobbs <[email protected]>,
                     Daniel Steffen <[email protected]> (Mac OS X),
                     Jim Ingham <[email protected]> (Mac OS X)

   16. ''[scrollbar]'' - Jeff Hobbs <[email protected]>,
                         Daniel Steffen <[email protected]> (Mac OS X),
                         Jim Ingham <[email protected]> (Mac OS X)

   17. ''[spinbox]'' - Jeff Hobbs <[email protected]>

   18. ''[text]'' - Jeff Hobbs <[email protected]>, Vince Darley <[email protected]>

   19. ''Menubars (obsolete)'' - Jeff Hobbs <[email protected]>

   20. ''[tk_optionMenu]'' - Jeff Hobbs <[email protected]>

   21. ''[panedwindow]'' - Jeff Hobbs <[email protected]>

   22. ''Style Engine'' - Fr�d�ric Bonnet <[email protected]>

   23. ''Option Parsing'' - Jeff Hobbs <[email protected]>,
                            Daniel Steffen <[email protected]> (Mac OS X),
                            Jim Ingham <[email protected]> (Mac OS X)

   24. ''Relief'' - Jeff Hobbs <[email protected]>,
		    Fr�d�ric Bonnet <[email protected]>

   25. ''Built-in Bitmaps'' - Jeff Hobbs <[email protected]>,
			      Jan Nijtmans <[email protected]>,
                              Daniel Steffen <[email protected]> (Mac OS X),
                              Jim Ingham <[email protected]> (Mac OS X)

   26. ''Conversions From String'' - Jeff Hobbs <[email protected]>

   27. ''Objects'' -  Jeff Hobbs <[email protected]>

   28. ''Utility Functions'' - Jeff Hobbs <[email protected]>

   29. ''Colormaps and Visuals'' - Jeff Hobbs <[email protected]>

   30. ''Color Names'' - Jeff Hobbs <[email protected]>,
                         Daniel Steffen <[email protected]> (Mac OS X),
                         Jim Ingham <[email protected]> (Mac OS X)

   31. ''Cursor Names'' - Jeff Hobbs <[email protected]>,
                          Daniel Steffen <[email protected]> (Mac OS X),
                          Jim Ingham <[email protected]> (Mac OS X)

   32. ''Key Symbols'' - Jeff Hobbs <[email protected]>,
                         Daniel Steffen <[email protected]> (Mac OS X),
                         Jim Ingham <[email protected]> (Mac OS X),
			 Benjamin Riefenstahl <[email protected]> (Mac OS X)

   33. ''Generic Dialog Support'' - Donal K. Fellows <[email protected]>,
				    Jeff Hobbs <[email protected]>

   34. ''[tk_chooseColor]'' - Donal K. Fellows <[email protected]> (Unix),
			      Jeff Hobbs <[email protected]>

   35. ''[tk_dialog]'' - Donal K. Fellows <[email protected]> (Unix),
			 Jeff Hobbs <[email protected]>,
                         Daniel Steffen <[email protected]> (Mac OS X),
                         Jim Ingham <[email protected]> (Mac OS X)

   36. ''[tk_chooseDirectory]'' - Donal K. Fellows <[email protected]> (Unix),
				  Jeff Hobbs <[email protected]>

   37. ''[tk_get*File]'' - Donal K. Fellows <[email protected]> (Unix),
			   Jeff Hobbs <[email protected]>

   38. ''[tk_messageBox]'' - Donal K. Fellows <[email protected]> (Unix),
			     Jeff Hobbs <[email protected]>

   39. ''Image Basics'' - Jan Nijtmans <[email protected]>,
			  Donal K. Fellows <[email protected]>

   40. ''Bitmap Images'' - Jan Nijtmans <[email protected]>,
			   Kevin Griffin <[email protected]>

   41. ''Photo Images'' - Jan Nijtmans <[email protected]>,
			  Donal K. Fellows <[email protected]>

   42. ''Photo Image|GIF'' - Jan Nijtmans <[email protected]>

   43. ''Photo Image|PPM'' - Jan Nijtmans <[email protected]>,
			     Donal K. Fellows <[email protected]>

   44. ''Generic Fonts'' - Jeff Hobbs <[email protected]>

   45. ''Aqua Fonts'' - George B. Smith <[email protected]>,
                       Daniel Steffen <[email protected]>,
                       Jim Ingham <[email protected]>,
		       Benjamin Riefenstahl <[email protected]>

   46. ''Unix Fonts'' - Jeff Hobbs <[email protected]>

   47. ''Win Fonts'' - Jeff Hobbs <[email protected]>,
		       Pat Thoyts <[email protected]>

   48. ''Geometry Management'' - Jeff Hobbs <[email protected]>,
				 Chengye Mao <[email protected]>

   49. ''[grid]'' - Jeff Hobbs <[email protected]>,
		    Peter Spjuth <[email protected]>

   50. ''[pack]'' - Jeff Hobbs <[email protected]>,
		    Peter Spjuth <[email protected]>

   51. ''[place]'' - Jeff Hobbs <[email protected]>,
		     Peter Spjuth <[email protected]>

   52. ''[clipboard]'' - Jeff Hobbs <[email protected]>
		         Joe English <[email protected]> (Unix),
                         Daniel Steffen <[email protected]> (Mac OS X),
                         Jim Ingham <[email protected]> (Mac OS X)

   53. ''[selection]'' - Jeff Hobbs <[email protected]>,
		         Joe English <[email protected]> (Unix)

   54. ''[console]'' - Jeff Hobbs <[email protected]>,
		       Chengye Mao <[email protected]>

   55. ''[focus]'' - Jeff Hobbs <[email protected]>

   56. ''[grab]'' - Jeff Hobbs <[email protected]>

   57. ''[option]'' - Allen Flick <[email protected]>,
		      Jeff Hobbs <[email protected]>

   58. ''[send]'' - Allen Flick <[email protected]>,
		    Jeff Hobbs <[email protected]>,
                    Daniel Steffen <[email protected]> (Mac OS X),
                    Jim Ingham <[email protected]> (Mac OS X),
		    Pat Thoyts <[email protected]>

   59. ''[tk_focus*]'' - Jeff Hobbs <[email protected]>

   60. ''[tk_setPalette]'' - Jeff Hobbs <[email protected]>

   61. ''Safe Tk'' - Jeff Hobbs <[email protected]>

   62. ''Geometry Functions'' - Jeff Hobbs <[email protected]>,
				Chengye Mao <[email protected]>

   63. ''Tk_Win Functions'' - Jeff Hobbs <[email protected]>

   64. ''Graphic Contexts'' - Jeff Hobbs <[email protected]>

   65. ''Generic Window Operations'' - Jeff Hobbs <[email protected]>

   66. ''Aqua Window Operations'' - George B. Smith <[email protected]>,
                                   Daniel Steffen <[email protected]>,
                                   Jim Ingham <[email protected]>,
                                   Vincent Darley <[email protected]>

   67. ''Unix Window Operations'' - Jeff Hobbs <[email protected]>,
				    Joe English <[email protected]>

   68. ''Win Window Operations'' - Jeff Hobbs <[email protected]>,
				   Chengye Mao <[email protected]>
                                   Vincent Darley (maintainer for wm iconbitmap only) <[email protected]>

   69. ''Events'' - Jeff Hobbs <[email protected]>

   70. ''Event Loop'' - Jeff Hobbs <[email protected]>,
			Jan Nijtmans <[email protected]>

   71. ''Error Handling'' - Jeff Hobbs <[email protected]>

   72. ''Atoms'' - Jeff Hobbs <[email protected]>

   73. ''Argv Parsing'' - Jeff Hobbs <[email protected]>

   74. ''Application Embedding'' - 
		Daniel Steffen <[email protected]> (Mac OS X),
		Jim Ingham <[email protected]> (Mac OS X),
		Don Porter <[email protected]>

   75. ''wish'' - 
                  Daniel Steffen <[email protected]> (Mac OS X),
                  Jim Ingham <[email protected]> (Mac OS X),

   76. ''Widget Tour'' - Donal K. Fellows <[email protected]>,
			 Jeff Hobbs <[email protected]>

   77. ''Square Demo'' - Jeff Hobbs <[email protected]>

   78. ''Other Demos'' - Donal K. Fellows <[email protected]>,
			 Jeff Hobbs <[email protected]>

   79. ''L10N'' - Jan Nijtmans <[email protected]>,
		  Miguel Ba��n <[email protected]>

   80. ''Release Notes'' - Jeff Hobbs <[email protected]>

   81. ''Portability'' - Jeff Hobbs <[email protected]>

   82. ''X11 Emulation'' - Jeff Hobbs <[email protected]>

   83. ''Mac OS X Build'' - George B. Smith <[email protected]>,
                       Daniel Steffen <[email protected]>,
                       Jim Ingham <[email protected]>,

   84. ''Unix Build'' - Jeff Hobbs <[email protected]>,
			Mo DeJong <[email protected]>,
			Lloyd Lim <[email protected]>

   85. ''Win Build'' - Jeff Hobbs <[email protected]>,
		       Mo DeJong <[email protected]>,
		       Pat Thoyts <[email protected]>

   86. ''Test Tools'' - Allen Flick <[email protected]>,
			Jeff Hobbs <[email protected]>,
                        Daniel Steffen <[email protected]> (Mac OS X),
                        Jim Ingham <[email protected]> (Mac OS X)

   87. ''Logos'' - Jeff Hobbs <[email protected]>
                   Daniel Steffen <[email protected]> (Mac OS X),
                   Jim Ingham <[email protected]> (Mac OS X),

~ General Categories

The  following categories in Tk's SourceForge Tracker do not refer to any
specific portion of Tk.  Reports in these categories should be mapped to
categories corresponding to a maintained area of Tk, when seeking the
appropriate maintainer:

   1. ''Other'' - Reports that span multiple categories.

~ Areas Without Maintainers

Those functional areas without a maintainer are maintained by the Tcl 
Core Team with each change requiring TYANNOTT review.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>

|


|

|


|



|




|

|
|
|

|

|
|
|

|


|


|

|


|


|


|


|




|


|


|

|
|
|

|
|
|

|

|

|

|

|

|

|
|
|

|
|

|

|
|

|

|

|

|

|
|
|

|
|
|

|
|
|
|

|


|


|

|
|

|


|


|


|


|


|


|

|


|

|




|

|


|


|


|


|


|
|
|
|

|
|

|


|

|

|


|

|
|


|

|

|

|


|

|

|

|




|


|

|

|

|


|

|

|

|
|
|


|
|
|

|


|

|


|
|

|

|

|

|



|



|



|

|
|

|
|
|

|






|

|




|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324

# TIP 30: Tk Toolkit Maintainer Assignments

	Author:         Don Porter <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         Jan Nijtmans <[email protected]>
	Author:         Todd M. Helfter <[email protected]>
	Author:         Chengye Mao <[email protected]>
	Author:         George B. Smith <[email protected]>
	Author:         Miguel Bañón <[email protected]>
	Author:         Daniel Steffen <[email protected]>
	Author:         Peter Spjuth <[email protected]>
	Author:         Jeff Hobbs <[email protected]>
	Author:         Vince Darley <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         Benjamin Riefenstahl <[email protected]>
	Author:         Pat Thoyts <[email protected]>
	Author:         Vince Darley <[email protected]>
	Author:         Peter Spjuth <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        09-Mar-2001
	Post-History:   
-----

# Abstract

This document keeps a record of who maintains each functional area
of Tk \([[23]](23.md)\).

# Assignments

Listed below are Tk's functional units, in the same order as in
[[23]](23.md).  See [[23]](23.md) for the precise definition of what code belongs to
what area, and how maintainers designate their support for
platform-specific portions of the code.  The area names listed below
are also the Categories in the SourceForge Tracker for the Tk Toolkit
<http://sourceforge.net/tracker/?group_id=12997> .

For each of Tk's functional units, the following maintainers are 
assigned:

   1. _Bindings_ - Jeff Hobbs <[email protected]>

   2. _Appearance_ - Jeff Hobbs <[email protected]>,
                       Daniel Steffen <[email protected]> \(Mac OS X\),
                       Jim Ingham <[email protected]> \(Mac OS X\)

   3. _[*button] and [label]_ - Allen Flick <[email protected]>,
				  Jeff Hobbs <[email protected]>,
                                  Daniel Steffen <[email protected]> \(Mac OS X\),
                                  Jim Ingham <[email protected]> \(Mac OS X\),
                                  Vincent Darley <[email protected]> \(Mac OS X\)

   4. _Canvas Basics_ - Jeff Hobbs <[email protected]>,
			  Jan Nijtmans <[email protected]>

   5. _Canvas Items_ - Jeff Hobbs <[email protected]>,
			 Jan Nijtmans <[email protected]>

   6. _Canvas PostScript_ - Jeff Hobbs <[email protected]>

   7. _[entry]_ - Allen Flick <[email protected]>,
		    Jeff Hobbs <[email protected]>

   8. _[frame] and [toplevel]_ - Jeff Hobbs <[email protected]>,
			Peter Spjuth <[email protected]>

   9. _[listbox]_ - Allen Flick <[email protected]>,
		      Jeff Hobbs <[email protected]>

   10. _Generic Menus_ - Jeff Hobbs <[email protected]>,
			   Todd Helfter <[email protected]>

   11. _AquaMac OS X Menus_ - George B. Smith <[email protected]>,
                       Daniel Steffen <[email protected]>,
                       Jim Ingham <[email protected]>,
                       Vincent Darley <[email protected]>

   12. _Unix Menus_ - Jeff Hobbs <[email protected]>,
			Todd Helfter <[email protected]>

   13. _Win Menus_ - Jeff Hobbs <[email protected]>,
		       Todd Helfter <[email protected]>

   14. _[message]_ - Jeff Hobbs <[email protected]>

   15. _[scale]_ - Jeff Hobbs <[email protected]>,
                     Daniel Steffen <[email protected]> \(Mac OS X\),
                     Jim Ingham <[email protected]> \(Mac OS X\)

   16. _[scrollbar]_ - Jeff Hobbs <[email protected]>,
                         Daniel Steffen <[email protected]> \(Mac OS X\),
                         Jim Ingham <[email protected]> \(Mac OS X\)

   17. _[spinbox]_ - Jeff Hobbs <[email protected]>

   18. _[text]_ - Jeff Hobbs <[email protected]>, Vince Darley <[email protected]>

   19. _Menubars \(obsolete\)_ - Jeff Hobbs <[email protected]>

   20. _[tk_optionMenu]_ - Jeff Hobbs <[email protected]>

   21. _[panedwindow]_ - Jeff Hobbs <[email protected]>

   22. _Style Engine_ - Frédéric Bonnet <[email protected]>

   23. _Option Parsing_ - Jeff Hobbs <[email protected]>,
                            Daniel Steffen <[email protected]> \(Mac OS X\),
                            Jim Ingham <[email protected]> \(Mac OS X\)

   24. _Relief_ - Jeff Hobbs <[email protected]>,
		    Frédéric Bonnet <[email protected]>

   25. _Built-in Bitmaps_ - Jeff Hobbs <[email protected]>,
			      Jan Nijtmans <[email protected]>,
                              Daniel Steffen <[email protected]> \(Mac OS X\),
                              Jim Ingham <[email protected]> \(Mac OS X\)

   26. _Conversions From String_ - Jeff Hobbs <[email protected]>

   27. _Objects_ -  Jeff Hobbs <[email protected]>

   28. _Utility Functions_ - Jeff Hobbs <[email protected]>

   29. _Colormaps and Visuals_ - Jeff Hobbs <[email protected]>

   30. _Color Names_ - Jeff Hobbs <[email protected]>,
                         Daniel Steffen <[email protected]> \(Mac OS X\),
                         Jim Ingham <[email protected]> \(Mac OS X\)

   31. _Cursor Names_ - Jeff Hobbs <[email protected]>,
                          Daniel Steffen <[email protected]> \(Mac OS X\),
                          Jim Ingham <[email protected]> \(Mac OS X\)

   32. _Key Symbols_ - Jeff Hobbs <[email protected]>,
                         Daniel Steffen <[email protected]> \(Mac OS X\),
                         Jim Ingham <[email protected]> \(Mac OS X\),
			 Benjamin Riefenstahl <[email protected]> \(Mac OS X\)

   33. _Generic Dialog Support_ - Donal K. Fellows <[email protected]>,
				    Jeff Hobbs <[email protected]>

   34. _[tk_chooseColor]_ - Donal K. Fellows <[email protected]> \(Unix\),
			      Jeff Hobbs <[email protected]>

   35. _[tk_dialog]_ - Donal K. Fellows <[email protected]> \(Unix\),
			 Jeff Hobbs <[email protected]>,
                         Daniel Steffen <[email protected]> \(Mac OS X\),
                         Jim Ingham <[email protected]> \(Mac OS X\)

   36. _[tk_chooseDirectory]_ - Donal K. Fellows <[email protected]> \(Unix\),
				  Jeff Hobbs <[email protected]>

   37. _[tk_get*File]_ - Donal K. Fellows <[email protected]> \(Unix\),
			   Jeff Hobbs <[email protected]>

   38. _[tk_messageBox]_ - Donal K. Fellows <[email protected]> \(Unix\),
			     Jeff Hobbs <[email protected]>

   39. _Image Basics_ - Jan Nijtmans <[email protected]>,
			  Donal K. Fellows <[email protected]>

   40. _Bitmap Images_ - Jan Nijtmans <[email protected]>,
			   Kevin Griffin <[email protected]>

   41. _Photo Images_ - Jan Nijtmans <[email protected]>,
			  Donal K. Fellows <[email protected]>

   42. _Photo Image\|GIF_ - Jan Nijtmans <[email protected]>

   43. _Photo Image\|PPM_ - Jan Nijtmans <[email protected]>,
			     Donal K. Fellows <[email protected]>

   44. _Generic Fonts_ - Jeff Hobbs <[email protected]>

   45. _Aqua Fonts_ - George B. Smith <[email protected]>,
                       Daniel Steffen <[email protected]>,
                       Jim Ingham <[email protected]>,
		       Benjamin Riefenstahl <[email protected]>

   46. _Unix Fonts_ - Jeff Hobbs <[email protected]>

   47. _Win Fonts_ - Jeff Hobbs <[email protected]>,
		       Pat Thoyts <[email protected]>

   48. _Geometry Management_ - Jeff Hobbs <[email protected]>,
				 Chengye Mao <[email protected]>

   49. _[grid]_ - Jeff Hobbs <[email protected]>,
		    Peter Spjuth <[email protected]>

   50. _[pack]_ - Jeff Hobbs <[email protected]>,
		    Peter Spjuth <[email protected]>

   51. _[place]_ - Jeff Hobbs <[email protected]>,
		     Peter Spjuth <[email protected]>

   52. _[clipboard]_ - Jeff Hobbs <[email protected]>
		         Joe English <[email protected]> \(Unix\),
                         Daniel Steffen <[email protected]> \(Mac OS X\),
                         Jim Ingham <[email protected]> \(Mac OS X\)

   53. _[selection]_ - Jeff Hobbs <[email protected]>,
		         Joe English <[email protected]> \(Unix\)

   54. _[console]_ - Jeff Hobbs <[email protected]>,
		       Chengye Mao <[email protected]>

   55. _[focus]_ - Jeff Hobbs <[email protected]>

   56. _[grab]_ - Jeff Hobbs <[email protected]>

   57. _[option]_ - Allen Flick <[email protected]>,
		      Jeff Hobbs <[email protected]>

   58. _[send]_ - Allen Flick <[email protected]>,
		    Jeff Hobbs <[email protected]>,
                    Daniel Steffen <[email protected]> \(Mac OS X\),
                    Jim Ingham <[email protected]> \(Mac OS X\),
		    Pat Thoyts <[email protected]>

   59. _[tk_focus*]_ - Jeff Hobbs <[email protected]>

   60. _[tk_setPalette]_ - Jeff Hobbs <[email protected]>

   61. _Safe Tk_ - Jeff Hobbs <[email protected]>

   62. _Geometry Functions_ - Jeff Hobbs <[email protected]>,
				Chengye Mao <[email protected]>

   63. _Tk\_Win Functions_ - Jeff Hobbs <[email protected]>

   64. _Graphic Contexts_ - Jeff Hobbs <[email protected]>

   65. _Generic Window Operations_ - Jeff Hobbs <[email protected]>

   66. _Aqua Window Operations_ - George B. Smith <[email protected]>,
                                   Daniel Steffen <[email protected]>,
                                   Jim Ingham <[email protected]>,
                                   Vincent Darley <[email protected]>

   67. _Unix Window Operations_ - Jeff Hobbs <[email protected]>,
				    Joe English <[email protected]>

   68. _Win Window Operations_ - Jeff Hobbs <[email protected]>,
				   Chengye Mao <[email protected]>
                                   Vincent Darley \(maintainer for wm iconbitmap only\) <[email protected]>

   69. _Events_ - Jeff Hobbs <[email protected]>

   70. _Event Loop_ - Jeff Hobbs <[email protected]>,
			Jan Nijtmans <[email protected]>

   71. _Error Handling_ - Jeff Hobbs <[email protected]>

   72. _Atoms_ - Jeff Hobbs <[email protected]>

   73. _Argv Parsing_ - Jeff Hobbs <[email protected]>

   74. _Application Embedding_ - 
		Daniel Steffen <[email protected]> \(Mac OS X\),
		Jim Ingham <[email protected]> \(Mac OS X\),
		Don Porter <[email protected]>

   75. _wish_ - 
                  Daniel Steffen <[email protected]> \(Mac OS X\),
                  Jim Ingham <[email protected]> \(Mac OS X\),

   76. _Widget Tour_ - Donal K. Fellows <[email protected]>,
			 Jeff Hobbs <[email protected]>

   77. _Square Demo_ - Jeff Hobbs <[email protected]>

   78. _Other Demos_ - Donal K. Fellows <[email protected]>,
			 Jeff Hobbs <[email protected]>

   79. _L10N_ - Jan Nijtmans <[email protected]>,
		  Miguel Bañón <[email protected]>

   80. _Release Notes_ - Jeff Hobbs <[email protected]>

   81. _Portability_ - Jeff Hobbs <[email protected]>

   82. _X11 Emulation_ - Jeff Hobbs <[email protected]>

   83. _Mac OS X Build_ - George B. Smith <[email protected]>,
                       Daniel Steffen <[email protected]>,
                       Jim Ingham <[email protected]>,

   84. _Unix Build_ - Jeff Hobbs <[email protected]>,
			Mo DeJong <[email protected]>,
			Lloyd Lim <[email protected]>

   85. _Win Build_ - Jeff Hobbs <[email protected]>,
		       Mo DeJong <[email protected]>,
		       Pat Thoyts <[email protected]>

   86. _Test Tools_ - Allen Flick <[email protected]>,
			Jeff Hobbs <[email protected]>,
                        Daniel Steffen <[email protected]> \(Mac OS X\),
                        Jim Ingham <[email protected]> \(Mac OS X\)

   87. _Logos_ - Jeff Hobbs <[email protected]>
                   Daniel Steffen <[email protected]> \(Mac OS X\),
                   Jim Ingham <[email protected]> \(Mac OS X\),

# General Categories

The  following categories in Tk's SourceForge Tracker do not refer to any
specific portion of Tk.  Reports in these categories should be mapped to
categories corresponding to a maintained area of Tk, when seeking the
appropriate maintainer:

   1. _Other_ - Reports that span multiple categories.

# Areas Without Maintainers

Those functional areas without a maintainer are maintained by the Tcl 
Core Team with each change requiring TYANNOTT review.

# Copyright

This document has been placed in the public domain.

Name change from tip/300.tip to tip/300.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

TIP:            300
Title:          Examine Glyph Substitution in the 'font actual' Command
Version:        $Revision: 1.4 $
Author:         Kevin B. Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        25-Nov-2006
Post-History:   
Tcl-Version:    8.5
Keywords:	Tk


~ Abstract

This TIP proposes enhancing the '''font actual''' command to allow determining
the actual font to be used when rendering a specific character.

~ Background

Tk, when rendering strings in a widget, often needs to augment the characters
in the requested font with characters borrowed from other fonts. As of the
date of this TIP, there is no way for a program to introspect this mechanism.
This ability has been requested by several user interface designers, because
the interfaces are often more attractive if the substitute fonts are used
directly, or simply to determine what font was chosen.

~ Proposed Change

This TIP proposes modifying the '''font actual''' command to have the syntax:

 > '''font actual''' ''font'' ?'''-displayof''' ''window''? ?''option''?
   ?'''--'''? ?''char''?

The ''font'', '''-displayof''' and ''option'' arguments are unchanged from the
current [font actual] command.

The '''--''' option marks the end of options. It is needed if ''option'' is
not supplied and ''char'' may be a hyphen, to distinguish ''char' from a
misspelt option.

The ''char'' option must be a single character.

The result of the command, if the ''char'' option is supplied, is the actual
font used to render the given character, rather than the base font.

~ Reference Implementation

A reference implementation for the proposed feature, including documentation
and test suite updates, is at SourceForge as Tk Patch #1602955.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|








|

|

|
|

|


|
|


|

|


|


|

|


>

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

# TIP 300: Examine Glyph Substitution in the 'font actual' Command

	Author:         Kevin B. Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        25-Nov-2006
	Post-History:   
	Tcl-Version:    8.5
	Keywords:	Tk
-----

# Abstract

This TIP proposes enhancing the **font actual** command to allow determining
the actual font to be used when rendering a specific character.

# Background

Tk, when rendering strings in a widget, often needs to augment the characters
in the requested font with characters borrowed from other fonts. As of the
date of this TIP, there is no way for a program to introspect this mechanism.
This ability has been requested by several user interface designers, because
the interfaces are often more attractive if the substitute fonts are used
directly, or simply to determine what font was chosen.

# Proposed Change

This TIP proposes modifying the **font actual** command to have the syntax:

 > **font actual** _font_ ?**-displayof** _window_? ?_option_?
   ?**--**? ?_char_?

The _font_, **-displayof** and _option_ arguments are unchanged from the
current [font actual] command.

The **--** option marks the end of options. It is needed if _option_ is
not supplied and _char_ may be a hyphen, to distinguish _char' from a
misspelt option.

The _char_ option must be a single character.

The result of the command, if the _char_ option is supplied, is the actual
font used to render the given character, rather than the base font.

# Reference Implementation

A reference implementation for the proposed feature, including documentation
and test suite updates, is at SourceForge as Tk Patch \#1602955.

# Copyright

This document has been placed in the public domain.

Name change from tip/301.tip to tip/301.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

TIP:            301
Title:          Split Bidirectional Channels For Half-Close
Version:        $Revision: 1.2 $
Author:         Alexandre Ferrieux <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        11-Dec-2006
Post-History:   
Tcl-Version:    8.6
Obsoleted-By:	332


~ Abstract

This TIP proposes to introduce a '''chan split''' command allowing to access
both sides of a bidirectional channel (r+ pipe, or socket) as separate Tcl
channels, in order to be able to close them separately. This would give Tcl
the same level of control that the OS enjoys on the lifetime of such
bidirectional connections.

~ Background

Bidirectional channels allow Tcl to make an efficient use of a "filter
process", by exchanging data back and forth over an abstract "single" channel.

However, this single channel abstraction comes with a too coarse-grained
'''close''' primitive. Indeed, it closes both directions simultaneously, while
it is often desirable to close "gracefully" the half-connection ''to'' the
filter process, leaving the return path open. The effect of such a half-close
is that the filter receives a bona fide EOF alone, without a nearly
simultaneous SIGPIPE on its write end if it happens to be writing at that
time. Moreover, if the filter is itself comprised of a pipeline of processes,
some of which doing buffered I/O, then this graceful EOF may be the only way
of flushing the chain and receiving back precious data.

This technique is supported by all modern OSes: for pipes there are actually
two separate file descriptors/handles, and it suffices to close() the write
side; for sockets, a single fd is used, but a specific syscall, shutdown(),
brings back the ability to half-close. Hence it is fairly natural for a
universal "OS glove" like Tcl to expose this universal feature.

~ Proposed Change

This TIP proposes to add a '''chan split''' subcommand to '''chan''', with the
syntax:

 > '''chan split''' ''channel''

The ''channel'' argument indicates the bidirectional channel to be split. The
command returns a two element list, with the first element being the name of
the channel that is open for reading only, and the second element being the
name of the channel that is open for writing only.

After calling [['''chan split''' ''channel'']], ''channel'' is still opened,
but now shares its internal descriptor(s)/handle(s) with the returned readable
and writable channel. Then, simple "reference counting" at the descriptor
level decides when a '''close''' translates into an actual close()/shutdown()
at the OS level: a descriptor is shut down only when all its Tcl-level
representatives have been closed.

As a consequence, the normal idiom for the graceful shutdown described above,
is to close the bidirectional channel immediately after splitting it. Later,
the sequence is initiated by closing the write side, then waiting for all data
and EOF on the read side:

|foreach {rch wch} [chan split $ch] break
|close $ch
|...
|# initiate graceful shutdown
|close $wch
|# get back final data
|set last [read $rch]
|close $rch

In the case of a pipe, the [[close $rch]] has the same semantics as [close
$ch] would have had, that is, waiting for the child's exit status, and raising
a Tcl exception if nonzero.

~ Rationale

I had initially only asked for an extension of '''close''', and Eric Hassold
brought up the superbly elegant idea of '''chan split'''. Later on, Neil
Madden came with the equally beautiful '''chan restrict''', which initially
won my preference. Only dirty concern for the amount of work needed vs.
actual uses, did make me regard the less ambitious '''chan split''' as a more
reasonable target (sorry for the change, Neil).

Also, it was suggested that the separation between the read and write side
could be exploited not only by '''close''', but also by '''fconfigure''',
e.g., to allow for a blocking-read/nonblocking-write, or different baudrates
for both directions of a serial port, etc. I feel those are possible later
extensions of '''chan split''', however their implementation may be much
harder than the '''close''' case, because (1) ioctls/fcntl() are not always
suited for separation, and (2) multiplexing them is not possible with Threads.

~ Reference Implementation

I have not yet written a reference implementation; I assume somebody with a
more fluent practice of the channel system implementation will do so more
efficiently. However, community feedback on news:comp.lang.tcl seems to
witness some interest in the concept. As a last resort, I can give it a try,
of course.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|




|





|
|








|
|



|

|


|

|




|
|

|








|
|
|
|
|
|
|
|

|



|

|
|
|

|
|


|


|
|
|

|







|


>

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

# TIP 301: Split Bidirectional Channels For Half-Close

	Author:         Alexandre Ferrieux <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        11-Dec-2006
	Post-History:   
	Tcl-Version:    8.6
	Obsoleted-By:	332
-----

# Abstract

This TIP proposes to introduce a **chan split** command allowing to access
both sides of a bidirectional channel \(r\+ pipe, or socket\) as separate Tcl
channels, in order to be able to close them separately. This would give Tcl
the same level of control that the OS enjoys on the lifetime of such
bidirectional connections.

# Background

Bidirectional channels allow Tcl to make an efficient use of a "filter
process", by exchanging data back and forth over an abstract "single" channel.

However, this single channel abstraction comes with a too coarse-grained
**close** primitive. Indeed, it closes both directions simultaneously, while
it is often desirable to close "gracefully" the half-connection _to_ the
filter process, leaving the return path open. The effect of such a half-close
is that the filter receives a bona fide EOF alone, without a nearly
simultaneous SIGPIPE on its write end if it happens to be writing at that
time. Moreover, if the filter is itself comprised of a pipeline of processes,
some of which doing buffered I/O, then this graceful EOF may be the only way
of flushing the chain and receiving back precious data.

This technique is supported by all modern OSes: for pipes there are actually
two separate file descriptors/handles, and it suffices to close\(\) the write
side; for sockets, a single fd is used, but a specific syscall, shutdown\(\),
brings back the ability to half-close. Hence it is fairly natural for a
universal "OS glove" like Tcl to expose this universal feature.

# Proposed Change

This TIP proposes to add a **chan split** subcommand to **chan**, with the
syntax:

 > **chan split** _channel_

The _channel_ argument indicates the bidirectional channel to be split. The
command returns a two element list, with the first element being the name of
the channel that is open for reading only, and the second element being the
name of the channel that is open for writing only.

After calling [**chan split** _channel_], _channel_ is still opened,
but now shares its internal descriptor\(s\)/handle\(s\) with the returned readable
and writable channel. Then, simple "reference counting" at the descriptor
level decides when a **close** translates into an actual close\(\)/shutdown\(\)
at the OS level: a descriptor is shut down only when all its Tcl-level
representatives have been closed.

As a consequence, the normal idiom for the graceful shutdown described above,
is to close the bidirectional channel immediately after splitting it. Later,
the sequence is initiated by closing the write side, then waiting for all data
and EOF on the read side:

	foreach {rch wch} [chan split $ch] break
	close $ch
	...
	# initiate graceful shutdown
	close $wch
	# get back final data
	set last [read $rch]
	close $rch

In the case of a pipe, the [close $rch] has the same semantics as [close
$ch] would have had, that is, waiting for the child's exit status, and raising
a Tcl exception if nonzero.

# Rationale

I had initially only asked for an extension of **close**, and Eric Hassold
brought up the superbly elegant idea of **chan split**. Later on, Neil
Madden came with the equally beautiful **chan restrict**, which initially
won my preference. Only dirty concern for the amount of work needed vs.
actual uses, did make me regard the less ambitious **chan split** as a more
reasonable target \(sorry for the change, Neil\).

Also, it was suggested that the separation between the read and write side
could be exploited not only by **close**, but also by **fconfigure**,
e.g., to allow for a blocking-read/nonblocking-write, or different baudrates
for both directions of a serial port, etc. I feel those are possible later
extensions of **chan split**, however their implementation may be much
harder than the **close** case, because \(1\) ioctls/fcntl\(\) are not always
suited for separation, and \(2\) multiplexing them is not possible with Threads.

# Reference Implementation

I have not yet written a reference implementation; I assume somebody with a
more fluent practice of the channel system implementation will do so more
efficiently. However, community feedback on news:comp.lang.tcl seems to
witness some interest in the concept. As a last resort, I can give it a try,
of course.

# Copyright

This document has been placed in the public domain.

Name change from tip/302.tip to tip/302.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

TIP:            302
Title:          Fix "after"'s Sensitivity To Adjustments Of System Clock
Version:        $Revision: 1.3 $
Author:         Alexandre Ferrieux <[email protected]>
Author:         Kevin Kenny <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        13-Dec-2006
Post-History:   
Keywords:       Tcl,time changes
Tcl-Version:    8.7


~ Abstract

Currently, '''after''' tasks can be drastically delayed or sped up simply by
adjusting the system clock. This is due to the implementation's use of an
''absolute'' target date based on the system clock. The idea of this TIP is to
use another timebase for this purpose: the count of ticks from boot, which is
not affected by system time adjustments.

~ Background

The basis of the implementation of '''after''' is, on each call to
'''vwait''', to compute the ''timeout'' argument to select() by difference
between the stored target date of the earliest event and the current system
date (''gettimeofday()''). This is perfect while the system date ticks
regularly. But if, say, the clock is set back by 5 minutes, then an after
handler scheduled 1 second ago which was just about to fire, will have 5
minutes yet to wait before its (unmodified) target date is reached. So, if
this handler was part of a 1-Hz periodic task, there will be a huge gap of
5:01 between two ticks at that point. If some other component is expecting
some kind of regularity, even with a conservative timeout of 10 times the
expected period, it ''will'' time out, decide the periodic task is dead, and
possibly take drastic action.

~ Proposed Change

This TIP proposes to use other timebases instead of gettimeofday() in the
vwait/after code: '''times()''' in unix, '''GetTickCount()''' in Windows.
These clocks suffer ''no'' sysadmin tinkering.

~ Potential Break Of Compatibility

It has been objected that ''some'' applications today may be using '''after'''
with an ''absolute'' spirit; IOW such apps are supposed to ''rely'' on the
fact that the after handler will fire when the system clock equals the target
date computed once for all when '''after''' was called. A prototype example
would be a crontab-like task, which would itself compute the offset by
difference between the target date and the current '''clock seconds'''.

~~ Arguments For Breaking It Anyway

 1. This ''absolute'' interpretation is far from being natural, because
    '''after''''s argument is an ''offset''.

 2. This technique is not usable for a longer range than 25 days (MAXINT
    milliseconds), so not applicable e.g. for a personal schedule.

 3. The '''overwhelming''' majority of uses of '''after''' takes the
    ''relative'' interpretation (periodic tasks, timeouts) and ''cannot'' work
    correctly today.

 4. If this TIP were implemented incompatibly (i.e. without a specific flag to
    '''after'''), those ''absolute-minded'' apps could simply be adapted
    ''and'' improved in both robustness and range by using a periodic task
    which polls '''clock seconds'''.

 5. There is little evidence that the total number of ''absolute-minded'' apps
    exceeds '''one''' (see discussion on news:comp.lang.tcl "[[after]] fooled
    by shifting date")

~ Syntax For Not Breaking It If Deemed Useful

Of course, if this supposed singleton is in fact many, or has enough weight to
preclude an improvement of the rest of Tcl timers, we can do:

 > '''after -robust''' ''millisecs''

or any other colorful option name. But in this case there is a high risk that:
''either'' '''after -robust''' becomes the dominant use, thus cluttering the
code in many places, ''or'' people remain largely unaware of the problem,
stick to the default '''after''', and space shuttles fall by dozens.

~ Escalation To The TCT

I'll leave it to the TCT to arbitrate, and decide whether ''fixing'' a widely
used core primitive can outweigh breaking a rare and clumsy use.

~ Reference Implementation

I have not yet written a reference implementation; I assume somebody with a
more fluent practice of the core will do so more efficiently. However, gentle
arm twisting, etc.

~ Copyright

This document has been placed in the public domain.

~ Comments

The ''times'' function in Unix is ''not'' an appropriate time base.  It reports the user and system time (CPU time, in other words) of the currently executing process and its children.  As far as I have been able to determine, Unix assumes that the system time reported by
''gettimeofday'' is the sole time base for absolute timing; if multiple timers are required in a single process, ''gettimeofday'' appears to be the only reference that is available.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|

|



|

|
|

|


|



|


|

|
|
|

|

|
|

|

|

|

|
|

|
|

|
|


|
|
|
|

|
|
|

|




|


|
|
|

|

|


|





|



|

|
|
>

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

# TIP 302: Fix "after"'s Sensitivity To Adjustments Of System Clock

	Author:         Alexandre Ferrieux <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        13-Dec-2006
	Post-History:   
	Keywords:       Tcl,time changes
	Tcl-Version:    8.7
-----

# Abstract

Currently, **after** tasks can be drastically delayed or sped up simply by
adjusting the system clock. This is due to the implementation's use of an
_absolute_ target date based on the system clock. The idea of this TIP is to
use another timebase for this purpose: the count of ticks from boot, which is
not affected by system time adjustments.

# Background

The basis of the implementation of **after** is, on each call to
**vwait**, to compute the _timeout_ argument to select\(\) by difference
between the stored target date of the earliest event and the current system
date \(_gettimeofday\(\)_\). This is perfect while the system date ticks
regularly. But if, say, the clock is set back by 5 minutes, then an after
handler scheduled 1 second ago which was just about to fire, will have 5
minutes yet to wait before its \(unmodified\) target date is reached. So, if
this handler was part of a 1-Hz periodic task, there will be a huge gap of
5:01 between two ticks at that point. If some other component is expecting
some kind of regularity, even with a conservative timeout of 10 times the
expected period, it _will_ time out, decide the periodic task is dead, and
possibly take drastic action.

# Proposed Change

This TIP proposes to use other timebases instead of gettimeofday\(\) in the
vwait/after code: **times\(\)** in unix, **GetTickCount\(\)** in Windows.
These clocks suffer _no_ sysadmin tinkering.

# Potential Break Of Compatibility

It has been objected that _some_ applications today may be using **after**
with an _absolute_ spirit; IOW such apps are supposed to _rely_ on the
fact that the after handler will fire when the system clock equals the target
date computed once for all when **after** was called. A prototype example
would be a crontab-like task, which would itself compute the offset by
difference between the target date and the current **clock seconds**.

## Arguments For Breaking It Anyway

 1. This _absolute_ interpretation is far from being natural, because
    **after**'s argument is an _offset_.

 2. This technique is not usable for a longer range than 25 days \(MAXINT
    milliseconds\), so not applicable e.g. for a personal schedule.

 3. The **overwhelming** majority of uses of **after** takes the
    _relative_ interpretation \(periodic tasks, timeouts\) and _cannot_ work
    correctly today.

 4. If this TIP were implemented incompatibly \(i.e. without a specific flag to
    **after**\), those _absolute-minded_ apps could simply be adapted
    _and_ improved in both robustness and range by using a periodic task
    which polls **clock seconds**.

 5. There is little evidence that the total number of _absolute-minded_ apps
    exceeds **one** \(see discussion on news:comp.lang.tcl "[after] fooled
    by shifting date"\)

# Syntax For Not Breaking It If Deemed Useful

Of course, if this supposed singleton is in fact many, or has enough weight to
preclude an improvement of the rest of Tcl timers, we can do:

 > **after -robust** _millisecs_

or any other colorful option name. But in this case there is a high risk that:
_either_ **after -robust** becomes the dominant use, thus cluttering the
code in many places, _or_ people remain largely unaware of the problem,
stick to the default **after**, and space shuttles fall by dozens.

# Escalation To The TCT

I'll leave it to the TCT to arbitrate, and decide whether _fixing_ a widely
used core primitive can outweigh breaking a rare and clumsy use.

# Reference Implementation

I have not yet written a reference implementation; I assume somebody with a
more fluent practice of the core will do so more efficiently. However, gentle
arm twisting, etc.

# Copyright

This document has been placed in the public domain.

# Comments

The _times_ function in Unix is _not_ an appropriate time base.  It reports the user and system time \(CPU time, in other words\) of the currently executing process and its children.  As far as I have been able to determine, Unix assumes that the system time reported by
_gettimeofday_ is the sole time base for absolute timing; if multiple timers are required in a single process, _gettimeofday_ appears to be the only reference that is available.

Name change from tip/303.tip to tip/303.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

TIP:		303
Title:		Enhance 'llength' Command to Support Nested Lists
Version:	$Revision: 1.3 $
Author:		Wolf-Dieter Busch <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Created:	29-Jan-2007
Post-History:	
Keywords:	Tcl, lindex


~ Abstract

The command '''llength''' currently returns the length of a list. Sometimes it
is desirable to know the length of a nested list. This TIP proposes an
improvement to '''llength''' to do that.

~ Description

Currently, finding the length of a nested list requires the combination of
'''llength''' and '''lindex'''. This works, but is not very clean for a
comparatively common operation when you compare with straight '''lindex'''
usage. This TIP proposes to enhance '''llength''' so that it also does the
indexing, making it's usage in such situations cleaner and less subject to
programming errors.

~~ Proposed Change

The '''llength''' command shall be updated to have syntax like this:

 > '''llength''' ''list'' ?''indexList'' ...?

When no ''indexList'' is supplied, the current behavior is used. When one or
more ''indexList'' arguments are supplied, they are used to restrict which
part of ''list'' is taken the length of, just as if '''lindex''' had been used
to index into ''list''.

Thus, [['''llength {a {b c} d}''']] shall return 3 as nowadays, [['''llength
{a {b c} d} 1''']]> shall return the length of the nested list on index 1,
here {b c} => 2, and [['''llength {a {b c} d} 1 0''']] shall return the length
of the nested list on index 0 of nested list on index 1, i.e., 1 in this case.

~~ Compatibility

As this only changes a way of use of the '''llength''' that currently returns
an error, there are no compatibility problems.

~ Example Implementation

The procedure '''idxllength''' (below) does what is described above, but
inefficiently:

|proc idxllength args {
|    llength [lindex {*}$args]
|}


~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|

|

|


|
|
|



|

|

|

|
|
|
|

|
|
|


|

|


|

|


|
|
<
|
>
|


>

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

# TIP 303: Enhance 'llength' Command to Support Nested Lists

	Author:		Wolf-Dieter Busch <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Created:	29-Jan-2007
	Post-History:	
	Keywords:	Tcl, lindex
-----

# Abstract

The command **llength** currently returns the length of a list. Sometimes it
is desirable to know the length of a nested list. This TIP proposes an
improvement to **llength** to do that.

# Description

Currently, finding the length of a nested list requires the combination of
**llength** and **lindex**. This works, but is not very clean for a
comparatively common operation when you compare with straight **lindex**
usage. This TIP proposes to enhance **llength** so that it also does the
indexing, making it's usage in such situations cleaner and less subject to
programming errors.

## Proposed Change

The **llength** command shall be updated to have syntax like this:

 > **llength** _list_ ?_indexList_ ...?

When no _indexList_ is supplied, the current behavior is used. When one or
more _indexList_ arguments are supplied, they are used to restrict which
part of _list_ is taken the length of, just as if **lindex** had been used
to index into _list_.

Thus, [**llength {a {b c} d}**] shall return 3 as nowadays, [**llength
\{a \{b c\} d\} 1**]> shall return the length of the nested list on index 1,
here \{b c\} => 2, and [**llength {a {b c} d} 1 0**] shall return the length
of the nested list on index 0 of nested list on index 1, i.e., 1 in this case.

## Compatibility

As this only changes a way of use of the **llength** that currently returns
an error, there are no compatibility problems.

# Example Implementation

The procedure **idxllength** \(below\) does what is described above, but
inefficiently:

	proc idxllength args {
	    llength [lindex {*}$args]

	}

# Copyright

This document has been placed in the public domain.

Name change from tip/304.tip to tip/304.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

TIP:            304
Title:          A Standalone [chan pipe] Primitive for Advanced Child IPC
Version:        $Revision: 1.15 $
Author:         Alexandre Ferrieux <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        07-Feb-2007
Post-History:   
Keywords:       Tcl,exec,process,subprocess,pipeline,channel
Tcl-Version:    8.6


~ Abstract

Currently, it is not easy to get both (separate) dataflows from the stdout and
stderr of a child. BLT's '''bgexec''' does this in an extension, and could be
added to the core. But the point of this TIP is to show that a much smaller
code addition can provide a lower-level primitive with much more potential
than '''bgexec''''s: a ''standalone pipe'' creation tool like TclX's
'''pipe''' command.

~ Background

Getting back both stdout and stderr from a child has long been an FAQ on
news:comp.lang.tcl, to the point that '''bgexec''' has been offered in an
extension, BLT, whose main job is very remote from IPC. Now this has been a
problem for many, who didn't want to have the problems of distributing a
script depending on an extension. Moreover, '''bgexec''' does not scale up, in
that it cannot bring back the separate stderrs of all four children in:

|	set ff [open "|a | b | c | d" r]

A popular workaround for script-only purists is to spawn an external "pump"
like ''cat'' in an [['''open''' ... r+]], and redirect the wanted stderr to
the write side of the pump. Its output can then be monitored through the read
side:

|	set pump [open "|cat" r+]
|	set f1 [open "|cmd args 2>@ $pump" r]
|	fileevent $f1 readable got_stdout
|	fileevent $pump readable got_stderr

Now this is all but elegant of course, difficult to deploy on Windows (where
you need an extra cat.exe), and not especially efficient since the "pump"
consumes context switches and memory bandwidth only to emulate a ''single'' OS
pipe when Tcl is forced to create ''two'' of them via [['''open''' ... r+]].

For this latter performance issue, a better alternative is a named pipe. But
it is even harder to create on Windows, and it is a nightmare to handle its
lifecycle properly (it doesn't die automagically with the creating process;
blocks on open() if other side is not ready).

~ Proposed Change

All this points to the obvious solution: steal TclX's '''pipe''' command,
which wraps the OS's pipe()/CreatePipe() syscall, yielding two Tcl channels
wrapping the read and write side of the underlying pipe.

TclX's '''pipe''' command allows two syntaxes:

|	pipe pr pw
|	foreach {pr pw} [pipe] break

Its application to following stderr is straightfoward:

|	pipe pr pw
|	set f1 [open "|cmd args 2>@ $pw" r]
|	fileevent $f1 readable got_stdout
|	fileevent $pr readable got_stderr

~~ Specification

The basic functionality is to return a pair of channels, so the script-level API does just that:

 > 	'''chan pipe'''

Create a pipe, and return a list of two channels wrapping either side of the pipe. The first element is the side opened for reading, the second for writing:

|	lassign [chan pipe] pr pw

Subsequently, anything written to $pw will be readable on $pr.
We purposefully drop the other [[pipe pr pw]] syntax from TclX, for the sake of minimality.

~~ C Interface

A counterpart to '''chan pipe''' is added to Tcl's C API:

 > int '''Tcl_CreatePipe'''(Tcl_Interp *''interp'', Tcl_Channel *''rchan'',
   Tcl_Channel *''wchan'', int ''flags'')

The ''interp'' argument is used for reporting errors and registering the
channels created, the ''rchan'' and ''wchan'' arguments point to variables
into which to place the channels for each end of the pipeline, and the
''flags'' argument is reserved for future expansion.

~ Discussion

It has been in TclX for years, so it is fireproof. The code can be directly
copied from there, and is dead simple, just calling Tcl_MakeFileChannel and
Tcl_RegisterChannel on both fds/handles. Just the low-level syscall changes
between unix and windows.

~~ Additional Benefits

It should also be noted that this primitive allows to deprecate the use of
[['''open''' "|..."]] and '''pid''' themselves !

|	lassign [chan pipe] p1r p1w
|	lassign [chan pipe] p2r p2w
|	set pids [exec cmd $args >@ $p1w 2>@ $p2w &]
|	fileevent $p1r readable got_stdout
|	fileevent $p2r readable got_stderr

Taking this idea one step further, one can even deprecate the "|" in
'''exec''', with:

|	exec a | b | c &

being rewritten as:

|	exec a >@ $p1w &
|	exec b <@ $p1r >@ $p2w &
|	exec c <@ $p2r &

(I'm not crazy about actually deprecating ol'good and concise idioms in favour
of the tedious lines above; however as an orthogonality worshipper I like to
think it would be theoretically possible to reimplement them in pure Tcl
thanks to the added power of one tiny extra primitive)

A more serious advantage, is that it allows the "half-close" of a command
pipeline (detailed in [301] which the current TIP makes partly obsolete).
Indeed

|	lassign [chan pipe] pr pw
|	lassign [chan pipe] qr qw
|	exec a <@$pr >@$qw &

allows to close just the read side with

|	close $pw

and still read all the output of the command up to its EOF:

|	while {[gets $qr line]>=0} {...}

which is notoriously impossible with

|	set pq [open |a r+]

~ Directions for Future Work

On unix, there's no reason to limit the use of unnamed pipes to stdout and
stderr. An arbitrary pipe topology can be set up between several childs with
descriptors 3,4,5... For this we could imagine a natural extension of
'''exec''''s '''2>@''' to '''3>@''', '''4<@''', etc.

|	exec foo >@ $p 3>@ $q 4<@ $r &
|	exec bar <@ $q >@ $r 4<@ $p &

Of course, such uses are extreme, but useful in complicated IPC setups to
achieve much better performance (through direct point-to-point pipes) than
would a simpler "star" or "blackboard" topology (where all children write back
to a central message routing process).

~ Reference Implementation

A patch against the Tcl HEAD (8.6) is located at
http://sf.net/tracker/?func=detail&aid=1978495&group_id=10894&atid=310894

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|


|
|

|


|


|


|


|



|
|
|
|

|
|
|
|



|
|

|

|
|


|

|
|



|
|
|
|

|



|



|


|

|

|

|
|

|
|

|

|


|
|


|


|

|
|
|
|
|

|
|

|



|
|
|

|


|


|


|
|
|



|



|



|

|




|

|
|


|
|
|

|

|
|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

# TIP 304: A Standalone [chan pipe] Primitive for Advanced Child IPC

	Author:         Alexandre Ferrieux <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        07-Feb-2007
	Post-History:   
	Keywords:       Tcl,exec,process,subprocess,pipeline,channel
	Tcl-Version:    8.6
-----

# Abstract

Currently, it is not easy to get both \(separate\) dataflows from the stdout and
stderr of a child. BLT's **bgexec** does this in an extension, and could be
added to the core. But the point of this TIP is to show that a much smaller
code addition can provide a lower-level primitive with much more potential
than **bgexec**'s: a _standalone pipe_ creation tool like TclX's
**pipe** command.

# Background

Getting back both stdout and stderr from a child has long been an FAQ on
news:comp.lang.tcl, to the point that **bgexec** has been offered in an
extension, BLT, whose main job is very remote from IPC. Now this has been a
problem for many, who didn't want to have the problems of distributing a
script depending on an extension. Moreover, **bgexec** does not scale up, in
that it cannot bring back the separate stderrs of all four children in:

		set ff [open "|a | b | c | d" r]

A popular workaround for script-only purists is to spawn an external "pump"
like _cat_ in an [**open** ... r+], and redirect the wanted stderr to
the write side of the pump. Its output can then be monitored through the read
side:

		set pump [open "|cat" r+]
		set f1 [open "|cmd args 2>@ $pump" r]
		fileevent $f1 readable got_stdout
		fileevent $pump readable got_stderr

Now this is all but elegant of course, difficult to deploy on Windows \(where
you need an extra cat.exe\), and not especially efficient since the "pump"
consumes context switches and memory bandwidth only to emulate a _single_ OS
pipe when Tcl is forced to create _two_ of them via [**open** ... r+].

For this latter performance issue, a better alternative is a named pipe. But
it is even harder to create on Windows, and it is a nightmare to handle its
lifecycle properly \(it doesn't die automagically with the creating process;
blocks on open\(\) if other side is not ready\).

# Proposed Change

All this points to the obvious solution: steal TclX's **pipe** command,
which wraps the OS's pipe\(\)/CreatePipe\(\) syscall, yielding two Tcl channels
wrapping the read and write side of the underlying pipe.

TclX's **pipe** command allows two syntaxes:

		pipe pr pw
		foreach {pr pw} [pipe] break

Its application to following stderr is straightfoward:

		pipe pr pw
		set f1 [open "|cmd args 2>@ $pw" r]
		fileevent $f1 readable got_stdout
		fileevent $pr readable got_stderr

## Specification

The basic functionality is to return a pair of channels, so the script-level API does just that:

 > 	**chan pipe**

Create a pipe, and return a list of two channels wrapping either side of the pipe. The first element is the side opened for reading, the second for writing:

		lassign [chan pipe] pr pw

Subsequently, anything written to $pw will be readable on $pr.
We purposefully drop the other [pipe pr pw] syntax from TclX, for the sake of minimality.

## C Interface

A counterpart to **chan pipe** is added to Tcl's C API:

 > int **Tcl\_CreatePipe**\(Tcl\_Interp \*_interp_, Tcl\_Channel \*_rchan_,
   Tcl\_Channel \*_wchan_, int _flags_\)

The _interp_ argument is used for reporting errors and registering the
channels created, the _rchan_ and _wchan_ arguments point to variables
into which to place the channels for each end of the pipeline, and the
_flags_ argument is reserved for future expansion.

# Discussion

It has been in TclX for years, so it is fireproof. The code can be directly
copied from there, and is dead simple, just calling Tcl\_MakeFileChannel and
Tcl\_RegisterChannel on both fds/handles. Just the low-level syscall changes
between unix and windows.

## Additional Benefits

It should also be noted that this primitive allows to deprecate the use of
[**open** "\|..."] and **pid** themselves !

		lassign [chan pipe] p1r p1w
		lassign [chan pipe] p2r p2w
		set pids [exec cmd $args >@ $p1w 2>@ $p2w &]
		fileevent $p1r readable got_stdout
		fileevent $p2r readable got_stderr

Taking this idea one step further, one can even deprecate the "\|" in
**exec**, with:

		exec a | b | c &

being rewritten as:

		exec a >@ $p1w &
		exec b <@ $p1r >@ $p2w &
		exec c <@ $p2r &

\(I'm not crazy about actually deprecating ol'good and concise idioms in favour
of the tedious lines above; however as an orthogonality worshipper I like to
think it would be theoretically possible to reimplement them in pure Tcl
thanks to the added power of one tiny extra primitive\)

A more serious advantage, is that it allows the "half-close" of a command
pipeline \(detailed in [[301]](301.md) which the current TIP makes partly obsolete\).
Indeed

		lassign [chan pipe] pr pw
		lassign [chan pipe] qr qw
		exec a <@$pr >@$qw &

allows to close just the read side with

		close $pw

and still read all the output of the command up to its EOF:

		while {[gets $qr line]>=0} {...}

which is notoriously impossible with

		set pq [open |a r+]

# Directions for Future Work

On unix, there's no reason to limit the use of unnamed pipes to stdout and
stderr. An arbitrary pipe topology can be set up between several childs with
descriptors 3,4,5... For this we could imagine a natural extension of
**exec**'s **2>@** to **3>@**, **4<@**, etc.

		exec foo >@ $p 3>@ $q 4<@ $r &
		exec bar <@ $q >@ $r 4<@ $p &

Of course, such uses are extreme, but useful in complicated IPC setups to
achieve much better performance \(through direct point-to-point pipes\) than
would a simpler "star" or "blackboard" topology \(where all children write back
to a central message routing process\).

# Reference Implementation

A patch against the Tcl HEAD \(8.6\) is located at
<http://sf.net/tracker/?func=detail&aid=1978495&group\_id=10894&atid=310894>

# Copyright

This document has been placed in the public domain.

Name change from tip/305.tip to tip/305.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

TIP:            305
Title:          ANSI Escape Sequence Support for Windows's Console Channel Driver
Version:        $Revision: 1.4 $
Author:         David Gravereaux <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        21-Feb-2007
Post-History:   
Discussions-To: news:comp.lang.tcl
Tcl-Version:    8.5


~ Abstract

The console channel driver for windows (win/tclWinConsole.c) could support colors, cursor movement, and scrolling by embedding such commands in the stream to the console in the age-old tradition of ANSI_X3.64-1979 escapes. By filtering-out such commands in the DriverOutputProc and doing the command actions, greater cross-platform support is enabled to other platforms (such as Linux) that have ANSI support.

~ Rationale

A long time ago, in a land far, far away... DOS programmers wrote character-mode applications for a screen that was 80x25 cells large and had 16 colors and a few special attributes using a strange codepage called ''IBM PC'' or ''CP437''. And life wasn't that bad.

Currently, there appears to only be two ways to write such an application in Tcl:

 * Use the services of TWAPI to call the native Console API intrinsics.

 * Use the ck shell (Curses Tcl Toolkit).

This change proposal is similar to the first option, but the commands are placed in the stream in a standardized manner that gains us immediate support with Linux.

This change proposal is different than the second option in that only the output direction of the console driver is modified. No support is proposed for such things as raw keyscan and mouse events.

This change proposal will not effect the opening modes of the console,
therefore will not have an adverse change to any current scripts.

~ Specification

This TIP proposes two changes visible at the script level. Firstly, the
'''fconfigure''' command will be able to set the speed of channels directed to the Windows console (often being stdout and stderr) via a '''-baud''' option. Secondly, channels directed to the Windows console will interpret ANSI control sequences as ANSI control sequences (subject to the limitations outlined below) and not directives to write characters.

The ''blink'' and ''underline'' SGR modes can not be supported due to OS limitations, nor can the color palette be modified to affirm color consistency.  ''reverse'' and ''concealed'' SGR modes can both be emulated, but ''concealed'' has a security risk and is not a replacement for turning local echo off.

~ Reference Implementation

A patch is currently being worked on. There is an ANSI test extension for wish available [http://www.pobox.com/~davygrvy/tclstuff/winAnsiCon12_pack.zip] that
contains numerous test screens (some with ansimations) and appears to work perfectly.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|

|

|





|








|


|

|

|

|
|

|


>

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

# TIP 305: ANSI Escape Sequence Support for Windows's Console Channel Driver

	Author:         David Gravereaux <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        21-Feb-2007
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Tcl-Version:    8.5
-----

# Abstract

The console channel driver for windows \(win/tclWinConsole.c\) could support colors, cursor movement, and scrolling by embedding such commands in the stream to the console in the age-old tradition of ANSI\_X3.64-1979 escapes. By filtering-out such commands in the DriverOutputProc and doing the command actions, greater cross-platform support is enabled to other platforms \(such as Linux\) that have ANSI support.

# Rationale

A long time ago, in a land far, far away... DOS programmers wrote character-mode applications for a screen that was 80x25 cells large and had 16 colors and a few special attributes using a strange codepage called _IBM PC_ or _CP437_. And life wasn't that bad.

Currently, there appears to only be two ways to write such an application in Tcl:

 * Use the services of TWAPI to call the native Console API intrinsics.

 * Use the ck shell \(Curses Tcl Toolkit\).

This change proposal is similar to the first option, but the commands are placed in the stream in a standardized manner that gains us immediate support with Linux.

This change proposal is different than the second option in that only the output direction of the console driver is modified. No support is proposed for such things as raw keyscan and mouse events.

This change proposal will not effect the opening modes of the console,
therefore will not have an adverse change to any current scripts.

# Specification

This TIP proposes two changes visible at the script level. Firstly, the
**fconfigure** command will be able to set the speed of channels directed to the Windows console \(often being stdout and stderr\) via a **-baud** option. Secondly, channels directed to the Windows console will interpret ANSI control sequences as ANSI control sequences \(subject to the limitations outlined below\) and not directives to write characters.

The _blink_ and _underline_ SGR modes can not be supported due to OS limitations, nor can the color palette be modified to affirm color consistency.  _reverse_ and _concealed_ SGR modes can both be emulated, but _concealed_ has a security risk and is not a replacement for turning local echo off.

# Reference Implementation

A patch is currently being worked on. There is an ANSI test extension for wish available <http://www.pobox.com/~davygrvy/tclstuff/winAnsiCon12_pack.zip>  that
contains numerous test screens \(some with ansimations\) and appears to work perfectly.

# Copyright

This document has been placed in the public domain.

Name change from tip/306.tip to tip/306.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
136
137
138
139
140
141

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

TIP:            306
Title:          Auto-Naming Widgets
Version:        $Revision: 1.11 $
Author:         Koen Danckaert <[email protected]>
Author:         Richard Suchenwirth <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        11-Jun-2007
Post-History:   
Keywords:       automatic,Tk,widget,naming
Tcl-Version:    8.6


~ Abstract

A Tk programmer must give every widget a unique name. This is often quite
annoying, especially for widgets whose name is stored in a variable (which
also must be given a name). This TIP proposes a small extension to generate
automatic names for widgets.

~ Rationale

Every Tk widget must be given a unique name. This is needed internally for Tk
and also for the programmer to be able to refer to it. Quite often, and as
recommended in many Tk coding guidelines (e.g.
http://www.beedub.com/book/2nd/TKINTRO.doc.html), the widget names are stored
in variables and only referred to indirectly. These variables must also be
given a name, which may lead to confusion, and requires more inventivity of
the programmer than needed.

An example from the BWidget source code:

| set status   [frame $path.status -background $bg]
| set label    [label $status.label]
| set indframe [frame $status.indf -background $bg]
| set prgframe [frame $status.prgf -background $bg]

Other cases where widget names are unimportant from a programmer's viewpoint,
are widgets which are never referred to after creation, and those which are
only referred to by other means (e.g. by a textvariable). Example:

| pack [label .name_label -text "Enter name:"] -side left
| pack [entry .name_entry -textvariable name] -side left

In all those cases, it would be helpful if Tk could generate the widget names
itself.

Further motivation for this can be found in the following:

 * Tcl/Tk already uses auto-naming for other things, e.g. for channels and for
   images.

 * In Python and Ruby's Tk implementation, automatic widget names are the
   default. For example, a label in TkInter is normally created as:

| mylabel = Label(parentframe, text="something")

 > In this case the Tk widget name will be something like
   ''$parentframe''.'''123'''. If you really want to assign a name yourself,
   you can use the optional ''name'' argument:

| mylabel = Label(parentframe, text="koen", name = "mylabel")

Currently the widget creation commands already return the widget name, which
is always the exact name the programmer has supplied. This makes it easy to
make an (almost) backwards compatible extension, as presented below.

~ Specification

When creating a new widget with a name that ends with "'''%'''", the "%" will
be replaced by a counter. The actual widget name is then returned. Depending
on the chosen implementation, there may be one global counter or each parent
widget can have its own counter.

| % button .%
| .1
| % set f [frame .%]
| .2
| % label $f.%
| .2.3
| % set p [frame .prefix%]
| .prefix4
| % label $p.%a%b%c%%
| .prefix3.%a%b%c%5

The examples above can now be written as:

| set status   [frame $path.% -background $bg]
| set label    [label $status.%]
| set indframe [frame $status.% -background $bg]
| set prgframe [frame $status.% -background $bg]

| pack [label .% -text "Enter name:"] -side left
| pack [entry .% -textvariable name] -side left

~ Reference Implementation

See SourceForge patch #1735008[http://sf.net/support/tracker.php?aid=1735008].
The reference implementation keeps a counter in the TkMainInfo structure,
which is thread-local.

~ Compatibility

~~ Backward Compatibility

The presented extension is backward compatible, except for existing code which
uses widget names ending on "%". Even this will only be a problem if the
widgets are referenced directly (i.e. not by a variable) after creation.

~~ Forward Compatibility

This is another issue. Megawidgets which want to support the new naming
scheme, will probably have to be adapted. In particular, when they are written
as:

| proc mymegawidget {win args} {
|     # do some stuff with $win
|     # ...
|
|     # Create the hull frame
|     frame $win -class MyMegaWidget
|
|     # Create internals
|     label $win.title -text "Title"
|     # ...
| }


they will have to be rewritten in the following way:

| proc mymegawidget {w args} {
|     # Create the hull frame (returns the actual widget name)
|     set win [frame $w -class MyMegaWidget]
|
|     # do some stuff with $win
|     # ...
|
|     # Create internals
|     label $win.title -text "Title"
|     # ...
| }


In Tk itself, there is one such example which has to be rewritten:
'''tk_optionMenu'''. This is not expected to be a significant hurdle.

~ Alternatives

 1. Implementing this TIP in Tcl. This would require all widget commands to be
    wrapped. That's a lot of work compared to the simple C code patch used
    here.

 2. Make a separate '''autoname''' command, and use this when creating
    widgets. For example:

| set frame [frame [autoname .%]]
| label [autoname $frame.%]

 > This makes the code a longer and more difficult to read, which is the
   opposite of what this TIP tries to achieve.

 3. A very simple autonaming can be done by just setting aside one global
    variable and define an alias that increments that variable:

| set ::# 0
| interp alias {} % {} incr ::#
| set frame [frame .[%]]
| label $frame.[%]

 > However, using a short procedure name like "%" has the drawback that
   extensions or modules which you want to incorporate in your code, may
   already have defined "%" for something else. Also, as each module may have
   its own autonaming scheme, there is a risk for overlapping widget names. So
   auto-naming really belongs in the core.

 4. Instead of using a special character, the widget creation commands could
    get a '''-parent''' option to define the parent widget. Then, allow the
    widget command to be called without an explicit widget path, in which case
    it creates an auto-named child of the parent. The use of '''-parent''' and
    an explicit pathname would be mutually exclusive. For example:

| set frame [frame .f]
| set button [button -parent $frame -borderwidth 2 ...]

 > This may create confusion, since it seems to allow the parent to be
   modified (after creation) with the "configure" widget command. Furthermore,
   to implement this, all widget creation C functions have to be modified,
   including in extensions such as BLT and tktable, instead of just the
   NameWindow() function. Probably also the '''configure''' subcommands have
   to be adapted...

 > Another drawback is that "normal" and "automatic" widget creation now have
   a different syntax.

 5. A variation of the previous version can be implemented in pure Tcl:

| proc newchildof {parent creator args} {
|     (generate proper $child given $parent)
|     $creator $child {*}$args
| }

|
| set frame [frame .f]
| set button [newchildof $frame button -borderwidth 2 ...]

 > A drawback of this is that it is a bit verbose, and that "normal" and
   "automatic" widget creation have a different syntax. Also each extension
   may use its own autonaming scheme, which does not exactly favor code
   readability, and may cause name collisions.

~ Discussion

There was a short discussion about this TIP on comp.lang.tcl
[http://groups.google.com/group/comp.lang.tcl/browse_frm/thread/2ecd6fbf92de985b/e7471f5829933df2?lnk=gst&q=306#e7471f5829933df2].
Most alternatives which came forth from this discussion, were added to the
previous section.

While some of the alternative proposals above are usable (especially
'''(5)'''), they still have drawbacks. The TIP author believes that
auto-naming really belongs in the core. Just like in Python and Ruby, auto
widget names will probably be the default once they're added to Tk. A good
standard syntax for this will not only increase the writability of the code,
but also the readability. Indeed, in current Tk code many widget names are
used but never referred to again. Just using ".%" on these places makes it
clear that the actual widget name is unimportant. Also, the proposed syntax is
clear and concise and does not divert from the normal widget creation syntax.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|


|
|


|



|
|






|
|
|
|



|

|
|












|

|
|
|

|



|

|

|




|
|
|
|
|
|
|
|
|
|



|
|
|
|

|
|

|

|



|

|



|

|





|
|
|
|
|
|
|
|
|
|
<
|
>


|
|
|
|
|
|
|
|
|
|
<
|
>

|

|





|


|
|

|





|
|
|
|

|






|

|


|
|

|
|


|


|




|
|
|
<
>
|
|
|

|




|


|



|
|








|


>

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
136
137
138

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

# TIP 306: Auto-Naming Widgets

	Author:         Koen Danckaert <[email protected]>
	Author:         Richard Suchenwirth <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        11-Jun-2007
	Post-History:   
	Keywords:       automatic,Tk,widget,naming
	Tcl-Version:    8.6
-----

# Abstract

A Tk programmer must give every widget a unique name. This is often quite
annoying, especially for widgets whose name is stored in a variable \(which
also must be given a name\). This TIP proposes a small extension to generate
automatic names for widgets.

# Rationale

Every Tk widget must be given a unique name. This is needed internally for Tk
and also for the programmer to be able to refer to it. Quite often, and as
recommended in many Tk coding guidelines \(e.g.
<http://www.beedub.com/book/2nd/TKINTRO.doc.html\),> the widget names are stored
in variables and only referred to indirectly. These variables must also be
given a name, which may lead to confusion, and requires more inventivity of
the programmer than needed.

An example from the BWidget source code:

	 set status   [frame $path.status -background $bg]
	 set label    [label $status.label]
	 set indframe [frame $status.indf -background $bg]
	 set prgframe [frame $status.prgf -background $bg]

Other cases where widget names are unimportant from a programmer's viewpoint,
are widgets which are never referred to after creation, and those which are
only referred to by other means \(e.g. by a textvariable\). Example:

	 pack [label .name_label -text "Enter name:"] -side left
	 pack [entry .name_entry -textvariable name] -side left

In all those cases, it would be helpful if Tk could generate the widget names
itself.

Further motivation for this can be found in the following:

 * Tcl/Tk already uses auto-naming for other things, e.g. for channels and for
   images.

 * In Python and Ruby's Tk implementation, automatic widget names are the
   default. For example, a label in TkInter is normally created as:

		 mylabel = Label(parentframe, text="something")

	 > In this case the Tk widget name will be something like
   _$parentframe_.**123**. If you really want to assign a name yourself,
   you can use the optional _name_ argument:

		 mylabel = Label(parentframe, text="koen", name = "mylabel")

Currently the widget creation commands already return the widget name, which
is always the exact name the programmer has supplied. This makes it easy to
make an \(almost\) backwards compatible extension, as presented below.

# Specification

When creating a new widget with a name that ends with "**%**", the "%" will
be replaced by a counter. The actual widget name is then returned. Depending
on the chosen implementation, there may be one global counter or each parent
widget can have its own counter.

	 % button .%
	 .1
	 % set f [frame .%]
	 .2
	 % label $f.%
	 .2.3
	 % set p [frame .prefix%]
	 .prefix4
	 % label $p.%a%b%c%%
	 .prefix3.%a%b%c%5

The examples above can now be written as:

	 set status   [frame $path.% -background $bg]
	 set label    [label $status.%]
	 set indframe [frame $status.% -background $bg]
	 set prgframe [frame $status.% -background $bg]

	 pack [label .% -text "Enter name:"] -side left
	 pack [entry .% -textvariable name] -side left

# Reference Implementation

See SourceForge patch \#1735008<http://sf.net/support/tracker.php?aid=1735008> .
The reference implementation keeps a counter in the TkMainInfo structure,
which is thread-local.

# Compatibility

## Backward Compatibility

The presented extension is backward compatible, except for existing code which
uses widget names ending on "%". Even this will only be a problem if the
widgets are referenced directly \(i.e. not by a variable\) after creation.

## Forward Compatibility

This is another issue. Megawidgets which want to support the new naming
scheme, will probably have to be adapted. In particular, when they are written
as:

	 proc mymegawidget {win args} {
	     # do some stuff with $win
	     # ...
	
	     # Create the hull frame
	     frame $win -class MyMegaWidget
	
	     # Create internals
	     label $win.title -text "Title"
	     # ...

	 }

they will have to be rewritten in the following way:

	 proc mymegawidget {w args} {
	     # Create the hull frame (returns the actual widget name)
	     set win [frame $w -class MyMegaWidget]
	
	     # do some stuff with $win
	     # ...
	
	     # Create internals
	     label $win.title -text "Title"
	     # ...

	 }

In Tk itself, there is one such example which has to be rewritten:
**tk\_optionMenu**. This is not expected to be a significant hurdle.

# Alternatives

 1. Implementing this TIP in Tcl. This would require all widget commands to be
    wrapped. That's a lot of work compared to the simple C code patch used
    here.

 2. Make a separate **autoname** command, and use this when creating
    widgets. For example:

		 set frame [frame [autoname .%]]
		 label [autoname $frame.%]

	 > This makes the code a longer and more difficult to read, which is the
   opposite of what this TIP tries to achieve.

 3. A very simple autonaming can be done by just setting aside one global
    variable and define an alias that increments that variable:

		 set ::# 0
		 interp alias {} % {} incr ::#
		 set frame [frame .[%]]
		 label $frame.[%]

	 > However, using a short procedure name like "%" has the drawback that
   extensions or modules which you want to incorporate in your code, may
   already have defined "%" for something else. Also, as each module may have
   its own autonaming scheme, there is a risk for overlapping widget names. So
   auto-naming really belongs in the core.

 4. Instead of using a special character, the widget creation commands could
    get a **-parent** option to define the parent widget. Then, allow the
    widget command to be called without an explicit widget path, in which case
    it creates an auto-named child of the parent. The use of **-parent** and
    an explicit pathname would be mutually exclusive. For example:

		 set frame [frame .f]
		 set button [button -parent $frame -borderwidth 2 ...]

	 > This may create confusion, since it seems to allow the parent to be
   modified \(after creation\) with the "configure" widget command. Furthermore,
   to implement this, all widget creation C functions have to be modified,
   including in extensions such as BLT and tktable, instead of just the
   NameWindow\(\) function. Probably also the **configure** subcommands have
   to be adapted...

	 > Another drawback is that "normal" and "automatic" widget creation now have
   a different syntax.

 5. A variation of the previous version can be implemented in pure Tcl:

		 proc newchildof {parent creator args} {
		     (generate proper $child given $parent)
		     $creator $child {*}$args

		 }
		
		 set frame [frame .f]
		 set button [newchildof $frame button -borderwidth 2 ...]

	 > A drawback of this is that it is a bit verbose, and that "normal" and
   "automatic" widget creation have a different syntax. Also each extension
   may use its own autonaming scheme, which does not exactly favor code
   readability, and may cause name collisions.

# Discussion

There was a short discussion about this TIP on comp.lang.tcl
<http://groups.google.com/group/comp.lang.tcl/browse_frm/thread/2ecd6fbf92de985b/e7471f5829933df2?lnk=gst&q=306#e7471f5829933df2> .
Most alternatives which came forth from this discussion, were added to the
previous section.

While some of the alternative proposals above are usable \(especially
**\(5\)**\), they still have drawbacks. The TIP author believes that
auto-naming really belongs in the core. Just like in Python and Ruby, auto
widget names will probably be the default once they're added to Tk. A good
standard syntax for this will not only increase the writability of the code,
but also the readability. Indeed, in current Tk code many widget names are
used but never referred to again. Just using ".%" on these places makes it
clear that the actual widget name is unimportant. Also, the proposed syntax is
clear and concise and does not divert from the normal widget creation syntax.

# Copyright

This document has been placed in the public domain.

Name change from tip/307.tip to tip/307.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

TIP:		307
Title:		Make TclTransferResult() Public
Version:	$Revision: 1.7 $
Author:		Erik Leunissen <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Created:	28-Sep-2007
Post-History:	
Keywords:	Tcl, result, transfer, interpreter, API rename


~ Abstract

This TIP proposes to make the existing function '''TclTransferResult'''() part
of the public interface.

~ Rationale

The function '''TclTransferResult'''() is used by Tcl internally to transfer
an interpreter result and/or error information between different Tcl
interpreters. Besides its use in the Tcl sources, applications (based on the
Tcl library) which use multiple interpreters may have a need for this
functionality as well. However, programmers are likely to overlook the
existing TclTransferResult() as long as the function continues to lead its
more or less hidden existence. (The TIP author discovered its existence only
after bugs in his own code led him to inspect how Tcl internally handles
result and error info between interpreters.) Making the function public is
very much a matter of courtesy/generosity to programmers that use the Tcl
library. It also seems to make the API's for result and error handling more
complete.

This TIP does not propose to change either the arguments or semantics of the
function.

~ Implementation

There is not much to implement: TclTransferResult() already exists in
''tclResult.c''. What remains to be done:

 * renaming to
   Tcl_TranferResult(): i.e. insert a single underscore character in
   its name. The function is not declared static already.

 * slot it into the Tcl stubs table.

 * write documentation

A draft version of the documentation has already been supplied as a separate
file ''Tcl_TransferResult.doc'' (see
[http://sf.net/support/tracker.php?aid=1723738]). It has been written as an
addition to an existing man page. The question remains which is the most
appropriate manual page to add it to.

Considerations for placement of the documentation:

 * man page for
   Tcl_CreateInterp: this is the only manual page that is solely intended for
   multiple interpreters which are truly arbitrary interpreters, i.e. without
   any imposed relationship between them. However, it doesn't concern interp
   results.

 * man page for
   Tcl_CreateSlave: this manual page says for itself that it concerns multiple
   interpreters, which is only half the truth: it concerns mostly interpreters
   that have an explicit master-slave relationship, the only exception being
   Tcl_CreateAlias(Obj).

 * man page for
   Tcl_SaveResult: handles interp results, but is not at all intended for
   multiple interpreter situations.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|

|
|

|
|

|







|

|
|


|







|
|






|





|


|


|


|


>

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

# TIP 307: Make TclTransferResult() Public

	Author:		Erik Leunissen <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Done
	Created:	28-Sep-2007
	Post-History:	
	Keywords:	Tcl, result, transfer, interpreter, API rename
-----

# Abstract

This TIP proposes to make the existing function **TclTransferResult**\(\) part
of the public interface.

# Rationale

The function **TclTransferResult**\(\) is used by Tcl internally to transfer
an interpreter result and/or error information between different Tcl
interpreters. Besides its use in the Tcl sources, applications \(based on the
Tcl library\) which use multiple interpreters may have a need for this
functionality as well. However, programmers are likely to overlook the
existing TclTransferResult\(\) as long as the function continues to lead its
more or less hidden existence. \(The TIP author discovered its existence only
after bugs in his own code led him to inspect how Tcl internally handles
result and error info between interpreters.\) Making the function public is
very much a matter of courtesy/generosity to programmers that use the Tcl
library. It also seems to make the API's for result and error handling more
complete.

This TIP does not propose to change either the arguments or semantics of the
function.

# Implementation

There is not much to implement: TclTransferResult\(\) already exists in
_tclResult.c_. What remains to be done:

 * renaming to
   Tcl\_TranferResult\(\): i.e. insert a single underscore character in
   its name. The function is not declared static already.

 * slot it into the Tcl stubs table.

 * write documentation

A draft version of the documentation has already been supplied as a separate
file _Tcl\_TransferResult.doc_ \(see
<http://sf.net/support/tracker.php?aid=1723738> \). It has been written as an
addition to an existing man page. The question remains which is the most
appropriate manual page to add it to.

Considerations for placement of the documentation:

 * man page for
   Tcl\_CreateInterp: this is the only manual page that is solely intended for
   multiple interpreters which are truly arbitrary interpreters, i.e. without
   any imposed relationship between them. However, it doesn't concern interp
   results.

 * man page for
   Tcl\_CreateSlave: this manual page says for itself that it concerns multiple
   interpreters, which is only half the truth: it concerns mostly interpreters
   that have an explicit master-slave relationship, the only exception being
   Tcl\_CreateAlias\(Obj\).

 * man page for
   Tcl\_SaveResult: handles interp results, but is not at all intended for
   multiple interpreter situations.

# Copyright

This document has been placed in the public domain.

Name change from tip/308.tip to tip/308.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871

872
873
874
875
876
877
878
879
880
881
882
883
884
885
886

887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922

923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942

943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
TIP:            308
Title:          Tcl Database Connectivity (TDBC)
Version:        $Revision: 1.17 $
Author:         Kevin B. Kenny <[email protected]>
Author:         Artur Trzewik <[email protected]>
Author:         Andreas Leitgeb <[email protected]>
Author:		Donal K. Fellows <[email protected]>
State:          Final
Type:           Informative
Vote:           Done
Created:        15-Nov-2007
Post-History:   
Obsoleted-By:	350


~ Abstract

This TIP defines a common database access interface for Tcl scripts.

~ Corrections

There are corrections to this TIP in [350] as well. Readers of this document
should see that one too.

~ Introduction

There has been a fair amount of discussion, that flares and dies back,
regarding the need for a "Tcl database connectivity layer" in the Tcl core.
This document specifies what this discussion means. At its present stage of
development, it is to be considered very much a draft; discussion is actively
solicited.

Parties who are interested in a detailed background of this TIP may a more
extensive discussion of motivations and objectives in the author's posting to
''comp.lang.tcl'' and the ''tcl-core'' newsgroup, obtainable from
[http://groups.google.com/group/comp.lang.tcl/msg/9351d1b2a59ee2ca] or
[http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/3581757].

~~ What is Tcl's Database Connectivity Layer?

If we look at other database connectivity layers such as ODBC/DAO, JDBC,
Perl's DBD/DBI, we find that there really isn't very much, if anything, inside
them. Rather than being a body of code, they consist primarily of
specifications of the interfaces to which the author of a database
connectivity module must conform. The real work of connecting to the databases
happens inside the connectivity modules, which are generally speaking under
the control of the database teams. In terms of practical politics, there isn't
really any other way to do it; the Tcl maintainers are highly unlikely to want
to take on the job of connecting to arbitrary database API's.

In other languages, such as C++ and Java, it is often necessary to have
interface definitions that are understood by a compiler in order to get the
"pluggability" of arbitrary database connectivity. In Tcl, however, an
"interface" is best understood as an ensemble implementing a predetermined set
of commands. There is no counterpart to a Java or C++ interface definition,
nor does there need to be. For this reason, the work product of a "Tcl
database connectivity" development effort is likely (at least at the first
stage) to consist primarily of a specification document, perhaps with
reference implementations for one or a few popular databases. To be considered
"in the core", the specification should be included with the Tcl
documentation, and be under control of the TIP process. The database
implementations should be considered "extensions," and have their own
configuration management. This statement doesn't say that we can't choose from
among them a set that we will package with releases of the Tcl core. In fact,
I hope that this effort will be one driver for the TCT to sort out the
management of "bundled extensions."

~~ Mechanics of This Document

I write this document in "standards committee prose". (While turgid, it at
least is often well-understood; I offer no further defence.) In particular:

 * the word "MAY" is construed as allowing a given behaviour but imposing no
   requirement other than that clients be prepared for it;

 * the word "MUST" (and conversely "MUST NOT") is construed as requiring a
   given behaviour; implementations that fail one or more requirements given
   by "'''must'''" are non-compliant;

 * the word "SHOULD" (and conversely "SHOULD NOT") indicates that a given
   behaviour is expected of an implementation unless there is a compelling
   reason not to include it; while not formally non-compliant, implementations
   that fail one or more requirements given by "SHOULD" can be understood to
   have issues with respect to "quality of implementation."

 * the future of determination ("SHALL" or "WILL" according to the usual
   customs of formal written English) is construed as a promise to which the
   Tcl Core or the Tcl Core Team, as appropriate, shall adhere. It describes
   requirements of the Tcl Core, rather than of database connection modules.

 * the term, "integer value" refers to any string acceptable to
   '''Tcl_GetBignumFromObj'''; the term "native integer value" refers to a
   value acceptable to '''Tcl_GetIntFromObj''', and hence to a value that can
   be represented by a C '''int''' on the target machine.

 * the term, "boolean value" refers to any string acceptable to
   '''Tcl_GetBooleanFromObj''' and hence includes at least '1', '0', 'on',
   'off', 'yes', 'no', 'true', and 'false'.

 * the term "ensemble" refers to a Tcl command that accepts subcommands. It
   does not imply that any given command is implemented using the '''namespace
   ensemble''' mechanism.

~ Specification

~~ Connecting to a Database

Obviously the first thing that any connectivity layer has to offer is the
ability to select a database. The way databases are named is quite specific to
the database manager, as is the way access is negotiated (credentials such as
user name and password may be required, session keys may be negotiated for
privacy and authentication, and so on). All of this machinery is formally out
of scope for this specification. Similarly, the machinery of database
administration (at least at the level of creating/deleting entire databases,
managing the physical layer, and authorizing clients) is presumed to be
already taken care of. We need merely specify that a connectivity layer must
provide at least one command that accepts arguments describing the desired
connection and returns a ''database handle'' - defined to be an ensemble
through which interactions with the given database instance will take place.
Here, ''database instance'' means the database, or databases, that the given
handle can access; rather a circular definition. In many SQL systems, it is
possible for a single connection to access several "databases" managed by SQL
CREATE DATABASE statments, or several "tablespaces" or similar constructs. We
presume that database module implementors will know what is appropriate for
their systems, and intentionally leave this particular matter somewhat vague.

~~ Basic Mechanics of Database Interfaces

Database handles are Tcl ensembles, meaning that they are commands that
support subcommands. Other ensembles, such as statement handles, are also
defined in this specification. Any of the ensembles MAY support abbreviation
of its subcommands according to the rules defined by
'''Tcl_GetIndexFromObj'''; nevertherless, code that uses the database
interface SHOULD spell out subcommands in full.

Many of the subcommands are expected to take options in Tcl's usual syntax of:

 > ?''-option'' ?''value''?? ?''-option value''?...

In all of the places where this syntax is expected, a database module MAY
support abbreviation of options according to the rules of
'''Tcl_GetIndexFromObj()'''; once again, code that uses the interface SHOULD
spell out options in full.

All the database objects (connections, statements and result sets) are "duck
typed" - that is, "If it walks like a duck and quacks like a duck, I would
call it a duck. (James Whitcomb Riley)." In other words, the ensembles may be
implemented using any available functionality as long as the result is that
they use the interfaces described. Nevertheless, as a convenience to
implementors, a set of base classes, called '''tdbc::connection''',
'''tdbc::statement''', and '''tdbc::resultset''', SHALL be provided using
Tcl's native object orientation as described in [257]. Certain advantages will
accrue to database implementors by using these base classes. In particular,
the '''tdbc::*''' classes SHALL do all the bookkeeping needed to determine
what statements and result sets are open, SHALL provide the internal iterators
'''allrows''' and '''foreach''', SHALL implement the '''transaction''' method
on connections, and SHALL ensure that the '''close''' method on the objects
functions the same as renaming the object to the null string.

~~ Configuring a Database Handle

Once a handle is returned, there are a number of session-level attributes that
may be controllable. Every database handle MUST provide a '''configure'''
subcommand that takes the form:

 > ''dbHandle'' '''configure''' ?''-option'' ?''value''?? ?''-option
   value''?...

This configuration process is analogous to configuring a Tk widget. If there
are no arguments presented to '''configure''', the return value MUST be a list
of alternating options and values describing the configuration parameters
currently in effect. If a single argument is presented, it MUST be the name of
a configuration parameter, and the return value MUST be current value for that
parameter. Finally, if more than one argument is presented, they MUST be a
list of alternating parameter names and values. This last form is an order to
set the given parameters to the given values.

The connectivity layer SHOULD implement the following parameters, and MAY
implement others:

(''Note:'' an earlier draft of this TIP specified a '''-autocommit''' option;
this option has been removed because it is redundant with the transaction
management primitives below.)

 * '''-encoding''' ''name''

 > Requests that the encoding to be used in database communication protocol be
   changed to the one given by ''name'', which MAY be any name acceptable to
   the [[encoding]] command. A well-designed database interface SHOULD NOT
   require this command; however, some backends make it virtually inevitable
   that mid-stream changes of encodings will be required.

 * '''-isolation''' ''level''

 > Requests that transactions performed on the database be executed at the
   given isolation ''level''. The acceptable values for ''level'' are:

 > * '''readuncommitted'''

 > > Allows the transaction to read "dirty", that is, uncommitted data. This
     isolation level may compromise data integrity, does not guarantee that
     foreign keys or uniqueness constraints are satisfied, and in generall
     does not guarantee data consistency.

 > * '''readcommitted'''

 > > Forbids the transaction from reading "dirty" data, but does not guarantee
     repeatable reads; if a transaction reads a row of a database at a given
     time, there is no guarantee that the same row will be available at a
     later time in the same transaction.

 > * '''repeatableread'''

 > > Guarantees that any row of the database, once read, will have the same
     values for the life of a transaction. Still permits "phantom reads" (that
     is, newly-added rows appearing if a table is queried a second time).

 > * '''serializable'''

 > > The most restrictive (and most expensive) level of transaction isolation.
     Any query to the database, if repeated, will return precisely the same
     results for the life of the transaction, exactly as if the transaction is
     the only user of the database.

 > * '''readonly'''

 > > Behaves like '''serializable''' in that the only results visible to the
     transaction are those that were committed prior to the start of the
     transaction, but forbids the transaction from modifying the database.

 > A database that does not implement one of these isolation levels SHOULD
   instead use the next more restrictive isolation level. If the given level
   of isolation cannot be obtained, the database interface MUST throw an error
   reporting the fact.  The default isolation level SHOULD be at least
   '''readcommitted'''.

 > A database interface MAY forbid changing the isolation level when a
   transaction is in progress.

 * '''-timeout''' ''ms''

 > Requests that operations requested on the database SHOULD time out after
   the given number of milliseconds, if such an option is supported by the
   underlying connectivity layer.

 * '''-readonly''' ''boolean''

 > Notifies that the application will, or will not, limit its activity to
   operations that do not modify the content of the database. This option MAY
   have the effect of adjusting the transaction isolation level.

The command that returns a database handle SHOULD also accept these options.

~~ Transaction Isolation

A database handle MUST implement the three subcommands '''starttransaction''',
'''commit''' and '''rollback''':

 > ''dbHandle'' '''starttransaction'''

Begins an atomic transaction on the database. If the underlying database does
not implement atomic transactions or rollback, the '''starttransaction'''
subcommand MUST throw an error reporting the fact.

If the underlying database does not implement nested transactions, a
'''starttransaction''' command that is executed when there is a transaction
already in progress (started, but neither committed nor rolled back) MUST
result in an error.

 > ''dbHandle'' '''commit'''

Commits a transaction to the database, making the changes durable.

 > ''dbHandle'' '''rollback'''

Rolls back a transaction against the database, cancelling any changes made
during the transaction.

Statements executed against the database when no transaction is in progress
(before the first '''starttransaction''' or after all started transactions
have been either committed or rolled back) SHOULD be ''auto-committed''; that
is, each such statement SHOULD be executed as if a '''starttransaction'''
command preceded the statement and a '''commit''' command followed it
(assuming that the statement succeeded; errors should result in '''rollback'''
of course).

These commands are provided primarily to support the construction of
higher-level operations. In particular, most simple transactions against a
database can be handled using the '''transaction''' command:

 > ''dbHandle'' '''transaction''' ''script''

Executes the given ''script'' with transaction isolation. In this command, the
''dbHandle'' argument is a handle to a database connection, and the ''script''
argument is a Tcl script to be evaluated in the calling scope. The script is
treated as a single atomic database transaction. The '''starttransaction'''
command is executed against the given database connection, and then the
''script'' is evaluated. If it completes successfully (''TCL_OK''), the
transaction SHALL be committed to the database.  If it fails, (''TCL_ERROR''),
the transaction SHALL be rolled back and not visible to other users of the
database. ''TCL_BREAK'', ''TCL_CONTINUE'' and ''TCL_RETURN'' SHALL result in a
commit and subsequently rethrow the same exception status outside the
transaction. Exception status codes other than these five SHALL rollback the
transaction and be rethrown.

(''Note:'' Scripts inside a '''transaction''' command SHOULD avoid use of the
'''return -code''' or '''return -level''' operations. If a script returns from
a transaction, with any combination of return options, the transaction SHALL
be committed.)

Just as with '''starttransaction''', if a [[''dbHandle'' '''transaction''']]
command is executed while another transaction is already in progress, it is
requesting nested transaction semantics. A database handle to an engine that
supports nested transactions MUST treat this case correctly; a database handle
to an engine that does not support nested transactions (including one that
does not support transactions at all) MUST throw an error.

The '''transaction''' subcommand SHALL be provided by the
'''tdbc::connection''' base class; database interfaces that use the TclOO
features and the TDBC base classes do not need to implement it.

~~ Closing a Database Connection

A database handle MUST implement the command:

 > ''dbHandle'' '''close'''

This command MUST dismiss the connection to the database and is expected to
clean up the system resources associated with it. If there is an uncommitted
transaction, it SHOULD be rolled back. Any handles to other objects associated
with the database SHOULD become invalid.

A database interface also SHOULD perform the same actions if a handle is
deleted by means of the '''rename''' command. (Interfaces that are implemented
in Tcl may be notified of this action by creating a deletion trace with
'''trace add command'''.) It is recognized that command deletion traces
present difficulties in situations like namespace and interpreter deletion;
the '''close''' subcommand shall therefore be considered the preferred way to
terminate connections.

A database interface SHOULD attempt to arrange, if possible, to rollback
unfinished transactions and clean up on process exit. In particular, if the
underlying database engine supports transactions, it SHOULD be considered an
error to commit any work that remains uncommitted on process exit.

The '''close''' command SHALL be provided by the '''tdbc::connection''' base
class; database interfaces that use the TDBC base classes do not need to
implement it. The base class implementation destroys the object using '''my
destroy'''. As a result, any statements obtained from the connection are also
destroyed, since they are stored in a namespace that is subordinate to the
connection's namespace. The destructor of the connection object is expected to
close the underlying database connection and release any system resources
associated with it.

~~ Preparing Statements

A database handle must support the '''prepare''' command, which has the
syntax:

 > ''dbHandle'' '''prepare''' ''SQL-code''

The ''SQL-code'' argument is a SQL statement that is to be executed against
the given database connection. This command does not execute the statement
directly; rather, it prepares to execute the statement, possibly performing
tasks such as code compilation and query optimisation.

The database interface MUST support substitutions in ''SQL-code''. Each
substitution request has the form '':variableName''. That is, each
substitution request begins with a literal colon (:), followed by a letter or
underscore, followed by zero or more letters, digits, or underscores. The
database interface is responsible for translating from this syntax to whatever
the underlying engine requires. Typical strings required in database
interfaces are '':name'', '':number'', ''@name'', ''@number'', and ''?''.

The return value from the '''prepare''' command is a ''statement handle'',
discussed under "The statement interface" below.

''Rationale.'' The choice of the colon deserves some discussion. It would
surely be more natural for Tcl to use a literal dollar sign to introduce a
variable name. This choice, however, seems unwise, since several databases
(most notably Oracle) allow the use of table and view names that contain
dollar signs. While it might be possible to continue to use these while
allowing for variable substitution (for instance, by mandating that table or
view names with dollar signs be enclosed in double quotes), it seems
unnatural. The colon is syntax that is recognized by JDBC, ODBC, and Oracle's
native API, and as such will be familiar to most SQL programmers and unlikely
to collide with native syntax.

The requirement to support prepared statements is intended to guard against
SQL insertion attacks. An interface to a database whose native API does not
support prepared statements MUST simulate them. In particular, when the
'''execute''' command is executed on a statement, substitution must be
performed in a safe fashion with whatever magic quoting is required. In any
case, magic quoting should be regarded as an infelicitous expedient and
avoided if at all possible.

If a database interface uses the '''tdbc::connection''' base class, then a
'''prepare''' method will be provided for it. If this method is not
overridden, then the database interface MUST arrange that the constructor of
the connection sets the instance variable, ''statementClass'', to the fully
qualified name of the command that constructs statements. The '''prepare'''
method SHALL invoke that command with a call of the form:

 > ''statementClass'' '''create''' ''handle'' ''connectionHandle'' ''sql''

where ''handle'' is the name of the new statement being created,
''connectionHandle'' is the handle to the connection creating it, and ''sql''
is the SQL statement being prepared.

~~ Stored Procedure Calls

A second way to prepare statements is to prepare a stored procedure call. If a
database interface supports stored procedures, it MUST support the
'''preparecall''' command:

 > ''dbHandle'' '''preparecall''' ''call''

''call'' is a string that describes a call to a stored procedure. It takes
the form:

 > ?'':varName'' '''='''? ''procName'' '''(''' ?'':varName''?  ?''','''
   ''varName''?...  ''')'''

The result of the '''preparecall''' command is a statement handle. The
statement handle may be used just as any other statement handle.

The '''preparecall''' method SHALL ''not'' be provided in the
'''tdbc::connection''' base class; individual database interfaces are expected
to do so. They MAY do so by rewriting the call to whatever syntax the native
database requires, and delegating to the '''prepare''' method to prepare that,
or they MAY instead prepare another ensemble. (See "The TDBC base classes"
below for details of integrating this mechanism with the base classes.)

~~ Quasi-Direct Execution

A database handle MUST support the following two calls:

 > ''dbHandle'' '''allrows''' ?'''-as''' ''lists''|''dicts''?
   ?'''-columnsvariable''' ''varName''? ?'''--'''? ''sql'' ?''dictionary''?

This command prepares the SQL statement given by the ''sql'' parameter, and
immediately executes it. Variable substitutions inside the ''sql'' parameter
are satisfied from the given ''dictionary'', if one is supplied, and from
variables in the caller's scope otherwise. The '''-as''' option determines the
form of the result, and the '''-columnsvariable''' option provides an optional
variable in which the names of the result columns will be stored. Upon
termination of the command, whether successful or unsuccessful, the prepared
statement is closed. The command returns a list of the rows returned by the
affected statement. (If the affected statement does not yield a set of rows,
the return value from the ''allrows'' command is an empty list.)

This command MUST function the same way as preparing the statement explicitly,
executing the '''statement allrows''' call (see below) on the resulting
statement handle, and then (irrespective of whether the operation succeeeded)
destroying the statement handle.

 > ''dbHandle'' '''foreach'''?'''-as''' ''lists''|''dicts''?
   ?'''-columnsvariable''' ''varName''? ?'''--'''? ''sql'' ?''dictionary''?
   ''varName'' ''script''

This command prepares the SQL statement given by the ''sql'' parameter, and
immediately executes it. Variable substitutions inside the ''sql'' parameter
are satisfied from the given ''dictionary'', if one is supplied, and from
variables in the caller's scope otherwise. The '''-as''' option determines the
form of the result, and the '''-columnsvariable''' option provides an optional
variable in which the names of the result columns will be stored. For each row
returned by the given statement, the given ''varName'' is set to a list or
dictionary containing the returned row, and the given ''script'' is executed
in the caller's scope. Upon termination of the command, whether successful or
unsuccessful, the prepared statement is closed.

This command MUST function the same way as preparing the statement explicitly
and then executing the ''statement'' '''foreach''' call on the resulting
statement handle.

Both of these commands SHALL be provided in the '''tdbc::connection''' base
class.

~~ Introspecting the Sets of Handles

A database handle MUST support the '''statements''' command:

 > ''dbHandle'' '''statements'''

This command MUST return a list of the statements that have been prepared by
means of [[''dbHandle'' '''prepare''']] but not yet dismissed using
[[''statementHandle'' '''close''']].

Likewise, a database handle MUST support the '''resultsets''' command:

 > ''dbHandle'' '''resultsets'''

This command MUST return a list of the result sets that have been returned (by
executing statements, or by querying metadata) and have not yet been dismissed
using [[''resultSetHandle'' '''close''']].

Both of these commands SHALL be provided in the ''tdbc::connection'' base
class. Using the base class implementations imposes certain restrictions on
derived classes. (See "The TDBC base classes" below for details of integrating
this mechanism with the base classes.)

~~ Querying Metadata

A database interface MUST provide a way of enumerating the tables in the
database. The syntax for querying tables MUST be:

 > ''dbHandle'' '''tables''' ?''matchPattern''?

The optional argument ''matchPattern'', if supplied, is a pattern against
which the table names are to be matched. The database interface MUST recognize
the SQL wildcards '''%''' and '''_''' in the pattern.

A database interface MUST provide a way of enumerating the columns in a
database table. The syntax for querying columns MUST be:

 > ''dbHandle'' '''columns''' ''tableName'' ''?matchPattern?''

The return value from the '''tables''' and '''columns''' commands MUST be a
dictionary. The keys of the dictionary MUST be the names of the tables in the
database, or respectively the columns in the given table.

The values stored in the dictionary returned from the '''tables''' command
MUST be dictionaries. The keys and values of these dictionaries, nevertheless,
are implementation-defined; only the keys are mandated in this specification.

The values stored in the dictionary returned from the '''columns''' command
MUST themselves be dictionaries. These subdictionaries MUST include the keys,
'''type''', '''precision''', '''scale''', and '''nullable'''. The '''type'''
value MUST be the data type of the column, and SHOULD be chosen from among the
standard types ''bigint'', ''binary'', ''bit'', ''char'', ''date'',
''decimal'', ''double'', ''float'', ''integer'', ''longvarbinary'',
''longvarchar'', ''numeric'', ''real'', ''time'', ''timestamp'', ''smallint'',
''tinyint'', ''varbinary'', and ''varchar'. The '''precision''' and
'''scale''' values SHOULD give the precision and scale of the column, and the
'''nullable''' value SHOULD give a boolean value that represents whether the
given column can contain NULL values.

Other keys MAY be included in the subdictionaries returned from '''tables'''
and '''columns''', and SHALL be added to this document (as optional columns)
on request from the implementors of database interfaces.

~~ The Statement Interface

The statement handle returned from the '''prepare''' command on a database
interface must itself be an ensemble. The following subcommands MUST be
accepted:

 > ''statementHandle'' '''params'''

Requests a description of the names and expected data types of the parameters
to the given statement. The return value from the '''params''' command MUST be
a dictionary whose keys are the names of the parameters and whose values are
themselves dictionaries.  The keys of the subdictionaries MUST include
''name'', ''type'', ''precision'', ''scale'', and ''nullable''. They are
interpreted in the same way as those of the '''columns''' subcommand to a
database interface (shown above). The subdictionaries also MUST include the
key, ''direction'', whose value identifies the direction of parameter
transmission, and MUST be chosen from among ''in'', ''out'' and ''inout''.

 > ''statementHandle'' '''execute''' ?''dictionary''?

Executes a statement against a database. Any variable substitution present in
the SQL that was provided when the statement was created MUST be performed at
this time. The variable values MUST be obtained from the given ''dictionary'',
if one is supplied. If the dictionary does not contain a key equal to a
variable name in the statement, a NULL value MUST be provided.

If the ''dictionary'' argument is omitted, the variable values MUST be
obtained from the scope in which the '''execute''' command was evaluated.  Any
variable that is undefined in that scope must be replaced with a ''NULL''
value. An array variable provided to a substituent MUST result in an error.
Read traces against the substituted variables SHOULD fire, in left-to-right
order as they appeared in the SQL statement. The result of the '''execute'''
command SHOULD be a result set, as defined under "The result set interface"
below.

This method is provided by the '''tdbc::connection''' base class. In the base
class, it works by creating an instance of the class whose name appears in the
'''statementClass''' instance variable. See "The TDBC base classes" below for
the details of how the derived classes should be implemented to avail
themselves of this method.

 > ''statementHandle'' '''close'''

Announces that a statement is no longer required, and frees all system
resources associated with it. The '''close''' command MAY invalidate any
result sets that were obtained by the '''params''' and '''execute''' commands.

As with database connections, the database interface SHOULD also clean up if a
statement handle is removed with ''[[rename $statement {}]]''. Once again, it
is recognized that the strange side effects of namespace and interpreter
deletion may make this cleanup impossible in some interfaces, so '''close'''
SHALL be considered the standard means of discarding statements.

The ''close'' command SHALL be provided in the ''tdbc::statement'' base class.
Database interfaces that use the TDBC base classes do not need to implement
it. The base class implementation destroys the object using '''my destroy'''.
As a result, any result sets obtained from the statement are also destroyed,
since they are stored in a namespace that is subordinate to the statement's
namespace. The destructor of the statement object is expected to release any
system resources associated with it.

~~~ Data Types of Parameters to Prepared Statements

The syntax described so far presumes that the database interface can determine
the expected types of the variables that appear in a prepared statement, or at
the very least can accept some sort of variant type and perform automatic type
coercion. This requirement does not seem horribly onerous at first inspection,
since SQLite allows for "everything is a string" parameters; ODBC offers
parameter introspection via the ''SQLDescribeParam'' call; and JDBC offers it
via the ''getParameterMetaData'' method of the ''PreparedStatement''
interface.

Nevertheless, a deeper examination discovers that in at least ODBC, a driver
is allowed to fail to offer ''SQLDescribeParam''. Inspection of the JDBC-ODBC
bridge reveals that in this case, JDBC will return a ''ParameterMetaData''
object that throws a ''SQLException'' on any attempt to query specific data.
The result is that, while the APIs to introspect parameter types are
available, they may be unusable against a particular database engine. In these
cases, a backup is needed.

For this reason, a database interface MUST support allowing the user to
specify types of the parameters of a prepared statement. The syntax for doing
so MUST be:

 > ''statementHandle'' '''paramtype''' ''paramName'' ?''direction''?  ''type''
   ?''precision''? ?''scale''?

Defines that the parameter identified by ''paramName'' in the given statement
is to be of type ''type''. The ''type'' MUST be chosen from among the names
''bigint'', ''binary'', ''bit'', ''char'', ''date'', ''decimal'', ''double'',
''float'', ''integer'', ''longvarbinary'', ''longvarchar'', ''numeric'',
''real'', ''time'', ''timestamp'', ''smallint'', ''tinyint'', ''varbinary'',
and ''varchar''.

(''Rationale:'' These types appear to suffice for ODBC, and we can always come
back and extend them later if needed.)

The ''precision'' of a parameter defines the number of characters or digits
that it requires, and its ''scale'' defines the number of digits after the
decimal point, if neeeded. A database interface MAY allow negative numbers for
''scale'' in contexts where they make sense. For example, a ''scale'' of -3,
if allowed, SHOULD indicate that quantities in the given column are all
multiples of 1000. The ''precision'' and ''scale'' are not required by all
types.

A ''direction'' must be one of the words, '''in''', '''out''' or
'''inout'''. It specifies that the given parameter is an input to the
statement, an output from the statement, or both. It is usually meaningful
only in stored procedure calls. Default is '''in''', unless the parameter
appears on the left-hand side of an equal side in a stored procedure call, in
which case the default is '''out'''.

~~~~Examples

| $statement paramtype name varchar 40
| $statement paramtype balance in decimal 10 2
| $statement paramtype transactionDate timestamp

Implementors of database APIs SHOULD make every effort to do appropriate type
introspection so that programmers can avoid needing to include explicit type
information in their SQL statements.

~~~ Internal Iterators

A statement handle MUST support the following two calls:

 > ''statement'' '''allrows''' ?'''-as''' ''lists''|''dicts''?
   ?'''-columnsvariable''' ''varName''? ?'''--'''? ?''dictionary''?

This command executes the given ''statement''. Variable substitutions inside
the statement are satisfied from the given ''dictionary'', if one is supplied,
and from variables in the caller's scope otherwise. The '''-as''' option
determines the form of the result, and the '''-columnsvariable''' option
provides an optional variable in which the names of the result columns will be
stored. Upon termination of the command, whether successful or unsuccessful,
the prepared statement is closed. The command returns a list of the rows
returned by the affected statement. (If the affected statement does not yield
a set of rows, the return value from the ''allrows'' command is an empty
list.)

This command MUST function the same way as executing the statement explicitly
(with the given ''dictionary'' argument if one is supplied), executing the
''resultset'' '''allrows''' call (see below) on the resulting result set, and
then (irrespective of whether the operation succeeeded) destroying the result
set.

 > ''statement'' '''foreach'''?'''-as''' ''lists''|''dicts''?
   ?'''-columnsvariable''' ''varName''? ?'''--'''? ?''dictionary''?
   ''varName'' ''script''

This command executes the given ''statement''. Variable substitutions inside
the statement are satisfied from the given ''dictionary'', if one is supplied,
and from variables in the caller's scope otherwise. The '''-as''' option
determines the form of the result, and the '''-columnsvariable''' option
provides an optional variable in which the names of the result columns will be
stored. For each row in the result set, the given ''varName'' is set to a list
or dictionary containing the returned row, and the given ''script'' is
executed in the caller's scope. Upon termination of the command, whether
successful or unsuccessful, the result set is closed.

This command MUST function the same way as executing the statement explicitly,
executing the ''resultset'' '''foreach''' call on the resulting statement
handle, and then (irrespective of whether the operation succeeded) closing the
result set.

Both of these commands SHALL be provided in the '''tdbc::statement''' base
class.

~~ The Result Set Interface

Result sets represent the results of operations performed on the database. A
preferred implementation for large result sets is that they be implemented as
database cursors, so that it is possible to iterate over result sets that will
not fit in memory. A result set MUST be an ensemble. The following subcommands
MUST be accepted:

 > ''resultSetHandle'' '''rowcount'''

Determines the number of rows affected by a SQL statement such as
'''INSERT''', '''DELETE''' or '''UPDATE'''. This count MUST be returned as an
integer. It should not be confused with the number of rows in the result set.
A database interface need not provide any interface to determine the latter
number (often, the only way to determine it is to read all the rows). For this
reason, the '''rowcount''' command MAY return an empty string, or a
non-positive number, for '''SELECT''' operations (and any other operations
that do not modify rows of the database).

 > ''resultSetHandle'' '''columns'''

Determines the set of columns contained in the result set. The set of columns
is returned simply as a list of column names, in the order in which they
appear in the results.

 > ''resultSetHandle'' '''nextrow''' ?'''-as''' '''lists|dicts'''? ?'''--'''?
   ''variableName''

(This interface SHALL be provided by the '''tdbc::resultset''' base class. The
default implementation SHALL delegate to either the '''nextlist''' or
'''nextdict''' methods, below.

Fetches a row of data from the result set and stores it in the given variable
in the caller's context.

If '''-as dicts''' is specified (the default), the row MUST be represented as
a dictionary suitable for use with the '''dict''' command. The keys in the
dictionary SHALL be the column names, and the values SHALL be the values of
the cells. If no rows remain, the '''nextrow'' command MUST store an empty
dictionary. If a cell in the row is NULL, the key MUST be omitted from the
dictionary. A database interface MUST NOT use a special value of any kind to
represent a NULL in a dictionary.

If '''-as lists''' is specified, the row MUST be represented as a list of
values, in the order in which they appear in the query. (If the statement is a
stored procedure call, the values comprise all the '''out''' or '''inout'''
parameters.) If no rows remain, the '''nextrow''' command MUST store an empty
list. If a cell in the row is NULL, an empty string MUST be stored as its
value.

The return value of ''nextrow'' MUST be 1 if a row has been returned, and 0 if
no rows remain in the result set.

In the result set, values of type ''bigint'', ''bit'', ''decimal'',
''double'', ''float'', ''integer'', ''numeric'', ''real'', ''smallint'', and
''tinyint'' MUST receive their natural representation as decimal numbers.
Ideally, they should be returned as "pure" numbers with their string
representations generated only on demand. Values of type ''char'',
''longvarchar'' and ''varchar'' MUST be returned as Tcl strings. ''A database
interface implemented in C ''MUST'' take care that all strings are well-formed
UTF-8.'' Values of type ''date'' and ''timestamp'' MUST be returned as a
numeric count of seconds from the Tcl epoch; if necessary, this count may have
a decimal point and an appropriate number of additional decimal places
appended to it. Values of type ''time'' MUST be returned as a integer count of
seconds since midnight, to which MAY be appended a decimal point and a
fraction of a second. Values of type ''binary'', ''longvarbinary'' and
''varbinary'' MUST be returned as Tcl byte arrays.

''Rationale:'' Dictionaries and lists are both useful in representing the
result set rows. Dictionaries allow for a ready distinction between NULL
values in a database and any other string. With any scheme where values that
can include NULLs can appear in Tcl objects, the problem arises that NULL must
be distinguished from any other string, particularly including the empty
string and the word "NULL". The lack of such a distinction has led to several
ill-advised proposals, such as [185], for representing NULLs in Tcl. These
alternatives founder on the principle of "everything is a string". The NULL
value is not any string. Dictionaries also have the advantage that results can
be addressed by name rather than by position.  On the other hand, lists are
convenient when formatting tabular results from ''ad hoc'' queries. The
brevity of code that can be achieved with them is also attractive. For this
reason, this TIP requires both formats to be made available.

 > ''resultSetHandle'' '''nextdict''' ''variableName''

 > ''resultSetHandle'' '''nextlist''' ''variableName''

These two calls are precisely equivalent to calls to the '''nextrow''' command
with the '''-as dicts''' and '''-as lists''' option respectively. A database
interface MUST provide both of these, and they are the fundamental means for
retrieving rows from the result set.

 > ''resultSetHandle'' '''close'''

Dismisses a result set and releases any system resources associated with it.

As with statements and database connections, the database interface SHOULD
also clean up if a resut set handle is removed with ''[[rename $statement
{}]]''. Once again, it is recognized that the strange side effects of
namespace and interpreter deletion may make this cleanup impossible in some
interfaces, so '''close''' SHALL be considered the standard means of
discarding result sets.

The '''close''' command SHALL be provided by the '''tdbc::resultset''' base
class. The base class implementation destroys the object using '''my
destroy'''. The destructor of the result object is expected to release any
system resources associated with it.

~~~ Internal Iterators

A result set handle MUST support the following two calls:

 > ''resultset'' '''allrows''' ?'''-as''' ''lists''|''dicts''?
   ?'''-columnsvariable''' ''varName'' ?'''--'''?

This command executes the '''nextrow''' command repeatedly, producing a list
of dictonaries or of lists (according to the value of the '''-as''' option).
The '''allrows'''command returns the resulting list. Optionally, the names of
the columns of the result set are also stored in the named variable given by
the '''-columnsvariable''' option.

 > ''statement'' '''foreach'''?'''-as''' ''lists''|''dicts''?
   ?'''-columnsvariable''' ''varName''? ?'''--'''? ''varName'' ''script''

This command optionally stores the names of the columns of the result set in
the variable designated by the '''-columnsvariable''' option. It then executes
the '''nextrow''' command repeatedly until all rows of the result set have
been processed. The '''nextrow''' command receives the given '''varName''' and
'''-as''' option, and stores the row in the named variable. For each row
processed, the given '''script''' is executed in the caller's scope.

Both of these commands SHALL be provided in the '''tdbc::resultset''' base
class.

~~ The TDBC Base Classes

Most implementations of database drivers SHOULD, as mentioned before, use Tcl
objects (as in [257]) that inherit from the '''tdbc::connection''',
'''tdbc::statement''' and '''tdbc::resultset''' classes. The foregoing
discussion has described the user-visible methods that are provided by doing
so (and must otherwise be implemented). This section is directed to the driver
implementor, and discusses certain necessary housekeeping issues.

~~~ Database Connections

However a database connection object is constructed, its constructor will need
to seize resources (such as opening a database connection to the underlying
database system). If the bookkeeping done by the base classes is to work
correctly, initialization of the '''tdbc::connection''' base class needs to
happen before external resources are seized. In addition, if the '''prepare'''
method is not overloaded (and the driver SHOULD NOT have to overload it), the
name of the class that implemements the statement interface needs to be
provided at this time. The recommended sequence for connection construction
is:

|  constructor args {
|      next;                         # Initialize tdbc::connection
|      my variable statementClass
|      set statementClass ::whatever;# Tell tdbc::connection what
|                                    # class must be instantiated by
|                                    # the 'prepare' method
|      my init {*}$args              # Perform implementation-specific
|                                    # initialization
|  }


Some database interfaces have a different API to stored procedures than to
ordinary SQL statements. These databases may need a separate type of statement
object from the one that implements ordinary statements. This object can be
managed as a statement owned by the connection by using a '''prepareCall'''
method that looks like:

|  method prepareCall {call} {
|      my variable statementSeq;   # Provided in the
|                                  # tdbc::connection base class
|      return [preparedStatementClass create \
|                  Stmt::[incr statementSeq] [self] $call]
|  }

In this call, '''preparedStatementClass''' is the name of the class that

implements prepared statements. Its constructor is expected to accept two
arguments: the handle to the database connection, and the prepared statement
that was passed to prepareCall. Placing the resulting object inside the
'''Stmt''' namespace under the current object (this namespace is created by
the constructor of '''tdbc::connection''') allows for its destruction to be
sequenced correctly when the connection is destroyed.

The methods that a derived class from '''tdbc::connection''' MUST implement
are '''prepareCall''', '''begintransaction''', '''commit''', and
'''rollback'''. In addition, system resources belonging to the connection
itself MUST be cleaned up by a destructor or by a deletion callback at C
level. (Statements and result sets MUST not be deleted then; the base classes
take care of that.) See "Best practices for memory management" below for
further discussion.

~~~ Statements

The class that implements a statement SHOULD normally inherit from the
'''tdbc::statement''' base class. Its constructor accepts the connection
handle and the SQL statement to prepare. The constructor is responsible for
invoking the base class constructor with '''next''', setting an instance
variable ''resultSetClass'' to the name of the class that implements its
result set, and then preparing the statement. (The constructor is invoked by
the '''prepare''' method of '''tdbc::connection.) A sample constructor looks
like:

|  constructor {connection sql} {
|      next;                        # initialize the base class
|      my variable resultSetClass 
|      set resultSetClass whatever; # Tell the base class what class
|                                   # to use for result sets
|      my init $connection $sql;    # The [[init]] method should do
|                                   # whatever is necessary to prepare
|                                   # the statement
|  }


Derived classes from '''tdbc::statement''' MUST also implement the
'''params''' and '''paramtype''' methods. In addition, system resources
belonging to the statement itself MUST be cleaned up by a destructor or by a
deletion callback at C level. (Result sets MUST not be deleted then; the base
classes take care of that.) See "Best practices for memory management" below
for further discussion.

~~~ Result Sets

The class that implements a result set SHOULD normally inherit from the
'''tdbc::resultset''' base class. Its constructor accepts the statement handle
and the arguments to the '''execute''' method. The constructor is responsible
for invoking the base class constructor with '''next''', and executing the
statement. A sample constructor looks like:

|  constructor {statement args} {
|      next
|      uplevel 1 [list {*}[namespace code {my init}] $statement {*}$args]
|  }


Note the peculiar form of invocation for the '''init''' method in the example
above. Since the '''init''' method needs access to local variables in the
caller's context to do variable substitution, it needs to be executed at the
same stack level as the constructor itself. The [[namespace code {my init}]]
call gives a command prefix that can be used to invoke the method in a foreign
context, and this command is then executed with [[uplevel 1]] to do the
initialization.

Besides the constructor and '''init''', the other methods that a result set
class MUST implement are '''columns''', '''nextrow''', and '''rowcount'''. In
addition, a destructor (or a C deletion callback) MUST clean up any system
resources belonging to the result set.

~~~ Best Practices for Memory Management in Database Interfaces

Since the TclOO interfaces are so new, it seems wise to give developers of
database interfaces written in C some guidance about effective ways to manage
memory. A C-level extension, if written correctly, gets considerable
assistance in releasing memory at the appropriate times from TclOO and the
tdbc base classes.

When a database interface is first loaded as an extension, it is entered
through its ''PackageName''_'''Init''' function. It will call, in order,
'''Tcl_InitStubs''', '''Tcloo_InitStubs''', and '''Tdbc_InitStubs''' so that
Tcl, the TclOO system, and the TDBC base classes are all available. Its next
task is to allocate any per-interpreter data that may be required. (In the
case of the '''tdbc::odbc''' bridge, the per-interpreter data include an ODBC
environment handle and a string literal pool.) The per-interpreter data
structure SHOULD be reference counted, since the order of destruction of the
objects that refer to it is unpredictable. Next, the initialization function
creates the classes, usually by evaluating an initialization script containing
a call to '''tcl_findLibrary''', where the Tcl code contains the skeletons of
the class definitions. With the class definitions in hand, methods that are
implemented in C can be attached to them. Any methods that need the
per-interpreter data can receive it as ClientData. The reference count of the
per-interpreter data SHOULD be incremented for these, and the method delete
procedures should be responsible for decrementing the reference count.

Each of the three classes that make up a database interface SHOULD have a
reference-counted data structure to hold any instance data. This structure
SHOULD be created within the '''init''' method, and attached to the object
with '''Tcl_ObjectSetMetadata'''. The metadata type structure SHOULD designate
a delete procedure that decrements the reference count. The type structure MAY
designate a clone procedure that returns '''TCL_ERROR'''; it is entirely
permissible for TDBC objects not to be clonable.

Generally speaking, each object's instance data structure will contain a
pointer to (and hold a counted reference to) the next higher object in the
ownership hierarchy. A result set will refer to the statement that produced
it; a statement will refer to the connection in which it executes, and a
connection will refer to the per-interp data.

With this infrastructure in place, object destruction becomes strictly a local
matter. Any object, when its reference count becomes zero, MUST release any
system resources that belong to it, and decrement the reference count of the
next object up. There is no need for a connection to track its statements, or
a statement to track its result sets. This happens automatically because the
'''prepare''' and '''execute''' methods create statements in a namespace
subordinate to the namespace of the owning connection, and create result sets
in a namespace subordinate to that of the owning statement. When the owning
objects are destroyed, the subordinate namespaces are also destroyed, invoking
the destructors of the objects within them.

This whole scheme is simpler than it sounds, and is observed to work well for
the '''tdbc::odbc''' bridge (see the source code of the bridge for further
details).  Closing a connection gracefully deletes the statement and result
class objects (in Tcl) from top to bottom, and then deletes the corresponding
C data structures from bottom to top, finally cleaning up the connection data
itself.

Note that, since TclOO does not guarantee to run destructors on '''exit''', if
a database interface needs to always close the underlying connection on
termination, the implementation code should install an exit handler with
'''Tcl_CreateExitHandler''' if it needs to.

~~ Support Procedures for Implementors of Database Interfaces

In addition to the convenience commands discussed above, the Tcl system SHALL
provide certain commands to aid the job of database implementors.

~~~ SQL Tokenisation

The task of mapping variable substituions in the form, ''':varName''' into
whatever form that a native database API can handle is a somewhat tricky one.
For instance, substitutions that appear inside quoted strings MUST NOT be
mapped. In order to aid in this task, the Tcl system SHALL provide a command,
'''::tdbc::tokenize'''. This command SHALL accept a SQL statement as its sole
parameter, and return a list of tokens. The lexical value of the tokens can be
distinguished by their first characters:

   * '$', ':' and '@' are all variable substitutions; the remainder of the
     token string is a variable name.

   * ';' is a statement separator, for databases that allow multiple
     statements to be prepared together.

   * '-' is a comment

   * Anything else is literal text to be copied into a SQL statement.

Assuming that a native database's lexical structure conforms with standard
SQL, the variable names can be substituted with parameter numbers, question
marks, or whatever the database needs, to yield the native SQL that must be
prepared.

Tokenisation is also available at the C level; to access it, a C extension
MUST first call '''Tdbc_InitStubs'''; it is a macro that behaves as if it is a
function with the type signature

 > int '''Tdbc_InitStubs'''(Tcl_Interp *''interp'');

where ''interp'' is a Tcl interpreter. The function returns '''TCL_OK''' if
successful, and '''TCL_ERROR''' (with an error message left in the
interpreter) in the case of failure.

The tokenisation is then available by calling 

 > Tcl_Obj *'''Tdbc_TokenizeSql'''(Tcl_Interp *''interp'', const char
   *''sqlCode'');

In this call, ''interp'' is a Tcl interpreter, and ''sqlCode'' is a SQL
statement to parse. If the parse is successful, the return value is a Tcl
object with a reference count of zero that contains a list of token strings as
with the '''tdbc::tokenize'' call.

~ References

This specification is largely built from studying existing cross-platform
database APIs and deriving a comon set of requirements from them. These
include both popular offerings in lower-level languages (ODBC and JDBC) and
Tcl-level ones (notably the 'nstcl-database' package, the SQLite API and
tclodbc).

"ODBC Programmer's Reference." Redmond, Wash.: Microsoft Corporation, 2007.
[http://msdn2.microsoft.com/library/ms714177.aspx].

"Java Platform Standard Edition 6 API Specification." Santa Clara, Calif.: Sun
Microsystems, 2007 [http://java.sun.com/javase/6/docs/api/]; in particular the
package named, '''java.sql'''.

Cleverly, Michael. "nstcl-database Package."
[http://nstcl.sourceforge.net/docs/nstcl-database/].

Hipp, D. Richard. "The Tcl interface to the Sqlite library."
[http://www.sqlite.org/tclsqlite.html].

Nurmi, Roy. "Tclodbc v 2.3 Reference." Available as part of the Tclodbc
distribution at [http://sourceforge.net/projects/tclodbc/], in the file,
'''DOC/REFERENC.HTM'''.

~ License

This file is explicitly released to the public domain and the author
explicitly disclaims all rights under copyright law.

----

~ Appendix. Additional Possibilities.

An earlier version of this TIP specified several more requirements for the
TDBC statement objects. In the current version, these requirements have been
lifted. The three areas that have been removed are batch processing,
asynchronous query handling, and references to cursors.

''Rationale:'' Specifying an interface like this one is always a tradeoff
between capability of the interface and burden upon the implementors. The
earlier requirement for handling these three areas seems improvident.

The handling of bulk data ("batch processing") is to a large extent a
performance issue. In most cases, if the performance of bulk data handling is
critical, an implementor will resort to a compiled language rather than to Tcl
to do so. The reporting of errors on bulk operations is complicated, as is the
specification of what will happen if certain parameter sets succeed while
others fail. The benefit of bulk data handling at the Tcl level was not deemed
adequate to justify the implementation complexity.

The handling of asynchronous queries is also chiefly a performance issue in
that it is intended to enable keeping a GUI live while long-running database
operations are in progress. This "keep the GUI alive during long operations"
requirement is equally well satisfied by performing database operations in a
separate thread (for a thread-enabled Tcl) or a separate subprocess, and these
techniques are familiar to Tcl programmers. For similar reasons, the ODBC
manual now formally deprecates using ODBC's asynchronous operations on
operating systems that support multithreading. Again, the benefits of
integrating TDBC into the event loop do not appear to justify the cost in
complexity to be gained.

References to cursors are a feature that is highly dependent on the underlying
database. It is not clear that the specification described below is even
readily implementable on all the platforms that have refcursors. Most of
these, in any case, provide some other way of achieving the same end. For
instance, Oracle allows returning a cursor by name, and then executing a
statment, "FETCH ALL FROM :cursorName", to retrieve the data from the cursor.
Again, here is a feature that adds complexity out of proportion to the
benefits achieved.

~~ Batch Processing

Some databases provide an interface to pass bulk data into a statement, in
order to provide an efficient means for doing tasks such as inserting a large
number of rows into a table at once. A statement handle MUST provide the
subcommands:

 > ''statement'' '''startbatch'''

Prepares to perform batch processing on the specified statement.  

 > ''statement'' '''addtobatch''' ''dictionary''

Adds the values given by ''dictionary'' into the specified statement. The
''dictionary'' argument is exactly the same as the ''dictionary'' argument to
[[''statement'' '''execute''']].

If no batch operation is in progress, the database interface MUST throw an
error.

 > ''statement'' '''executebatch'''

Executes the batch of operations accumulated by [[''statement''
'''addToBatch''']].

The result of '''executebatch''' MUST be a result set. The rows of the result
set are the result of concatenating the rows returned from the individual
operations.

If no batch operation is in progress, the database interface MUST return an
error.

If an underlying database does not support batch operations, the database
interface SHOULD simulate them by accumulating the data in memory and
executing the statement repeatedly when the '''executeBatch''' operation is
requested.

The database interface MUST return an error if an attempt is made to execute a
statement in the ordinary manner or to request a commit while there is an
unfinished batch in progress. A rollback, or closing the statement, or closing
the database connection, while a batch is in progress MUST result in
abandoning the batch without applying any changes to the database.

~~ Asynchronous Queries

Some database operations take a long time to complete. In order to avoid
freezing the event loop, a database interface MAY provide an asynchronous
query mechanism. If it does so, it MUST take the form:

 > ''resultSet'' '''whenready''' ''script''

In this interface, ''resultSet'' is the handle of a result set. The
'''whenready''' command requests that ''script'' be evaluated at the global
level once for each row of the result set, plus once after all rows have been
returned. The script SHOULD execute '''nextrow''' to retrieve the next row or
get the indication that no rows remain.

~~ References to Cursors

Some databases allow stored procedures to return references to cursors. If a
column of a result set contains a reference to a cursor, it MUST be
represented in Tcl as another result set handle. A Tcl script can then iterate
over this included result set to use the reference to a cursor.

The given result set MUST be destroyed upon the next call to ''nextrow''. For
this reason, Tcl code MUST not use the '''allrows''' command with a statement
that can return references to cursors.

----

~ Appendix. Change Summary

   2008-04-27: Removed asynchronous queries, refcursors, and batch updates
     from the main body of the spec. Performed a good bit of general cleanup
     to bring the spec back in line with the reference implementation being
     developed.

   2007-11-23: Expanded transaction management to have both the
     '''transaction''' command and explicit transaction boundaries. Added
     transaction isolation levels.

   > Added lists as an alternative to dicts as a representation of rows in
     result sets. Added a side interface for retrieving the set of column
     names in the convenience procedures.

   > Simplified introspection to return lists instead of result sets
<
|
<
|
|
|
|
|
|
|
|
|
|
>

|



|

|


|









|
|
|

|











|



|

|
|









|

|
|




|

|

|





|
|




|
|
|


|



|
|

|

|



|

|

|
|


|

|






|





|




|



|


|

|


|
|
|

|

|
|


|


|


|
|


|










|

|

|

|
|
|



|

|
|

|

|




|

|




|

|
|
|

|

|




|

|



|



|

|


|

|



|

|





|

|
|

|


|



|
|


|



|





|
|
|
|
|
|



|

|

|
|

|

|
|

|




|
|

|

|



|
|

|
|


|



|







|

|

|







|

|
|





|

|


|

|




|
|
|



|

|


|


|

|
|







|




|
|

|
|


|

|
|


|



|

|

|


|
|

|


|
|

|
|
|

|



|
|

|
|
|
|
|



|
|


|
|


|
|
|

|
|
|
|
|

|
|




|


|


|

|

|


|
|

|

|

|
|
|

|

|
|

|




|

|

|




|

|



|



|

|

|
|
|
|
|
|


|
|


|

|



|


|


|
|
|
|
|

|



|



|
|
|


|



|

|



|


|
|


|

|


|

|





|






|
|



|
|
|








|
|

|
|
|
|
|
|

|
|

|
|

|

|


|
|

|

|

|

|
|
|





|



|
|

|
|
|
|



|
|
|


|
|
|


|
|
|

|
|
|
|

|
|




|
|


|


|







|


|


|
|
|
|

|





|
|

|
|
|




|
|

|




|
|
|
|



|


|
|
|

|
|
|
|


|

|
|

|





|



|



|

|

|
|



|




|
|

|


|
|
|


|



|
|

|
|
|

|

|
|


|
|
|
|
|

|


|


|
|

|


|


|
|
|
|
|




|
|
|
|
|
|
|
|
<
>




|


|
|
|
|
|
<
|
|
>



|
|


|
|
|

|
|


|


|

|
|
|
|


|
|
|
|
|
|
|
|
<
|
>
|
|

|
|


|


|
|
|


|
|
|
<
|
>
|
|

|

|


|
|
|


|








|
|

|
|
|



|








|
|

|



|









|






|
|
|



|


|

|




|

|



|



















|


|

|
|
|



|
|

|


|

|



|
|
|


|


|
|


|


|


|
|

|






|






|



|











|















|






|



|

|
|
|




|

|
|

|








|








|





|

|
|

|


|






|
|




|







|








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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869

870
871
872
873
874
875
876
877
878
879
880
881
882

883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919

920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939

940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223

# TIP 308: Tcl Database Connectivity (TDBC)

	Author:         Kevin B. Kenny <[email protected]>
	Author:         Artur Trzewik <[email protected]>
	Author:         Andreas Leitgeb <[email protected]>
	Author:		Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Informative
	Vote:           Done
	Created:        15-Nov-2007
	Post-History:   
	Obsoleted-By:	350
-----

# Abstract

This TIP defines a common database access interface for Tcl scripts.

# Corrections

There are corrections to this TIP in [[350]](350.md) as well. Readers of this document
should see that one too.

# Introduction

There has been a fair amount of discussion, that flares and dies back,
regarding the need for a "Tcl database connectivity layer" in the Tcl core.
This document specifies what this discussion means. At its present stage of
development, it is to be considered very much a draft; discussion is actively
solicited.

Parties who are interested in a detailed background of this TIP may a more
extensive discussion of motivations and objectives in the author's posting to
_comp.lang.tcl_ and the _tcl-core_ newsgroup, obtainable from
<http://groups.google.com/group/comp.lang.tcl/msg/9351d1b2a59ee2ca>  or
<http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/3581757> .

## What is Tcl's Database Connectivity Layer?

If we look at other database connectivity layers such as ODBC/DAO, JDBC,
Perl's DBD/DBI, we find that there really isn't very much, if anything, inside
them. Rather than being a body of code, they consist primarily of
specifications of the interfaces to which the author of a database
connectivity module must conform. The real work of connecting to the databases
happens inside the connectivity modules, which are generally speaking under
the control of the database teams. In terms of practical politics, there isn't
really any other way to do it; the Tcl maintainers are highly unlikely to want
to take on the job of connecting to arbitrary database API's.

In other languages, such as C\+\+ and Java, it is often necessary to have
interface definitions that are understood by a compiler in order to get the
"pluggability" of arbitrary database connectivity. In Tcl, however, an
"interface" is best understood as an ensemble implementing a predetermined set
of commands. There is no counterpart to a Java or C\+\+ interface definition,
nor does there need to be. For this reason, the work product of a "Tcl
database connectivity" development effort is likely \(at least at the first
stage\) to consist primarily of a specification document, perhaps with
reference implementations for one or a few popular databases. To be considered
"in the core", the specification should be included with the Tcl
documentation, and be under control of the TIP process. The database
implementations should be considered "extensions," and have their own
configuration management. This statement doesn't say that we can't choose from
among them a set that we will package with releases of the Tcl core. In fact,
I hope that this effort will be one driver for the TCT to sort out the
management of "bundled extensions."

## Mechanics of This Document

I write this document in "standards committee prose". \(While turgid, it at
least is often well-understood; I offer no further defence.\) In particular:

 * the word "MAY" is construed as allowing a given behaviour but imposing no
   requirement other than that clients be prepared for it;

 * the word "MUST" \(and conversely "MUST NOT"\) is construed as requiring a
   given behaviour; implementations that fail one or more requirements given
   by "**must**" are non-compliant;

 * the word "SHOULD" \(and conversely "SHOULD NOT"\) indicates that a given
   behaviour is expected of an implementation unless there is a compelling
   reason not to include it; while not formally non-compliant, implementations
   that fail one or more requirements given by "SHOULD" can be understood to
   have issues with respect to "quality of implementation."

 * the future of determination \("SHALL" or "WILL" according to the usual
   customs of formal written English\) is construed as a promise to which the
   Tcl Core or the Tcl Core Team, as appropriate, shall adhere. It describes
   requirements of the Tcl Core, rather than of database connection modules.

 * the term, "integer value" refers to any string acceptable to
   **Tcl\_GetBignumFromObj**; the term "native integer value" refers to a
   value acceptable to **Tcl\_GetIntFromObj**, and hence to a value that can
   be represented by a C **int** on the target machine.

 * the term, "boolean value" refers to any string acceptable to
   **Tcl\_GetBooleanFromObj** and hence includes at least '1', '0', 'on',
   'off', 'yes', 'no', 'true', and 'false'.

 * the term "ensemble" refers to a Tcl command that accepts subcommands. It
   does not imply that any given command is implemented using the **namespace
   ensemble** mechanism.

# Specification

## Connecting to a Database

Obviously the first thing that any connectivity layer has to offer is the
ability to select a database. The way databases are named is quite specific to
the database manager, as is the way access is negotiated \(credentials such as
user name and password may be required, session keys may be negotiated for
privacy and authentication, and so on\). All of this machinery is formally out
of scope for this specification. Similarly, the machinery of database
administration \(at least at the level of creating/deleting entire databases,
managing the physical layer, and authorizing clients\) is presumed to be
already taken care of. We need merely specify that a connectivity layer must
provide at least one command that accepts arguments describing the desired
connection and returns a _database handle_ - defined to be an ensemble
through which interactions with the given database instance will take place.
Here, _database instance_ means the database, or databases, that the given
handle can access; rather a circular definition. In many SQL systems, it is
possible for a single connection to access several "databases" managed by SQL
CREATE DATABASE statments, or several "tablespaces" or similar constructs. We
presume that database module implementors will know what is appropriate for
their systems, and intentionally leave this particular matter somewhat vague.

## Basic Mechanics of Database Interfaces

Database handles are Tcl ensembles, meaning that they are commands that
support subcommands. Other ensembles, such as statement handles, are also
defined in this specification. Any of the ensembles MAY support abbreviation
of its subcommands according to the rules defined by
**Tcl\_GetIndexFromObj**; nevertherless, code that uses the database
interface SHOULD spell out subcommands in full.

Many of the subcommands are expected to take options in Tcl's usual syntax of:

 > ?_-option_ ?_value_?? ?_-option value_?...

In all of the places where this syntax is expected, a database module MAY
support abbreviation of options according to the rules of
**Tcl\_GetIndexFromObj\(\)**; once again, code that uses the interface SHOULD
spell out options in full.

All the database objects \(connections, statements and result sets\) are "duck
typed" - that is, "If it walks like a duck and quacks like a duck, I would
call it a duck. \(James Whitcomb Riley\)." In other words, the ensembles may be
implemented using any available functionality as long as the result is that
they use the interfaces described. Nevertheless, as a convenience to
implementors, a set of base classes, called **tdbc::connection**,
**tdbc::statement**, and **tdbc::resultset**, SHALL be provided using
Tcl's native object orientation as described in [[257]](257.md). Certain advantages will
accrue to database implementors by using these base classes. In particular,
the **tdbc::\*** classes SHALL do all the bookkeeping needed to determine
what statements and result sets are open, SHALL provide the internal iterators
**allrows** and **foreach**, SHALL implement the **transaction** method
on connections, and SHALL ensure that the **close** method on the objects
functions the same as renaming the object to the null string.

## Configuring a Database Handle

Once a handle is returned, there are a number of session-level attributes that
may be controllable. Every database handle MUST provide a **configure**
subcommand that takes the form:

 > _dbHandle_ **configure** ?_-option_ ?_value_?? ?_-option
   value_?...

This configuration process is analogous to configuring a Tk widget. If there
are no arguments presented to **configure**, the return value MUST be a list
of alternating options and values describing the configuration parameters
currently in effect. If a single argument is presented, it MUST be the name of
a configuration parameter, and the return value MUST be current value for that
parameter. Finally, if more than one argument is presented, they MUST be a
list of alternating parameter names and values. This last form is an order to
set the given parameters to the given values.

The connectivity layer SHOULD implement the following parameters, and MAY
implement others:

\(_Note:_ an earlier draft of this TIP specified a **-autocommit** option;
this option has been removed because it is redundant with the transaction
management primitives below.\)

 * **-encoding** _name_

	 > Requests that the encoding to be used in database communication protocol be
   changed to the one given by _name_, which MAY be any name acceptable to
   the [encoding] command. A well-designed database interface SHOULD NOT
   require this command; however, some backends make it virtually inevitable
   that mid-stream changes of encodings will be required.

 * **-isolation** _level_

	 > Requests that transactions performed on the database be executed at the
   given isolation _level_. The acceptable values for _level_ are:

	 > \* **readuncommitted**

	 > > Allows the transaction to read "dirty", that is, uncommitted data. This
     isolation level may compromise data integrity, does not guarantee that
     foreign keys or uniqueness constraints are satisfied, and in generall
     does not guarantee data consistency.

	 > \* **readcommitted**

	 > > Forbids the transaction from reading "dirty" data, but does not guarantee
     repeatable reads; if a transaction reads a row of a database at a given
     time, there is no guarantee that the same row will be available at a
     later time in the same transaction.

	 > \* **repeatableread**

	 > > Guarantees that any row of the database, once read, will have the same
     values for the life of a transaction. Still permits "phantom reads" \(that
     is, newly-added rows appearing if a table is queried a second time\).

	 > \* **serializable**

	 > > The most restrictive \(and most expensive\) level of transaction isolation.
     Any query to the database, if repeated, will return precisely the same
     results for the life of the transaction, exactly as if the transaction is
     the only user of the database.

	 > \* **readonly**

	 > > Behaves like **serializable** in that the only results visible to the
     transaction are those that were committed prior to the start of the
     transaction, but forbids the transaction from modifying the database.

	 > A database that does not implement one of these isolation levels SHOULD
   instead use the next more restrictive isolation level. If the given level
   of isolation cannot be obtained, the database interface MUST throw an error
   reporting the fact.  The default isolation level SHOULD be at least
   **readcommitted**.

	 > A database interface MAY forbid changing the isolation level when a
   transaction is in progress.

 * **-timeout** _ms_

	 > Requests that operations requested on the database SHOULD time out after
   the given number of milliseconds, if such an option is supported by the
   underlying connectivity layer.

 * **-readonly** _boolean_

	 > Notifies that the application will, or will not, limit its activity to
   operations that do not modify the content of the database. This option MAY
   have the effect of adjusting the transaction isolation level.

The command that returns a database handle SHOULD also accept these options.

## Transaction Isolation

A database handle MUST implement the three subcommands **starttransaction**,
**commit** and **rollback**:

 > _dbHandle_ **starttransaction**

Begins an atomic transaction on the database. If the underlying database does
not implement atomic transactions or rollback, the **starttransaction**
subcommand MUST throw an error reporting the fact.

If the underlying database does not implement nested transactions, a
**starttransaction** command that is executed when there is a transaction
already in progress \(started, but neither committed nor rolled back\) MUST
result in an error.

 > _dbHandle_ **commit**

Commits a transaction to the database, making the changes durable.

 > _dbHandle_ **rollback**

Rolls back a transaction against the database, cancelling any changes made
during the transaction.

Statements executed against the database when no transaction is in progress
\(before the first **starttransaction** or after all started transactions
have been either committed or rolled back\) SHOULD be _auto-committed_; that
is, each such statement SHOULD be executed as if a **starttransaction**
command preceded the statement and a **commit** command followed it
\(assuming that the statement succeeded; errors should result in **rollback**
of course\).

These commands are provided primarily to support the construction of
higher-level operations. In particular, most simple transactions against a
database can be handled using the **transaction** command:

 > _dbHandle_ **transaction** _script_

Executes the given _script_ with transaction isolation. In this command, the
_dbHandle_ argument is a handle to a database connection, and the _script_
argument is a Tcl script to be evaluated in the calling scope. The script is
treated as a single atomic database transaction. The **starttransaction**
command is executed against the given database connection, and then the
_script_ is evaluated. If it completes successfully \(_TCL\_OK_\), the
transaction SHALL be committed to the database.  If it fails, \(_TCL\_ERROR_\),
the transaction SHALL be rolled back and not visible to other users of the
database. _TCL\_BREAK_, _TCL\_CONTINUE_ and _TCL\_RETURN_ SHALL result in a
commit and subsequently rethrow the same exception status outside the
transaction. Exception status codes other than these five SHALL rollback the
transaction and be rethrown.

\(_Note:_ Scripts inside a **transaction** command SHOULD avoid use of the
**return -code** or **return -level** operations. If a script returns from
a transaction, with any combination of return options, the transaction SHALL
be committed.\)

Just as with **starttransaction**, if a [_dbHandle_ **transaction**]
command is executed while another transaction is already in progress, it is
requesting nested transaction semantics. A database handle to an engine that
supports nested transactions MUST treat this case correctly; a database handle
to an engine that does not support nested transactions \(including one that
does not support transactions at all\) MUST throw an error.

The **transaction** subcommand SHALL be provided by the
**tdbc::connection** base class; database interfaces that use the TclOO
features and the TDBC base classes do not need to implement it.

## Closing a Database Connection

A database handle MUST implement the command:

 > _dbHandle_ **close**

This command MUST dismiss the connection to the database and is expected to
clean up the system resources associated with it. If there is an uncommitted
transaction, it SHOULD be rolled back. Any handles to other objects associated
with the database SHOULD become invalid.

A database interface also SHOULD perform the same actions if a handle is
deleted by means of the **rename** command. \(Interfaces that are implemented
in Tcl may be notified of this action by creating a deletion trace with
**trace add command**.\) It is recognized that command deletion traces
present difficulties in situations like namespace and interpreter deletion;
the **close** subcommand shall therefore be considered the preferred way to
terminate connections.

A database interface SHOULD attempt to arrange, if possible, to rollback
unfinished transactions and clean up on process exit. In particular, if the
underlying database engine supports transactions, it SHOULD be considered an
error to commit any work that remains uncommitted on process exit.

The **close** command SHALL be provided by the **tdbc::connection** base
class; database interfaces that use the TDBC base classes do not need to
implement it. The base class implementation destroys the object using **my
destroy**. As a result, any statements obtained from the connection are also
destroyed, since they are stored in a namespace that is subordinate to the
connection's namespace. The destructor of the connection object is expected to
close the underlying database connection and release any system resources
associated with it.

## Preparing Statements

A database handle must support the **prepare** command, which has the
syntax:

 > _dbHandle_ **prepare** _SQL-code_

The _SQL-code_ argument is a SQL statement that is to be executed against
the given database connection. This command does not execute the statement
directly; rather, it prepares to execute the statement, possibly performing
tasks such as code compilation and query optimisation.

The database interface MUST support substitutions in _SQL-code_. Each
substitution request has the form _:variableName_. That is, each
substitution request begins with a literal colon \(:\), followed by a letter or
underscore, followed by zero or more letters, digits, or underscores. The
database interface is responsible for translating from this syntax to whatever
the underlying engine requires. Typical strings required in database
interfaces are _:name_, _:number_, _@name_, _@number_, and _?_.

The return value from the **prepare** command is a _statement handle_,
discussed under "The statement interface" below.

_Rationale._ The choice of the colon deserves some discussion. It would
surely be more natural for Tcl to use a literal dollar sign to introduce a
variable name. This choice, however, seems unwise, since several databases
\(most notably Oracle\) allow the use of table and view names that contain
dollar signs. While it might be possible to continue to use these while
allowing for variable substitution \(for instance, by mandating that table or
view names with dollar signs be enclosed in double quotes\), it seems
unnatural. The colon is syntax that is recognized by JDBC, ODBC, and Oracle's
native API, and as such will be familiar to most SQL programmers and unlikely
to collide with native syntax.

The requirement to support prepared statements is intended to guard against
SQL insertion attacks. An interface to a database whose native API does not
support prepared statements MUST simulate them. In particular, when the
**execute** command is executed on a statement, substitution must be
performed in a safe fashion with whatever magic quoting is required. In any
case, magic quoting should be regarded as an infelicitous expedient and
avoided if at all possible.

If a database interface uses the **tdbc::connection** base class, then a
**prepare** method will be provided for it. If this method is not
overridden, then the database interface MUST arrange that the constructor of
the connection sets the instance variable, _statementClass_, to the fully
qualified name of the command that constructs statements. The **prepare**
method SHALL invoke that command with a call of the form:

 > _statementClass_ **create** _handle_ _connectionHandle_ _sql_

where _handle_ is the name of the new statement being created,
_connectionHandle_ is the handle to the connection creating it, and _sql_
is the SQL statement being prepared.

## Stored Procedure Calls

A second way to prepare statements is to prepare a stored procedure call. If a
database interface supports stored procedures, it MUST support the
**preparecall** command:

 > _dbHandle_ **preparecall** _call_

_call_ is a string that describes a call to a stored procedure. It takes
the form:

 > ?_:varName_ **=**? _procName_ **\(** ?_:varName_?  ?**,**
   _varName_?...  **\)**

The result of the **preparecall** command is a statement handle. The
statement handle may be used just as any other statement handle.

The **preparecall** method SHALL _not_ be provided in the
**tdbc::connection** base class; individual database interfaces are expected
to do so. They MAY do so by rewriting the call to whatever syntax the native
database requires, and delegating to the **prepare** method to prepare that,
or they MAY instead prepare another ensemble. \(See "The TDBC base classes"
below for details of integrating this mechanism with the base classes.\)

## Quasi-Direct Execution

A database handle MUST support the following two calls:

 > _dbHandle_ **allrows** ?**-as** _lists_\|_dicts_?
   ?**-columnsvariable** _varName_? ?**--**? _sql_ ?_dictionary_?

This command prepares the SQL statement given by the _sql_ parameter, and
immediately executes it. Variable substitutions inside the _sql_ parameter
are satisfied from the given _dictionary_, if one is supplied, and from
variables in the caller's scope otherwise. The **-as** option determines the
form of the result, and the **-columnsvariable** option provides an optional
variable in which the names of the result columns will be stored. Upon
termination of the command, whether successful or unsuccessful, the prepared
statement is closed. The command returns a list of the rows returned by the
affected statement. \(If the affected statement does not yield a set of rows,
the return value from the _allrows_ command is an empty list.\)

This command MUST function the same way as preparing the statement explicitly,
executing the **statement allrows** call \(see below\) on the resulting
statement handle, and then \(irrespective of whether the operation succeeeded\)
destroying the statement handle.

 > _dbHandle_ **foreach**?**-as** _lists_\|_dicts_?
   ?**-columnsvariable** _varName_? ?**--**? _sql_ ?_dictionary_?
   _varName_ _script_

This command prepares the SQL statement given by the _sql_ parameter, and
immediately executes it. Variable substitutions inside the _sql_ parameter
are satisfied from the given _dictionary_, if one is supplied, and from
variables in the caller's scope otherwise. The **-as** option determines the
form of the result, and the **-columnsvariable** option provides an optional
variable in which the names of the result columns will be stored. For each row
returned by the given statement, the given _varName_ is set to a list or
dictionary containing the returned row, and the given _script_ is executed
in the caller's scope. Upon termination of the command, whether successful or
unsuccessful, the prepared statement is closed.

This command MUST function the same way as preparing the statement explicitly
and then executing the _statement_ **foreach** call on the resulting
statement handle.

Both of these commands SHALL be provided in the **tdbc::connection** base
class.

## Introspecting the Sets of Handles

A database handle MUST support the **statements** command:

 > _dbHandle_ **statements**

This command MUST return a list of the statements that have been prepared by
means of [_dbHandle_ **prepare**] but not yet dismissed using
[_statementHandle_ **close**].

Likewise, a database handle MUST support the **resultsets** command:

 > _dbHandle_ **resultsets**

This command MUST return a list of the result sets that have been returned \(by
executing statements, or by querying metadata\) and have not yet been dismissed
using [_resultSetHandle_ **close**].

Both of these commands SHALL be provided in the _tdbc::connection_ base
class. Using the base class implementations imposes certain restrictions on
derived classes. \(See "The TDBC base classes" below for details of integrating
this mechanism with the base classes.\)

## Querying Metadata

A database interface MUST provide a way of enumerating the tables in the
database. The syntax for querying tables MUST be:

 > _dbHandle_ **tables** ?_matchPattern_?

The optional argument _matchPattern_, if supplied, is a pattern against
which the table names are to be matched. The database interface MUST recognize
the SQL wildcards **%** and **\_** in the pattern.

A database interface MUST provide a way of enumerating the columns in a
database table. The syntax for querying columns MUST be:

 > _dbHandle_ **columns** _tableName_ _?matchPattern?_

The return value from the **tables** and **columns** commands MUST be a
dictionary. The keys of the dictionary MUST be the names of the tables in the
database, or respectively the columns in the given table.

The values stored in the dictionary returned from the **tables** command
MUST be dictionaries. The keys and values of these dictionaries, nevertheless,
are implementation-defined; only the keys are mandated in this specification.

The values stored in the dictionary returned from the **columns** command
MUST themselves be dictionaries. These subdictionaries MUST include the keys,
**type**, **precision**, **scale**, and **nullable**. The **type**
value MUST be the data type of the column, and SHOULD be chosen from among the
standard types _bigint_, _binary_, _bit_, _char_, _date_,
_decimal_, _double_, _float_, _integer_, _longvarbinary_,
_longvarchar_, _numeric_, _real_, _time_, _timestamp_, _smallint_,
_tinyint_, _varbinary_, and _varchar'. The **precision** and
**scale** values SHOULD give the precision and scale of the column, and the
**nullable** value SHOULD give a boolean value that represents whether the
given column can contain NULL values.

Other keys MAY be included in the subdictionaries returned from **tables**
and **columns**, and SHALL be added to this document \(as optional columns\)
on request from the implementors of database interfaces.

## The Statement Interface

The statement handle returned from the **prepare** command on a database
interface must itself be an ensemble. The following subcommands MUST be
accepted:

 > _statementHandle_ **params**

Requests a description of the names and expected data types of the parameters
to the given statement. The return value from the **params** command MUST be
a dictionary whose keys are the names of the parameters and whose values are
themselves dictionaries.  The keys of the subdictionaries MUST include
_name_, _type_, _precision_, _scale_, and _nullable_. They are
interpreted in the same way as those of the **columns** subcommand to a
database interface \(shown above\). The subdictionaries also MUST include the
key, _direction_, whose value identifies the direction of parameter
transmission, and MUST be chosen from among _in_, _out_ and _inout_.

 > _statementHandle_ **execute** ?_dictionary_?

Executes a statement against a database. Any variable substitution present in
the SQL that was provided when the statement was created MUST be performed at
this time. The variable values MUST be obtained from the given _dictionary_,
if one is supplied. If the dictionary does not contain a key equal to a
variable name in the statement, a NULL value MUST be provided.

If the _dictionary_ argument is omitted, the variable values MUST be
obtained from the scope in which the **execute** command was evaluated.  Any
variable that is undefined in that scope must be replaced with a _NULL_
value. An array variable provided to a substituent MUST result in an error.
Read traces against the substituted variables SHOULD fire, in left-to-right
order as they appeared in the SQL statement. The result of the **execute**
command SHOULD be a result set, as defined under "The result set interface"
below.

This method is provided by the **tdbc::connection** base class. In the base
class, it works by creating an instance of the class whose name appears in the
**statementClass** instance variable. See "The TDBC base classes" below for
the details of how the derived classes should be implemented to avail
themselves of this method.

 > _statementHandle_ **close**

Announces that a statement is no longer required, and frees all system
resources associated with it. The **close** command MAY invalidate any
result sets that were obtained by the **params** and **execute** commands.

As with database connections, the database interface SHOULD also clean up if a
statement handle is removed with _[rename $statement {}]_. Once again, it
is recognized that the strange side effects of namespace and interpreter
deletion may make this cleanup impossible in some interfaces, so **close**
SHALL be considered the standard means of discarding statements.

The _close_ command SHALL be provided in the _tdbc::statement_ base class.
Database interfaces that use the TDBC base classes do not need to implement
it. The base class implementation destroys the object using **my destroy**.
As a result, any result sets obtained from the statement are also destroyed,
since they are stored in a namespace that is subordinate to the statement's
namespace. The destructor of the statement object is expected to release any
system resources associated with it.

### Data Types of Parameters to Prepared Statements

The syntax described so far presumes that the database interface can determine
the expected types of the variables that appear in a prepared statement, or at
the very least can accept some sort of variant type and perform automatic type
coercion. This requirement does not seem horribly onerous at first inspection,
since SQLite allows for "everything is a string" parameters; ODBC offers
parameter introspection via the _SQLDescribeParam_ call; and JDBC offers it
via the _getParameterMetaData_ method of the _PreparedStatement_
interface.

Nevertheless, a deeper examination discovers that in at least ODBC, a driver
is allowed to fail to offer _SQLDescribeParam_. Inspection of the JDBC-ODBC
bridge reveals that in this case, JDBC will return a _ParameterMetaData_
object that throws a _SQLException_ on any attempt to query specific data.
The result is that, while the APIs to introspect parameter types are
available, they may be unusable against a particular database engine. In these
cases, a backup is needed.

For this reason, a database interface MUST support allowing the user to
specify types of the parameters of a prepared statement. The syntax for doing
so MUST be:

 > _statementHandle_ **paramtype** _paramName_ ?_direction_?  _type_
   ?_precision_? ?_scale_?

Defines that the parameter identified by _paramName_ in the given statement
is to be of type _type_. The _type_ MUST be chosen from among the names
_bigint_, _binary_, _bit_, _char_, _date_, _decimal_, _double_,
_float_, _integer_, _longvarbinary_, _longvarchar_, _numeric_,
_real_, _time_, _timestamp_, _smallint_, _tinyint_, _varbinary_,
and _varchar_.

\(_Rationale:_ These types appear to suffice for ODBC, and we can always come
back and extend them later if needed.\)

The _precision_ of a parameter defines the number of characters or digits
that it requires, and its _scale_ defines the number of digits after the
decimal point, if neeeded. A database interface MAY allow negative numbers for
_scale_ in contexts where they make sense. For example, a _scale_ of -3,
if allowed, SHOULD indicate that quantities in the given column are all
multiples of 1000. The _precision_ and _scale_ are not required by all
types.

A _direction_ must be one of the words, **in**, **out** or
**inout**. It specifies that the given parameter is an input to the
statement, an output from the statement, or both. It is usually meaningful
only in stored procedure calls. Default is **in**, unless the parameter
appears on the left-hand side of an equal side in a stored procedure call, in
which case the default is **out**.

### ~Examples

	 $statement paramtype name varchar 40
	 $statement paramtype balance in decimal 10 2
	 $statement paramtype transactionDate timestamp

Implementors of database APIs SHOULD make every effort to do appropriate type
introspection so that programmers can avoid needing to include explicit type
information in their SQL statements.

### Internal Iterators

A statement handle MUST support the following two calls:

 > _statement_ **allrows** ?**-as** _lists_\|_dicts_?
   ?**-columnsvariable** _varName_? ?**--**? ?_dictionary_?

This command executes the given _statement_. Variable substitutions inside
the statement are satisfied from the given _dictionary_, if one is supplied,
and from variables in the caller's scope otherwise. The **-as** option
determines the form of the result, and the **-columnsvariable** option
provides an optional variable in which the names of the result columns will be
stored. Upon termination of the command, whether successful or unsuccessful,
the prepared statement is closed. The command returns a list of the rows
returned by the affected statement. \(If the affected statement does not yield
a set of rows, the return value from the _allrows_ command is an empty
list.\)

This command MUST function the same way as executing the statement explicitly
\(with the given _dictionary_ argument if one is supplied\), executing the
_resultset_ **allrows** call \(see below\) on the resulting result set, and
then \(irrespective of whether the operation succeeeded\) destroying the result
set.

 > _statement_ **foreach**?**-as** _lists_\|_dicts_?
   ?**-columnsvariable** _varName_? ?**--**? ?_dictionary_?
   _varName_ _script_

This command executes the given _statement_. Variable substitutions inside
the statement are satisfied from the given _dictionary_, if one is supplied,
and from variables in the caller's scope otherwise. The **-as** option
determines the form of the result, and the **-columnsvariable** option
provides an optional variable in which the names of the result columns will be
stored. For each row in the result set, the given _varName_ is set to a list
or dictionary containing the returned row, and the given _script_ is
executed in the caller's scope. Upon termination of the command, whether
successful or unsuccessful, the result set is closed.

This command MUST function the same way as executing the statement explicitly,
executing the _resultset_ **foreach** call on the resulting statement
handle, and then \(irrespective of whether the operation succeeded\) closing the
result set.

Both of these commands SHALL be provided in the **tdbc::statement** base
class.

## The Result Set Interface

Result sets represent the results of operations performed on the database. A
preferred implementation for large result sets is that they be implemented as
database cursors, so that it is possible to iterate over result sets that will
not fit in memory. A result set MUST be an ensemble. The following subcommands
MUST be accepted:

 > _resultSetHandle_ **rowcount**

Determines the number of rows affected by a SQL statement such as
**INSERT**, **DELETE** or **UPDATE**. This count MUST be returned as an
integer. It should not be confused with the number of rows in the result set.
A database interface need not provide any interface to determine the latter
number \(often, the only way to determine it is to read all the rows\). For this
reason, the **rowcount** command MAY return an empty string, or a
non-positive number, for **SELECT** operations \(and any other operations
that do not modify rows of the database\).

 > _resultSetHandle_ **columns**

Determines the set of columns contained in the result set. The set of columns
is returned simply as a list of column names, in the order in which they
appear in the results.

 > _resultSetHandle_ **nextrow** ?**-as** **lists\|dicts**? ?**--**?
   _variableName_

\(This interface SHALL be provided by the **tdbc::resultset** base class. The
default implementation SHALL delegate to either the **nextlist** or
**nextdict** methods, below.

Fetches a row of data from the result set and stores it in the given variable
in the caller's context.

If **-as dicts** is specified \(the default\), the row MUST be represented as
a dictionary suitable for use with the **dict** command. The keys in the
dictionary SHALL be the column names, and the values SHALL be the values of
the cells. If no rows remain, the **nextrow_ command MUST store an empty
dictionary. If a cell in the row is NULL, the key MUST be omitted from the
dictionary. A database interface MUST NOT use a special value of any kind to
represent a NULL in a dictionary.

If **-as lists** is specified, the row MUST be represented as a list of
values, in the order in which they appear in the query. \(If the statement is a
stored procedure call, the values comprise all the **out** or **inout**
parameters.\) If no rows remain, the **nextrow** command MUST store an empty
list. If a cell in the row is NULL, an empty string MUST be stored as its
value.

The return value of _nextrow_ MUST be 1 if a row has been returned, and 0 if
no rows remain in the result set.

In the result set, values of type _bigint_, _bit_, _decimal_,
_double_, _float_, _integer_, _numeric_, _real_, _smallint_, and
_tinyint_ MUST receive their natural representation as decimal numbers.
Ideally, they should be returned as "pure" numbers with their string
representations generated only on demand. Values of type _char_,
_longvarchar_ and _varchar_ MUST be returned as Tcl strings. _A database
interface implemented in C _MUST_ take care that all strings are well-formed
UTF-8._ Values of type _date_ and _timestamp_ MUST be returned as a
numeric count of seconds from the Tcl epoch; if necessary, this count may have
a decimal point and an appropriate number of additional decimal places
appended to it. Values of type _time_ MUST be returned as a integer count of
seconds since midnight, to which MAY be appended a decimal point and a
fraction of a second. Values of type _binary_, _longvarbinary_ and
_varbinary_ MUST be returned as Tcl byte arrays.

_Rationale:_ Dictionaries and lists are both useful in representing the
result set rows. Dictionaries allow for a ready distinction between NULL
values in a database and any other string. With any scheme where values that
can include NULLs can appear in Tcl objects, the problem arises that NULL must
be distinguished from any other string, particularly including the empty
string and the word "NULL". The lack of such a distinction has led to several
ill-advised proposals, such as [[185]](185.md), for representing NULLs in Tcl. These
alternatives founder on the principle of "everything is a string". The NULL
value is not any string. Dictionaries also have the advantage that results can
be addressed by name rather than by position.  On the other hand, lists are
convenient when formatting tabular results from _ad hoc_ queries. The
brevity of code that can be achieved with them is also attractive. For this
reason, this TIP requires both formats to be made available.

 > _resultSetHandle_ **nextdict** _variableName_

 > _resultSetHandle_ **nextlist** _variableName_

These two calls are precisely equivalent to calls to the **nextrow** command
with the **-as dicts** and **-as lists** option respectively. A database
interface MUST provide both of these, and they are the fundamental means for
retrieving rows from the result set.

 > _resultSetHandle_ **close**

Dismisses a result set and releases any system resources associated with it.

As with statements and database connections, the database interface SHOULD
also clean up if a resut set handle is removed with _[rename $statement
\{\}]_. Once again, it is recognized that the strange side effects of
namespace and interpreter deletion may make this cleanup impossible in some
interfaces, so **close** SHALL be considered the standard means of
discarding result sets.

The **close** command SHALL be provided by the **tdbc::resultset** base
class. The base class implementation destroys the object using **my
destroy**. The destructor of the result object is expected to release any
system resources associated with it.

### Internal Iterators

A result set handle MUST support the following two calls:

 > _resultset_ **allrows** ?**-as** _lists_\|_dicts_?
   ?**-columnsvariable** _varName_ ?**--**?

This command executes the **nextrow** command repeatedly, producing a list
of dictonaries or of lists \(according to the value of the **-as** option\).
The **allrows**command returns the resulting list. Optionally, the names of
the columns of the result set are also stored in the named variable given by
the **-columnsvariable** option.

 > _statement_ **foreach**?**-as** _lists_\|_dicts_?
   ?**-columnsvariable** _varName_? ?**--**? _varName_ _script_

This command optionally stores the names of the columns of the result set in
the variable designated by the **-columnsvariable** option. It then executes
the **nextrow** command repeatedly until all rows of the result set have
been processed. The **nextrow** command receives the given **varName** and
**-as** option, and stores the row in the named variable. For each row
processed, the given **script** is executed in the caller's scope.

Both of these commands SHALL be provided in the **tdbc::resultset** base
class.

## The TDBC Base Classes

Most implementations of database drivers SHOULD, as mentioned before, use Tcl
objects \(as in [[257]](257.md)\) that inherit from the **tdbc::connection**,
**tdbc::statement** and **tdbc::resultset** classes. The foregoing
discussion has described the user-visible methods that are provided by doing
so \(and must otherwise be implemented\). This section is directed to the driver
implementor, and discusses certain necessary housekeeping issues.

### Database Connections

However a database connection object is constructed, its constructor will need
to seize resources \(such as opening a database connection to the underlying
database system\). If the bookkeeping done by the base classes is to work
correctly, initialization of the **tdbc::connection** base class needs to
happen before external resources are seized. In addition, if the **prepare**
method is not overloaded \(and the driver SHOULD NOT have to overload it\), the
name of the class that implemements the statement interface needs to be
provided at this time. The recommended sequence for connection construction
is:

	  constructor args {
	      next;                         # Initialize tdbc::connection
	      my variable statementClass
	      set statementClass ::whatever;# Tell tdbc::connection what
	                                    # class must be instantiated by
	                                    # the 'prepare' method
	      my init {*}$args              # Perform implementation-specific
	                                    # initialization

	  }

Some database interfaces have a different API to stored procedures than to
ordinary SQL statements. These databases may need a separate type of statement
object from the one that implements ordinary statements. This object can be
managed as a statement owned by the connection by using a **prepareCall**
method that looks like:

	  method prepareCall {call} {
	      my variable statementSeq;   # Provided in the
	                                  # tdbc::connection base class
	      return [preparedStatementClass create \
	                  Stmt::[incr statementSeq] [self] $call]

	  }

In this call, **preparedStatementClass** is the name of the class that
implements prepared statements. Its constructor is expected to accept two
arguments: the handle to the database connection, and the prepared statement
that was passed to prepareCall. Placing the resulting object inside the
**Stmt** namespace under the current object \(this namespace is created by
the constructor of **tdbc::connection**\) allows for its destruction to be
sequenced correctly when the connection is destroyed.

The methods that a derived class from **tdbc::connection** MUST implement
are **prepareCall**, **begintransaction**, **commit**, and
**rollback**. In addition, system resources belonging to the connection
itself MUST be cleaned up by a destructor or by a deletion callback at C
level. \(Statements and result sets MUST not be deleted then; the base classes
take care of that.\) See "Best practices for memory management" below for
further discussion.

### Statements

The class that implements a statement SHOULD normally inherit from the
**tdbc::statement** base class. Its constructor accepts the connection
handle and the SQL statement to prepare. The constructor is responsible for
invoking the base class constructor with **next**, setting an instance
variable _resultSetClass_ to the name of the class that implements its
result set, and then preparing the statement. \(The constructor is invoked by
the **prepare** method of **tdbc::connection.\) A sample constructor looks
like:

	  constructor {connection sql} {
	      next;                        # initialize the base class
	      my variable resultSetClass 
	      set resultSetClass whatever; # Tell the base class what class
	                                   # to use for result sets
	      my init $connection $sql;    # The [[init]] method should do
	                                   # whatever is necessary to prepare
	                                   # the statement

	  }

Derived classes from **tdbc::statement** MUST also implement the
**params** and **paramtype** methods. In addition, system resources
belonging to the statement itself MUST be cleaned up by a destructor or by a
deletion callback at C level. \(Result sets MUST not be deleted then; the base
classes take care of that.\) See "Best practices for memory management" below
for further discussion.

### Result Sets

The class that implements a result set SHOULD normally inherit from the
**tdbc::resultset** base class. Its constructor accepts the statement handle
and the arguments to the **execute** method. The constructor is responsible
for invoking the base class constructor with **next**, and executing the
statement. A sample constructor looks like:

	  constructor {statement args} {
	      next
	      uplevel 1 [list {*}[namespace code {my init}] $statement {*}$args]

	  }

Note the peculiar form of invocation for the **init** method in the example
above. Since the **init** method needs access to local variables in the
caller's context to do variable substitution, it needs to be executed at the
same stack level as the constructor itself. The [namespace code {my init}]
call gives a command prefix that can be used to invoke the method in a foreign
context, and this command is then executed with [uplevel 1] to do the
initialization.

Besides the constructor and **init**, the other methods that a result set
class MUST implement are **columns**, **nextrow**, and **rowcount**. In
addition, a destructor \(or a C deletion callback\) MUST clean up any system
resources belonging to the result set.

### Best Practices for Memory Management in Database Interfaces

Since the TclOO interfaces are so new, it seems wise to give developers of
database interfaces written in C some guidance about effective ways to manage
memory. A C-level extension, if written correctly, gets considerable
assistance in releasing memory at the appropriate times from TclOO and the
tdbc base classes.

When a database interface is first loaded as an extension, it is entered
through its _PackageName_\_**Init** function. It will call, in order,
**Tcl\_InitStubs**, **Tcloo\_InitStubs**, and **Tdbc\_InitStubs** so that
Tcl, the TclOO system, and the TDBC base classes are all available. Its next
task is to allocate any per-interpreter data that may be required. \(In the
case of the **tdbc::odbc** bridge, the per-interpreter data include an ODBC
environment handle and a string literal pool.\) The per-interpreter data
structure SHOULD be reference counted, since the order of destruction of the
objects that refer to it is unpredictable. Next, the initialization function
creates the classes, usually by evaluating an initialization script containing
a call to **tcl\_findLibrary**, where the Tcl code contains the skeletons of
the class definitions. With the class definitions in hand, methods that are
implemented in C can be attached to them. Any methods that need the
per-interpreter data can receive it as ClientData. The reference count of the
per-interpreter data SHOULD be incremented for these, and the method delete
procedures should be responsible for decrementing the reference count.

Each of the three classes that make up a database interface SHOULD have a
reference-counted data structure to hold any instance data. This structure
SHOULD be created within the **init** method, and attached to the object
with **Tcl\_ObjectSetMetadata**. The metadata type structure SHOULD designate
a delete procedure that decrements the reference count. The type structure MAY
designate a clone procedure that returns **TCL\_ERROR**; it is entirely
permissible for TDBC objects not to be clonable.

Generally speaking, each object's instance data structure will contain a
pointer to \(and hold a counted reference to\) the next higher object in the
ownership hierarchy. A result set will refer to the statement that produced
it; a statement will refer to the connection in which it executes, and a
connection will refer to the per-interp data.

With this infrastructure in place, object destruction becomes strictly a local
matter. Any object, when its reference count becomes zero, MUST release any
system resources that belong to it, and decrement the reference count of the
next object up. There is no need for a connection to track its statements, or
a statement to track its result sets. This happens automatically because the
**prepare** and **execute** methods create statements in a namespace
subordinate to the namespace of the owning connection, and create result sets
in a namespace subordinate to that of the owning statement. When the owning
objects are destroyed, the subordinate namespaces are also destroyed, invoking
the destructors of the objects within them.

This whole scheme is simpler than it sounds, and is observed to work well for
the **tdbc::odbc** bridge \(see the source code of the bridge for further
details\).  Closing a connection gracefully deletes the statement and result
class objects \(in Tcl\) from top to bottom, and then deletes the corresponding
C data structures from bottom to top, finally cleaning up the connection data
itself.

Note that, since TclOO does not guarantee to run destructors on **exit**, if
a database interface needs to always close the underlying connection on
termination, the implementation code should install an exit handler with
**Tcl\_CreateExitHandler** if it needs to.

## Support Procedures for Implementors of Database Interfaces

In addition to the convenience commands discussed above, the Tcl system SHALL
provide certain commands to aid the job of database implementors.

### SQL Tokenisation

The task of mapping variable substituions in the form, **:varName** into
whatever form that a native database API can handle is a somewhat tricky one.
For instance, substitutions that appear inside quoted strings MUST NOT be
mapped. In order to aid in this task, the Tcl system SHALL provide a command,
**::tdbc::tokenize**. This command SHALL accept a SQL statement as its sole
parameter, and return a list of tokens. The lexical value of the tokens can be
distinguished by their first characters:

   * '$', ':' and '@' are all variable substitutions; the remainder of the
     token string is a variable name.

   * ';' is a statement separator, for databases that allow multiple
     statements to be prepared together.

   * '-' is a comment

   * Anything else is literal text to be copied into a SQL statement.

Assuming that a native database's lexical structure conforms with standard
SQL, the variable names can be substituted with parameter numbers, question
marks, or whatever the database needs, to yield the native SQL that must be
prepared.

Tokenisation is also available at the C level; to access it, a C extension
MUST first call **Tdbc\_InitStubs**; it is a macro that behaves as if it is a
function with the type signature

 > int **Tdbc\_InitStubs**\(Tcl\_Interp \*_interp_\);

where _interp_ is a Tcl interpreter. The function returns **TCL\_OK** if
successful, and **TCL\_ERROR** \(with an error message left in the
interpreter\) in the case of failure.

The tokenisation is then available by calling 

 > Tcl\_Obj \***Tdbc\_TokenizeSql**\(Tcl\_Interp \*_interp_, const char
   *_sqlCode_\);

In this call, _interp_ is a Tcl interpreter, and _sqlCode_ is a SQL
statement to parse. If the parse is successful, the return value is a Tcl
object with a reference count of zero that contains a list of token strings as
with the **tdbc::tokenize_ call.

# References

This specification is largely built from studying existing cross-platform
database APIs and deriving a comon set of requirements from them. These
include both popular offerings in lower-level languages \(ODBC and JDBC\) and
Tcl-level ones \(notably the 'nstcl-database' package, the SQLite API and
tclodbc\).

"ODBC Programmer's Reference." Redmond, Wash.: Microsoft Corporation, 2007.
<http://msdn2.microsoft.com/library/ms714177.aspx> .

"Java Platform Standard Edition 6 API Specification." Santa Clara, Calif.: Sun
Microsystems, 2007 <http://java.sun.com/javase/6/docs/api/> ; in particular the
package named, **java.sql**.

Cleverly, Michael. "nstcl-database Package."
<http://nstcl.sourceforge.net/docs/nstcl-database/> .

Hipp, D. Richard. "The Tcl interface to the Sqlite library."
<http://www.sqlite.org/tclsqlite.html> .

Nurmi, Roy. "Tclodbc v 2.3 Reference." Available as part of the Tclodbc
distribution at <http://sourceforge.net/projects/tclodbc/> , in the file,
**DOC/REFERENC.HTM**.

# License

This file is explicitly released to the public domain and the author
explicitly disclaims all rights under copyright law.

----

# Appendix. Additional Possibilities.

An earlier version of this TIP specified several more requirements for the
TDBC statement objects. In the current version, these requirements have been
lifted. The three areas that have been removed are batch processing,
asynchronous query handling, and references to cursors.

_Rationale:_ Specifying an interface like this one is always a tradeoff
between capability of the interface and burden upon the implementors. The
earlier requirement for handling these three areas seems improvident.

The handling of bulk data \("batch processing"\) is to a large extent a
performance issue. In most cases, if the performance of bulk data handling is
critical, an implementor will resort to a compiled language rather than to Tcl
to do so. The reporting of errors on bulk operations is complicated, as is the
specification of what will happen if certain parameter sets succeed while
others fail. The benefit of bulk data handling at the Tcl level was not deemed
adequate to justify the implementation complexity.

The handling of asynchronous queries is also chiefly a performance issue in
that it is intended to enable keeping a GUI live while long-running database
operations are in progress. This "keep the GUI alive during long operations"
requirement is equally well satisfied by performing database operations in a
separate thread \(for a thread-enabled Tcl\) or a separate subprocess, and these
techniques are familiar to Tcl programmers. For similar reasons, the ODBC
manual now formally deprecates using ODBC's asynchronous operations on
operating systems that support multithreading. Again, the benefits of
integrating TDBC into the event loop do not appear to justify the cost in
complexity to be gained.

References to cursors are a feature that is highly dependent on the underlying
database. It is not clear that the specification described below is even
readily implementable on all the platforms that have refcursors. Most of
these, in any case, provide some other way of achieving the same end. For
instance, Oracle allows returning a cursor by name, and then executing a
statment, "FETCH ALL FROM :cursorName", to retrieve the data from the cursor.
Again, here is a feature that adds complexity out of proportion to the
benefits achieved.

## Batch Processing

Some databases provide an interface to pass bulk data into a statement, in
order to provide an efficient means for doing tasks such as inserting a large
number of rows into a table at once. A statement handle MUST provide the
subcommands:

 > _statement_ **startbatch**

Prepares to perform batch processing on the specified statement.  

 > _statement_ **addtobatch** _dictionary_

Adds the values given by _dictionary_ into the specified statement. The
_dictionary_ argument is exactly the same as the _dictionary_ argument to
[_statement_ **execute**].

If no batch operation is in progress, the database interface MUST throw an
error.

 > _statement_ **executebatch**

Executes the batch of operations accumulated by [_statement_
**addToBatch**].

The result of **executebatch** MUST be a result set. The rows of the result
set are the result of concatenating the rows returned from the individual
operations.

If no batch operation is in progress, the database interface MUST return an
error.

If an underlying database does not support batch operations, the database
interface SHOULD simulate them by accumulating the data in memory and
executing the statement repeatedly when the **executeBatch** operation is
requested.

The database interface MUST return an error if an attempt is made to execute a
statement in the ordinary manner or to request a commit while there is an
unfinished batch in progress. A rollback, or closing the statement, or closing
the database connection, while a batch is in progress MUST result in
abandoning the batch without applying any changes to the database.

## Asynchronous Queries

Some database operations take a long time to complete. In order to avoid
freezing the event loop, a database interface MAY provide an asynchronous
query mechanism. If it does so, it MUST take the form:

 > _resultSet_ **whenready** _script_

In this interface, _resultSet_ is the handle of a result set. The
**whenready** command requests that _script_ be evaluated at the global
level once for each row of the result set, plus once after all rows have been
returned. The script SHOULD execute **nextrow** to retrieve the next row or
get the indication that no rows remain.

## References to Cursors

Some databases allow stored procedures to return references to cursors. If a
column of a result set contains a reference to a cursor, it MUST be
represented in Tcl as another result set handle. A Tcl script can then iterate
over this included result set to use the reference to a cursor.

The given result set MUST be destroyed upon the next call to _nextrow_. For
this reason, Tcl code MUST not use the **allrows** command with a statement
that can return references to cursors.

----

# Appendix. Change Summary

   2008-04-27: Removed asynchronous queries, refcursors, and batch updates
     from the main body of the spec. Performed a good bit of general cleanup
     to bring the spec back in line with the reference implementation being
     developed.

   2007-11-23: Expanded transaction management to have both the
     **transaction** command and explicit transaction boundaries. Added
     transaction isolation levels.

   > Added lists as an alternative to dicts as a representation of rows in
     result sets. Added a side interface for retrieving the set of column
     names in the convenience procedures.

   > Simplified introspection to return lists instead of result sets
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280


   > Added reference to the author's cover letter on tcl-core.

   > Added missing citation of the nstcl-database API.

----

~ Appendix. Comments

Artur Trzewik (2007-11-19):

 > I miss defined error handling. Current DB-Api handles them in different
   way. How to obtain SQL-error message from server. If "execute" fails should
   it return TCL_ERROR or it should be special api for error code.

 > I miss C-framework or template to implement such API. Writing everything
   from scratch for all DB will be quite painfully. There are many things
   which can be reused: New Tcl objects, handles managing, thread-safe
   managing, encoding. Also prepared statements are not so easy. For example
   mysql requires that one allocate fixed size memory for all variables. It
   does not fit well with Tcl.

Kevin Kenny (2007-11-23):

 > Rest assured that at least one reference implementation will be published
   before this TIP is considered FINAL; database implementors are not going to
   be abandoned.

Andreas Leitgeb (2008-06-17):

 > For '''allrows''' and '''foreach''' calls, there has been some discussion
   about replacing the idiom '''-as list|dict''' by separate methods. Was this
   discussion dropped, or has it just not yet been reflected here?

 > For '''allrows''' and '''foreach''' calls there is ?'''-columnsvariable'''
   ''varName''? ... I think, another option: ?'''-indicatorvariable'''
   ''varName''?  would be useful, as it allows both NULLs and equally named
   columns at the same time. Without indicator, dicts can handle only the
   former, and lists only the latter.








|

|



|








|





|

|
|


|
|
|


>
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280

   > Added reference to the author's cover letter on tcl-core.

   > Added missing citation of the nstcl-database API.

----

# Appendix. Comments

Artur Trzewik \(2007-11-19\):

 > I miss defined error handling. Current DB-Api handles them in different
   way. How to obtain SQL-error message from server. If "execute" fails should
   it return TCL\_ERROR or it should be special api for error code.

 > I miss C-framework or template to implement such API. Writing everything
   from scratch for all DB will be quite painfully. There are many things
   which can be reused: New Tcl objects, handles managing, thread-safe
   managing, encoding. Also prepared statements are not so easy. For example
   mysql requires that one allocate fixed size memory for all variables. It
   does not fit well with Tcl.

Kevin Kenny \(2007-11-23\):

 > Rest assured that at least one reference implementation will be published
   before this TIP is considered FINAL; database implementors are not going to
   be abandoned.

Andreas Leitgeb \(2008-06-17\):

 > For **allrows** and **foreach** calls, there has been some discussion
   about replacing the idiom **-as list\|dict** by separate methods. Was this
   discussion dropped, or has it just not yet been reflected here?

 > For **allrows** and **foreach** calls there is ?**-columnsvariable**
   _varName_? ... I think, another option: ?**-indicatorvariable**
   _varName_?  would be useful, as it allows both NULLs and equally named
   columns at the same time. Without indicator, dicts can handle only the
   former, and lists only the latter.

Name change from tip/309.tip to tip/309.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

TIP:		309
Title:		Expose the Expression Parsing
Version:	$Revision: 1.2 $
Author:		Arjen Markus <[email protected]>
State:		Draft
Type:		Project
Vote:		Pending
Created:	07-Jan-2008
Post-History:
Tcl-Version:	8.7
Keywords:	expr, parse


~ Abstract

This TIP proposes a new command to expose the parsing of expressions by the
'''expr''' command. This will make it much easier to implement alternative
number systems, such as complex numbers, or to implement symbolic algebra.

~ Rationale

The '''expr''' command uses the traditional infix notation for arithmetical
expressions. Tcl itself uses a prefix notation. While it is quite easy to
create a set of procedures to do complex number arithmetic, using them means
the use of prefix notation, for example:

A polynomial expression like ''1 + i*z**2'' could become:

| [add [complex 1 0] [mult [complex 0 1] $z $z]

(where [[complex]] is used to make sure the constants are complex).

People used to the infix notation will find this a very clumsy, if not
error-prone way of working.

Basic symbolic algebra, like the determination of a derivative (useful for
certain numerical algorithms) is much easier when working with the prefix
notation:

| deriv [add $expr1 $expr2] --> add [deriv $expr1] [deriv $expr2]

This calls for an easy way to convert an infix notation to Tcl's prefix
notation.

~ Proposal

Introduce a new command, tentatively called s-expr, as this is the traditional
term used in LISP for expressions in the prefix notation, that converts a
given infix expression into an equivalent prefix expression.

The rules are simple:

 * Any valid '''expr''' expression can be converted. Invalid expressions
   result in the same error messages as if they were meant for '''expr'''.

 * The symbolic name for the command is simply the same as the string that
   represents the operation.

 * Operations have the same precedence as for '''expr'''. This TIP does not
   include a mechanism for introducing new operations.

 * Functions are translated into a command of the same name (no particular
   namespace) and the list of comma-separated arguments is converted into an
   ordinary sequence of arguments.

 * Errors that result from the evaluation of the expression are handled by the
   particular implementation of the operations and functions.

 * The resulting string can then be used by '''eval''' or '''uplevel''' to run
   the set of commands in the right order.

~ Implementation Notes

There is no implementation of this command yet, but here is a sketch:

 * Let the '''expr''' parser construct a parse tree from the command.

 * Let a new function convert the parse tree into a string holding the prefix
   expression and pass that to the interpreter as the result of [[s-expr]].

This limits the sort of expressions (in particular "constants" as understood
by the specific arithmetic system) to expressions that can be parsed by the
'''expr''' parser, but as this now handles lists, as a consequence of the
'''in''' and '''ni''' operations, this does not seem a severe limitation.

The advantage of this approach is that much of the hard work is already done
and that compatibility with the '''expr''' command is ensured.

~ Copyright

This document is placed in the public domain

<
|
<
|
|
|
|
|
|
|
|
>

|


|


|

|




|

|

|




|
|


|




|







|
|




|


|
|





|


|



|


|

|
|
|
|


|

|


>

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

# TIP 309: Expose the Expression Parsing

	Author:		Arjen Markus <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		Pending
	Created:	07-Jan-2008
	Post-History:
	Tcl-Version:	8.7
	Keywords:	expr, parse
-----

# Abstract

This TIP proposes a new command to expose the parsing of expressions by the
**expr** command. This will make it much easier to implement alternative
number systems, such as complex numbers, or to implement symbolic algebra.

# Rationale

The **expr** command uses the traditional infix notation for arithmetical
expressions. Tcl itself uses a prefix notation. While it is quite easy to
create a set of procedures to do complex number arithmetic, using them means
the use of prefix notation, for example:

A polynomial expression like _1 \+ i\*z\*\*2_ could become:

	 [add [complex 1 0] [mult [complex 0 1] $z $z]

\(where [complex] is used to make sure the constants are complex\).

People used to the infix notation will find this a very clumsy, if not
error-prone way of working.

Basic symbolic algebra, like the determination of a derivative \(useful for
certain numerical algorithms\) is much easier when working with the prefix
notation:

	 deriv [add $expr1 $expr2] --> add [deriv $expr1] [deriv $expr2]

This calls for an easy way to convert an infix notation to Tcl's prefix
notation.

# Proposal

Introduce a new command, tentatively called s-expr, as this is the traditional
term used in LISP for expressions in the prefix notation, that converts a
given infix expression into an equivalent prefix expression.

The rules are simple:

 * Any valid **expr** expression can be converted. Invalid expressions
   result in the same error messages as if they were meant for **expr**.

 * The symbolic name for the command is simply the same as the string that
   represents the operation.

 * Operations have the same precedence as for **expr**. This TIP does not
   include a mechanism for introducing new operations.

 * Functions are translated into a command of the same name \(no particular
   namespace\) and the list of comma-separated arguments is converted into an
   ordinary sequence of arguments.

 * Errors that result from the evaluation of the expression are handled by the
   particular implementation of the operations and functions.

 * The resulting string can then be used by **eval** or **uplevel** to run
   the set of commands in the right order.

# Implementation Notes

There is no implementation of this command yet, but here is a sketch:

 * Let the **expr** parser construct a parse tree from the command.

 * Let a new function convert the parse tree into a string holding the prefix
   expression and pass that to the interpreter as the result of [s-expr].

This limits the sort of expressions \(in particular "constants" as understood
by the specific arithmetic system\) to expressions that can be parsed by the
**expr** parser, but as this now handles lists, as a consequence of the
**in** and **ni** operations, this does not seem a severe limitation.

The advantage of this approach is that much of the hard work is already done
and that compatibility with the **expr** command is ensured.

# Copyright

This document is placed in the public domain

Name change from tip/31.tip to tip/31.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
TIP:            31
Title:          CVS tags in the Tcl and Tk repositories
Version:        $Revision: 1.38 $
Author:         Don Porter <[email protected]>
Author:         miguel sofer <[email protected]>
Author:         Jeff Hobbs <[email protected]>
Author:         Kevin Kenny <[email protected]>
Author:         David Gravereaux <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         Andreas Kupries <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         <[email protected]>
Author:         Kevin Kenny <[email protected] >
State:          Draft
Type:           Informative
Vote:           Pending
Created:        12-Mar-2001
Post-History:   


~ Abstract

This document keeps a record of the CVS tags used in the Tcl and Tk
repositories and their meanings.

~ Background

CVS uses tags to collectively label a particular set of revisions of a
particular set of files.  With a tag, one may easily request all the
revisions of all the files that correspond to something meaningful,
such as an official release of a project.

There are two kinds of tags provided by CVS.  First is the release tag
<
|
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>

|




|








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

# TIP 31: CVS tags in the Tcl and Tk repositories

	Author:         Don Porter <[email protected]>
	Author:         miguel sofer <[email protected]>
	Author:         Jeff Hobbs <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	Author:         David Gravereaux <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         <[email protected]>
	Author:         Kevin Kenny <[email protected] >
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        12-Mar-2001
	Post-History:   
-----

# Abstract

This document keeps a record of the CVS tags used in the Tcl and Tk
repositories and their meanings.

# Background

CVS uses tags to collectively label a particular set of revisions of a
particular set of files.  With a tag, one may easily request all the
revisions of all the files that correspond to something meaningful,
such as an official release of a project.

There are two kinds of tags provided by CVS.  First is the release tag
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294


A tag may be used in a CVS repository only once, so we must keep track
of what tags have already been used, and what they mean.  The
remaining sections of this TIP record the tags in use.  This TIP
should be kept up to date by adding any new tags here as they are
added to the CVS repository.

~ Release Tags

The following tags in the Tcl and Tk CVS repositories correspond to
the following releases of Tcl/Tk:

   * ''core-8-6-b1'' - Tcl/Tk 8.6b1

   * ''core-8-6-a3'' - Tcl/Tk 8.6a3

   * ''core-8-6-a2'' - Tcl/Tk 8.6a2

   * ''core-8-6-a1'' - Tcl/Tk 8.6a1

   * ''core-8-5-6''  - Tcl/Tk 8.5.6

   * ''core-8-5-5''  - Tcl/Tk 8.5.5

   * ''core-8-5-4''  - Tcl/Tk 8.5.4

   * ''core-8-5-3''  - Tcl/Tk 8.5.3

   * ''core-8-5-2''  - Tcl/Tk 8.5.2

   * ''core-8-5-1''  - Tcl/Tk 8.5.1

   * ''core-8-5-0''  - Tcl/Tk 8.5.0

   * ''core-8-5-b3'' - Tcl/Tk 8.5b3

   * ''core-8-5-b2'' - Tcl/Tk 8.5b2

   * ''core-8-5-b1'' - Tcl/Tk 8.5b1

   * ''core-8-5-a6'' - Tcl/Tk 8.5a6

   * ''core-8-5-a5'' - Tcl/Tk 8.5a5

   * ''core-8-5-a4'' - Tcl/Tk 8.5a4

   * ''core-8-5-a3'' - Tcl/Tk 8.5a3

   * ''core-8-5-a2'' - Tcl/Tk 8.5a2

   * ''core-8-5-a1'' - Tcl/Tk 8.5a1

   * ''core-8-4-18'' - Tcl/Tk 8.4.18

   * ''core-8-4-17'' - Tcl/Tk 8.4.17

   * ''core-8-4-16'' - Tcl/Tk 8.4.16

   * ''core-8-4-15'' - Tcl/Tk 8.4.15

   * ''core-8-4-14'' - Tcl/Tk 8.4.14

   * ''core-8-4-13'' - Tcl/Tk 8.4.13

   * ''core-8-4-12'' - Tcl/Tk 8.4.12

   * ''core-8-4-11'' - Tcl/Tk 8.4.11

   * ''core-8-4-10'' - Tcl/Tk 8.4.10

   * ''core-8-4-9'' - Tcl/Tk 8.4.9

   * ''core-8-4-8'' - Tcl/Tk 8.4.8

   * ''core-8-4-7'' - Tcl/Tk 8.4.7

   * ''core-8-4-6'' - Tcl/Tk 8.4.6

   * ''core-8-4-5'' - Tcl/Tk 8.4.5

   * ''core-8-4-4'' - Tcl/Tk 8.4.4

   * ''core-8-4-3'' - Tcl/Tk 8.4.3

   * ''core-8-4-2'' - Tcl/Tk 8.4.2

   * ''core-8-4-1'' - Tcl/Tk 8.4.1

   * ''core-8-4-0'' - Tcl/Tk 8.4.0

   * ''core-8-4-b2'' - Tcl/Tk 8.4b2

   * ''core-8-4-b1'' - Tcl/Tk 8.4b1

   * ''core-8-4-a4'' - Tcl/Tk 8.4a4

   * ''core-8-4-a3'' - Tcl/Tk 8.4a3

   * ''core-8-4-a2'' - Tcl/Tk 8.4a2

   * ''core-8-4-a1'' - Tcl/Tk 8.4a1

   * ''core-8-3-4'' - Tcl/Tk 8.3.4

   * ''core-8-3-3'' - Tcl/Tk 8.3.3

   * ''core-8-3-2'' - Tcl/Tk 8.3.2

   * ''core-8-3-1'' - Tcl/Tk 8.3.1

   * ''core-8-3-0'' - Tcl/Tk 8.3.0

   * ''core-8-3-b2'' - Tcl/Tk 8.3b2

   * ''core-8-3-b1'' - Tcl/Tk 8.3b1

   * ''core-8-2-3'' - Tcl/Tk 8.2.3

   * ''core-8-2-2'' - Tcl/Tk 8.2.2

   * ''core-8-2-1'' - Tcl/Tk 8.2.1

   * ''core-8-2-0'' - Tcl/Tk 8.2.0

   * ''core-8-2-b3'' - Tcl/Tk 8.2b3

   * ''core-8-2-b2'' - Tcl/Tk 8.2b2

   * ''core-8-2-b1'' - Tcl/Tk 8.2b1

   * ''core-8-1-1'' - Tcl/Tk 8.1.1

   * ''core-8-1-0'' - Tcl/Tk 8.1.0

   * ''core-8-1-b3'' - Tcl/Tk 8.1b3

   * ''core-8-1-b2'' - Tcl/Tk 8.1b2

   * ''core-8-1-b1'' - Tcl/Tk 8.1b1

   * ''core-8-0-5'' - Tcl/Tk 8.0.5

   * ''core-8-0-4'' - Tcl/Tk 8.0.4

   * ''core-8-0-3'' - Tcl/Tk 8.0.3

   * ''core-8-0-2'' - Tcl/Tk 8.0p2

~ Branch Tags - Official Development

The following branch tags label branches of development from which
releases of Tcl/Tk are generated:

   * ''HEAD'' - current development of new features; spawns future
     alpha and beta releases.

   * ''core-8-5-branch'' - bug fix branch; spawns 8.5.''X'' releases
     after 8.5.2.

   * ''core-8-4-branch'' - bug fix branch; spawns 8.4.''X'' releases
     after 8.4.2.

~ Branch Tags - Features

The following branch tags label branches on which features are being
developed and tested.  No releases of Tcl/Tk will be spawned from these
branches.  As the features mature, they will be merged onto the HEAD
branch, or they may be rejected.

   * ''core-8-4-win-speedup'' (Tk) - Work on improving performance of
     Tk on the Windows platforms.

   * ''tip-59-implementation'' (Tcl) - For coordinating between Andreas
     Kupries and the platform maintainers on implementing [59].

   * ''mod-8-3-4-branch'' (Tcl) - Contains the modularization work done
     by ActiveState for Cisco. Not for public modification.

   * ''dgp-refactor'' (Tcl) - Various refactoring exercises.

   * ''kennykb-numerics-branch'' (Tcl) - Explorations into improving
     Tcl's numeric properties, including support for large integers
     and rationals, and improvements to Tcl's floating point
     conversions.

   * ''msofer-wcodes-branch'' (Tcl) - Experimental features for the bytecode engine.

   * ''tip-257-implementation-branch'' (Tcl) - For development of the
     implementation of [257]. Branch root version at the tag
     ''tip-257-implementation-branch-root''.

   * ''tip-278-branch'' (Tcl) - Work on [278].

   * ''core-stabilizer-branch'' (Tcl/Tk) - Branch where the version
     number is bumped to the next level of stability above the HEAD
     for advance testing of issues that might arise when the HEAD is
     declared more stable.

   * ''tip-162-branch'' (Tcl) - Work on [162].  Includes extreme
     windows channel driver rewrite.  Maintained by [email protected]

~ Dead Branches

The following branch tags label branches that are no longer being
developed.  Some are old official branches from which releases are no
longer being spawned.  Others are feature development branches that
have been merged into an official branch, or rejected.

   * ''macosx-8-4-branch'' - Branch used during MacOSX porting work.
     Merged into 8.4.0.

   * ''dkf-64bit-support-branch'' (Tcl) - Work on supporting 64-bit
     numbers, particularly on 32-bit platforms (including large file
     support.)  See [72] for overview.  Results merged into HEAD.

   * ''kennykb-tip-22-33'' (Tcl) - Work on implementing the changes
     described in [22] and [33].  Abandoned.

   * ''dgp-privates-into-namespace'' (Tk) - Work on moving Tk's private
     commands and variables into the ::tk namespace and its children
     (see [44].)  Merged into Tk 8.4a3.

   * ''core-8-3-1-io-rewrite'' (Tcl) - Work rewriting Tcl's IO Channels
     to correct problems with the implementation of stacked channels.
     Merged into Tcl 8.3.2 and Tcl 8.4a2.

   * ''daves-chop-branch'' (Tcl) - Attempts to modularize subsystems so
     they can be easily removed at compile-time.  First step towards
     a 'tinytcl' on the HEAD rather than starting with an older
     version.  (maintained by [email protected])

   * ''daves-mk-branch'' (Tcl) - On-going work to improve the native
     windows makefiles.  One top-root makefile.win will serve as the
     starting point for MSVC++, BCC, and Watcom.  Extreme use of
     shared info will highlight this new system.  This is not TEA -
     this is anti-TEA. (maintained by [email protected])

   * ''core-8-3-1-branch'' - Spawned Tcl/Tk 8.3.X releases.

   * ''core-8-2-1-branch'' - Spawned Tcl/Tk 8.2.X releases.

   * ''core-8-1-branch-old'' - Spawned Tcl/Tk 8.1bX releases.

   * ''dev-stubs-branch'', ''dev-8-1-stubs-branch'' - Two branches on
     which the stubs interfaces were developed.  Merged into Tcl 8.1.

   * ''msofer-bcEngine'' (Tcl) - Work on improving performance of the
     bytecode engine.

~ Copyright

This document has been placed in the public domain.








|




|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|




|


|


|


|






|


|
|

|


|

|




|

|
|
|

|

|




|


|






|


|
|
|

|
|

|

|

|



|


|

|

|

|

|

|

|

|


|


|


>
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294

A tag may be used in a CVS repository only once, so we must keep track
of what tags have already been used, and what they mean.  The
remaining sections of this TIP record the tags in use.  This TIP
should be kept up to date by adding any new tags here as they are
added to the CVS repository.

# Release Tags

The following tags in the Tcl and Tk CVS repositories correspond to
the following releases of Tcl/Tk:

   * _core-8-6-b1_ - Tcl/Tk 8.6b1

   * _core-8-6-a3_ - Tcl/Tk 8.6a3

   * _core-8-6-a2_ - Tcl/Tk 8.6a2

   * _core-8-6-a1_ - Tcl/Tk 8.6a1

   * _core-8-5-6_  - Tcl/Tk 8.5.6

   * _core-8-5-5_  - Tcl/Tk 8.5.5

   * _core-8-5-4_  - Tcl/Tk 8.5.4

   * _core-8-5-3_  - Tcl/Tk 8.5.3

   * _core-8-5-2_  - Tcl/Tk 8.5.2

   * _core-8-5-1_  - Tcl/Tk 8.5.1

   * _core-8-5-0_  - Tcl/Tk 8.5.0

   * _core-8-5-b3_ - Tcl/Tk 8.5b3

   * _core-8-5-b2_ - Tcl/Tk 8.5b2

   * _core-8-5-b1_ - Tcl/Tk 8.5b1

   * _core-8-5-a6_ - Tcl/Tk 8.5a6

   * _core-8-5-a5_ - Tcl/Tk 8.5a5

   * _core-8-5-a4_ - Tcl/Tk 8.5a4

   * _core-8-5-a3_ - Tcl/Tk 8.5a3

   * _core-8-5-a2_ - Tcl/Tk 8.5a2

   * _core-8-5-a1_ - Tcl/Tk 8.5a1

   * _core-8-4-18_ - Tcl/Tk 8.4.18

   * _core-8-4-17_ - Tcl/Tk 8.4.17

   * _core-8-4-16_ - Tcl/Tk 8.4.16

   * _core-8-4-15_ - Tcl/Tk 8.4.15

   * _core-8-4-14_ - Tcl/Tk 8.4.14

   * _core-8-4-13_ - Tcl/Tk 8.4.13

   * _core-8-4-12_ - Tcl/Tk 8.4.12

   * _core-8-4-11_ - Tcl/Tk 8.4.11

   * _core-8-4-10_ - Tcl/Tk 8.4.10

   * _core-8-4-9_ - Tcl/Tk 8.4.9

   * _core-8-4-8_ - Tcl/Tk 8.4.8

   * _core-8-4-7_ - Tcl/Tk 8.4.7

   * _core-8-4-6_ - Tcl/Tk 8.4.6

   * _core-8-4-5_ - Tcl/Tk 8.4.5

   * _core-8-4-4_ - Tcl/Tk 8.4.4

   * _core-8-4-3_ - Tcl/Tk 8.4.3

   * _core-8-4-2_ - Tcl/Tk 8.4.2

   * _core-8-4-1_ - Tcl/Tk 8.4.1

   * _core-8-4-0_ - Tcl/Tk 8.4.0

   * _core-8-4-b2_ - Tcl/Tk 8.4b2

   * _core-8-4-b1_ - Tcl/Tk 8.4b1

   * _core-8-4-a4_ - Tcl/Tk 8.4a4

   * _core-8-4-a3_ - Tcl/Tk 8.4a3

   * _core-8-4-a2_ - Tcl/Tk 8.4a2

   * _core-8-4-a1_ - Tcl/Tk 8.4a1

   * _core-8-3-4_ - Tcl/Tk 8.3.4

   * _core-8-3-3_ - Tcl/Tk 8.3.3

   * _core-8-3-2_ - Tcl/Tk 8.3.2

   * _core-8-3-1_ - Tcl/Tk 8.3.1

   * _core-8-3-0_ - Tcl/Tk 8.3.0

   * _core-8-3-b2_ - Tcl/Tk 8.3b2

   * _core-8-3-b1_ - Tcl/Tk 8.3b1

   * _core-8-2-3_ - Tcl/Tk 8.2.3

   * _core-8-2-2_ - Tcl/Tk 8.2.2

   * _core-8-2-1_ - Tcl/Tk 8.2.1

   * _core-8-2-0_ - Tcl/Tk 8.2.0

   * _core-8-2-b3_ - Tcl/Tk 8.2b3

   * _core-8-2-b2_ - Tcl/Tk 8.2b2

   * _core-8-2-b1_ - Tcl/Tk 8.2b1

   * _core-8-1-1_ - Tcl/Tk 8.1.1

   * _core-8-1-0_ - Tcl/Tk 8.1.0

   * _core-8-1-b3_ - Tcl/Tk 8.1b3

   * _core-8-1-b2_ - Tcl/Tk 8.1b2

   * _core-8-1-b1_ - Tcl/Tk 8.1b1

   * _core-8-0-5_ - Tcl/Tk 8.0.5

   * _core-8-0-4_ - Tcl/Tk 8.0.4

   * _core-8-0-3_ - Tcl/Tk 8.0.3

   * _core-8-0-2_ - Tcl/Tk 8.0p2

# Branch Tags - Official Development

The following branch tags label branches of development from which
releases of Tcl/Tk are generated:

   * _HEAD_ - current development of new features; spawns future
     alpha and beta releases.

   * _core-8-5-branch_ - bug fix branch; spawns 8.5._X_ releases
     after 8.5.2.

   * _core-8-4-branch_ - bug fix branch; spawns 8.4._X_ releases
     after 8.4.2.

# Branch Tags - Features

The following branch tags label branches on which features are being
developed and tested.  No releases of Tcl/Tk will be spawned from these
branches.  As the features mature, they will be merged onto the HEAD
branch, or they may be rejected.

   * _core-8-4-win-speedup_ \(Tk\) - Work on improving performance of
     Tk on the Windows platforms.

   * _tip-59-implementation_ \(Tcl\) - For coordinating between Andreas
     Kupries and the platform maintainers on implementing [[59]](59.md).

   * _mod-8-3-4-branch_ \(Tcl\) - Contains the modularization work done
     by ActiveState for Cisco. Not for public modification.

   * _dgp-refactor_ \(Tcl\) - Various refactoring exercises.

   * _kennykb-numerics-branch_ \(Tcl\) - Explorations into improving
     Tcl's numeric properties, including support for large integers
     and rationals, and improvements to Tcl's floating point
     conversions.

   * _msofer-wcodes-branch_ \(Tcl\) - Experimental features for the bytecode engine.

   * _tip-257-implementation-branch_ \(Tcl\) - For development of the
     implementation of [[257]](257.md). Branch root version at the tag
     _tip-257-implementation-branch-root_.

   * _tip-278-branch_ \(Tcl\) - Work on [[278]](278.md).

   * _core-stabilizer-branch_ \(Tcl/Tk\) - Branch where the version
     number is bumped to the next level of stability above the HEAD
     for advance testing of issues that might arise when the HEAD is
     declared more stable.

   * _tip-162-branch_ \(Tcl\) - Work on [[162]](162.md).  Includes extreme
     windows channel driver rewrite.  Maintained by [email protected]

# Dead Branches

The following branch tags label branches that are no longer being
developed.  Some are old official branches from which releases are no
longer being spawned.  Others are feature development branches that
have been merged into an official branch, or rejected.

   * _macosx-8-4-branch_ - Branch used during MacOSX porting work.
     Merged into 8.4.0.

   * _dkf-64bit-support-branch_ \(Tcl\) - Work on supporting 64-bit
     numbers, particularly on 32-bit platforms \(including large file
     support.\)  See [[72]](72.md) for overview.  Results merged into HEAD.

   * _kennykb-tip-22-33_ \(Tcl\) - Work on implementing the changes
     described in [[22]](22.md) and [[33]](33.md).  Abandoned.

   * _dgp-privates-into-namespace_ \(Tk\) - Work on moving Tk's private
     commands and variables into the ::tk namespace and its children
     \(see [[44]](44.md).\)  Merged into Tk 8.4a3.

   * _core-8-3-1-io-rewrite_ \(Tcl\) - Work rewriting Tcl's IO Channels
     to correct problems with the implementation of stacked channels.
     Merged into Tcl 8.3.2 and Tcl 8.4a2.

   * _daves-chop-branch_ \(Tcl\) - Attempts to modularize subsystems so
     they can be easily removed at compile-time.  First step towards
     a 'tinytcl' on the HEAD rather than starting with an older
     version.  \(maintained by [email protected]\)

   * _daves-mk-branch_ \(Tcl\) - On-going work to improve the native
     windows makefiles.  One top-root makefile.win will serve as the
     starting point for MSVC\+\+, BCC, and Watcom.  Extreme use of
     shared info will highlight this new system.  This is not TEA -
     this is anti-TEA. \(maintained by [email protected]\)

   * _core-8-3-1-branch_ - Spawned Tcl/Tk 8.3.X releases.

   * _core-8-2-1-branch_ - Spawned Tcl/Tk 8.2.X releases.

   * _core-8-1-branch-old_ - Spawned Tcl/Tk 8.1bX releases.

   * _dev-stubs-branch_, _dev-8-1-stubs-branch_ - Two branches on
     which the stubs interfaces were developed.  Merged into Tcl 8.1.

   * _msofer-bcEngine_ \(Tcl\) - Work on improving performance of the
     bytecode engine.

# Copyright

This document has been placed in the public domain.

Name change from tip/310.tip to tip/310.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

TIP:		310
Title:		Add a New Pseudo-Random Number Generator
Version:	$Revision: 1.3 $
Author:		Arjen Markus <[email protected]>
State:		Rejected
Type:		Project
Vote:		Done
Created:	07-Jan-2008
Post-History:
Tcl-Version:	8.6
Keywords:	expr


~ Abstract

This TIP proposes to add a new '''expr''' function: a random number generator
with a longer sequence than the one currently in the core.

~ Rationale

The '''expr''' command has used a straightforward implementation of a
pseudo-random number generator via the rand() function for many years. This
has a number of desirable properties, but better ones (e.g. with a longer
sequence) have been known for a long time. This TIP proposes a new function as
an alternative PRNG.

PRNGs with different properties can be important for Monte Carlo simulations
and other algorithms that require large amounts of random numbers without
having to worry about the sequence length.

~ Proposal

Introduce a new function, ''randM()'', as an alternative PRNG to the
'''expr''' command. This function is based on work by George Marsaglia and
implementations in many different languages are available on the Internet.
There will be a corresponding seed function ''srandM(x)''.

The new function is not a replacement of the original rand() function.

~ Implementation

With the new tcl::mathfunc mechanism ([232]) it should be simple to add this
function to the core.

An example implementation in Tcl is given below:

| # marsaglia.tcl --
| #     Implementation of a PRNG according to George Marsaglia
| #

| namespace eval ::PRNG {
|     variable mod [expr {wide(256)*wide(256)*wide(256)*wide(256)-5}]
|     variable fac [expr {wide(256)*wide(32)}]
|     variable x1 [expr {wide($mod*rand())}]
|     variable x2 [expr {wide($mod*rand())}]
|     variable x3 [expr {wide($mod*rand())}]
|
|     puts $mod
| }

|
| proc ::PRNG::marsaglia {} {
|     variable mod
|     variable fac
|     variable x1
|     variable x2
|     variable x3
|
|     set xn [expr {($fac*($x3+$x2+$x1))%$mod}]
|
|     set x1 $x2
|     set x2 $x3
|     set x3 $xn
|
|     return [expr {$xn/double($mod)}]
| }


~ Copyright

This document is placed in the public domain

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|
|
|
|






|

|
|

|

|

|

|




|
|
<
>
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
|
>
|


>

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

# TIP 310: Add a New Pseudo-Random Number Generator

	Author:		Arjen Markus <[email protected]>
	State:		Rejected
	Type:		Project
	Vote:		Done
	Created:	07-Jan-2008
	Post-History:
	Tcl-Version:	8.6
	Keywords:	expr
-----

# Abstract

This TIP proposes to add a new **expr** function: a random number generator
with a longer sequence than the one currently in the core.

# Rationale

The **expr** command has used a straightforward implementation of a
pseudo-random number generator via the rand\(\) function for many years. This
has a number of desirable properties, but better ones \(e.g. with a longer
sequence\) have been known for a long time. This TIP proposes a new function as
an alternative PRNG.

PRNGs with different properties can be important for Monte Carlo simulations
and other algorithms that require large amounts of random numbers without
having to worry about the sequence length.

# Proposal

Introduce a new function, _randM\(\)_, as an alternative PRNG to the
**expr** command. This function is based on work by George Marsaglia and
implementations in many different languages are available on the Internet.
There will be a corresponding seed function _srandM\(x\)_.

The new function is not a replacement of the original rand\(\) function.

# Implementation

With the new tcl::mathfunc mechanism \([[232]](232.md)\) it should be simple to add this
function to the core.

An example implementation in Tcl is given below:

	 # marsaglia.tcl --
	 #     Implementation of a PRNG according to George Marsaglia

	 #
	 namespace eval ::PRNG {
	     variable mod [expr {wide(256)*wide(256)*wide(256)*wide(256)-5}]
	     variable fac [expr {wide(256)*wide(32)}]
	     variable x1 [expr {wide($mod*rand())}]
	     variable x2 [expr {wide($mod*rand())}]
	     variable x3 [expr {wide($mod*rand())}]
	
	     puts $mod

	 }
	
	 proc ::PRNG::marsaglia {} {
	     variable mod
	     variable fac
	     variable x1
	     variable x2
	     variable x3
	
	     set xn [expr {($fac*($x3+$x2+$x1))%$mod}]
	
	     set x1 $x2
	     set x2 $x3
	     set x3 $xn
	
	     return [expr {$xn/double($mod)}]

	 }

# Copyright

This document is placed in the public domain

Name change from tip/311.tip to tip/311.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242

TIP:            311
Title:          Tcl/Tk 8.6 Release Calendar
Version:        $Revision: 1.66 $
Author:         Don Porter <[email protected]>
Author:         Larry W. Virden <[email protected]>
Author:         Joe Mistachkin <[email protected]>
Author:         Pat Thoyts <[email protected]>
Author:         Miguel Sofer <[email protected]>
Author:         Lars Hellstr�m <[email protected]>
Author:         Alexandre Ferrieux <[email protected]>
Author:         Arnulf Wiedemann <[email protected]>
Author:         Trevor Davel <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         Jan Nijtmans <[email protected]>
State:          Draft
Type:           Informative
Vote:           Pending
Created:        08-Jan-2008
Post-History:   


~ Abstract

This TIP serves to coordinate Tcl/Tk 8.6 development releases and the features
they deliver.

~ Introduction

Following up on a message to the '[email protected]' mailing
list, [http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/3594952], a
draft release calendar for Tcl/Tk 8.6 alpha and beta releases is presented
below.

The intent is for developers working on Tcl and Tk to add under each release
date those features they intend to make part of that release. For features
which already are described by another TIP, a reference to that TIP is
sufficient, and the recommended way to update this page. For features which
have not yet been TIPped, a brief description and the names of those actively
working on it are an acceptable temporary replacement, but should be replaced
with a TIP reference as soon as one is ready.

This is meant to be a working document, which gets updated by all stakeholders
to reflect ongoing progress and any changes of plan. It's not a contract or a
promise, just a place to record the intents of an entire community of
developers. Anything in it might be revised, and any intent expressed in it
might well not be fulfilled.  Due to its nature, there will never be any vote
on this TIP. It is more analogous to similar informational TIPs like [31].

~ Release Calendar

~~ Tcl/Tk 8.6a1; Release Date: June 25, 2008

   * [230], Tcl Channel Transformation Reflection API

   * [257], Object Orientation for Tcl

   * [285], Script Cancellation with '''interp cancel''' and Tcl_CancelEval

   * [317], Extend '''binary''' Ensemble with Binary Encodings

~~ Tcl/Tk 8.6a2; Release Date: August 25, 2008

   * [304], A Standalone '''chan pipe''' Primitive for Advanced Child IPC

   * NRE core. This is an internal change that allows infinite recursion and
     enables new features (like '''::tcl::unsupported::tailcall'''). Official
     API exposure was in later versions.

~~ Tcl/Tk 8.6a3; Release Date: October 10, 2008

   * [195], A Unique Prefix Handling Command

   * [236], Absolute Positioning of Canvas Items

   * [265], A Convenient C-side Command Option Parser for Tcl

   * [308], Tcl Database Connectivity (TDBC)

   * [313], Inexact Searching in Sorted List

   * [314], Ensembles with Parameters

   * [315], Add pathSeparator to tcl_platform Array

   * [316], Portable Access Functions for Stat Buffers

   * [318], Extend Default Whitespace in '''string trim''' Beyond ASCII

   * [320], Improved Variable Handling in the Core Object System

   * [323], Do Nothing Gracefully

   * [326], Add '''-stride''' Option to '''lsort'''

   * [327], Proper Tailcalls

   * [328], Coroutines

   * [330], Eliminate interp->result from the Public Headers

   * [331], Allow '''lset''' to Extend Lists

~~ Tcl/Tk 8.6b1; Release Date: December 23, 2008

   * [97], Moving Vertices of Canvas Items

   * [119], Angled Text on a Canvas

   * [197], Unfocussed Text Widget Cursor Control

   * [210], Add '''tempfile''' Subcommand to '''file'''

   * [234], Add Support For Zlib Compression

   * [307], Make TclTransferResult() Public

   * [321], Add a '''tk busy''' Command

   * [322], Publish the NRE API

   * [324], A Standard Dialog For Font Selection

   * [329], '''Try'''/'''Catch'''/'''Finally''' syntax

   * [332], Half-Close for Bidirectional Channels

   * [335], An API for Detecting Active Interpreters

   * [336], Supported Access To interp->errorline

   * [337], Make TclBackgroundException() Public

   * [338], Embedder Access to Startup Scripts of *_Main()

   * [341], Multiple '''dict filter''' Patterns

   * [343], A Binary Specifier for '''format'''/'''scan'''

~~ Tcl/Tk 8.6b2; Release Date: August 5, 2011

   * [50], Bundle [[incr Tcl]] with the Core Tcl distribution

   > * Note that this is Itcl-ng (Itcl 4.0), and it is done by the external
       packages mechanism.

   * [162], IPv6 Sockets for Tcl

   * [171], Change Default <MouseWheel> Bindings Behavior

   * [244], PNG Photo Image Support for Tk

   * [348], Substituted 'errorstack' / 'traceback'

   * [353], NR-enabled Expressions for Extensions

   * [354], Minor Production-Driven TclOO Revisions

   * [356], NR-enabled Substitutions for Extensions

   * [357], Export TclLoadFile

   > * Enables bundling of TDBC drivers with Tcl.

   * [359], Extended Window Manager Hint Support

   > * Note that this is also being backported to 8.5 and 8.4; it is in
       response to a change in expectations in third-party software.

   * [360], Modernize X11 Menus

   * [362], Simple 32 and 64 bit Registry Support

   * [364],
     Threading Support: Configuration and Package

   * [381], Call Chain Introspection and Control

~~ Tcl/Tk 8.6b3; Release Date: September 18, 2012

   * [106], Add Encoding Abilities to the [[dde]] Command

   * [376], Bundle sqlite3 and tdbc::sqlite3 Packages

   * [378], Fixing the Performance of [280]

   * [380], TclOO Slots for Flexible Declarations

   * [382], Let tk_getSaveFile ignore file overwrites

   * [388], Extending Unicode literals past the BMP

   * [395], New 'string is entier' Command

   * [396], Symmetric Coroutines, Multiple Args, and yieldto

   * [397], Extensible Object Copying

   * [398], Quickly Exit with Non-Blocking Blocked Channels

   * [403], Web Colors for Tk

   * [404], Let Message Catalogs get the Locale from their File Name

~~ Tcl/Tk 8.6.0: Release Date: December 20, 2012

   * [400], Setting the Compression Dictionary and Other 'zlib' Updates

   * [405], Add Collecting Loops, the 'lmap' and 'dict map' Commands

   * [413], Unicode Support for 'string is space' and 'string trim'

   * [416], New Options for 'load' - -global and -lazy

~~~ Pending Features

These have been voted in, but not yet implemented.

   * [399], Dynamic Locale Changing for msgcat

   > * May be superseded by [412] due to problems found with a lack of
       dynamism in this TIP's API.

These are currently on the schedule to make 8.6, though perhaps not 8.6.0.
[406] and [412] target co-distributed packages, not Tcl itself.

   * [392], Allow Bignums to be Disabled at Runtime on a Per-Interp Basis

   > * May make later versions than 8.6.0 and may be backported to 8.5.

   * [406], "C" is for Cookie

   * [412], Dynamic Locale Changing for msgcat with On-Demand File
     Load

   > * Replacement for [399].

~ Work Roster

See the Wiki page, http://wiki.tcl.tk/20966

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>

|




|


|
















|

|

|

|

|

|

|

|

|


|


|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|


|

|

|

|

|

|

|

|

|

|

|


|

|

|


|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|



|

|



|

|

|

|

|


|

|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242

# TIP 311: Tcl/Tk 8.6 Release Calendar

	Author:         Don Porter <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	Author:         Joe Mistachkin <[email protected]>
	Author:         Pat Thoyts <[email protected]>
	Author:         Miguel Sofer <[email protected]>
	Author:         Lars Hellström <[email protected]>
	Author:         Alexandre Ferrieux <[email protected]>
	Author:         Arnulf Wiedemann <[email protected]>
	Author:         Trevor Davel <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         Jan Nijtmans <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        08-Jan-2008
	Post-History:   
-----

# Abstract

This TIP serves to coordinate Tcl/Tk 8.6 development releases and the features
they deliver.

# Introduction

Following up on a message to the '[email protected]' mailing
list, <http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/3594952> , a
draft release calendar for Tcl/Tk 8.6 alpha and beta releases is presented
below.

The intent is for developers working on Tcl and Tk to add under each release
date those features they intend to make part of that release. For features
which already are described by another TIP, a reference to that TIP is
sufficient, and the recommended way to update this page. For features which
have not yet been TIPped, a brief description and the names of those actively
working on it are an acceptable temporary replacement, but should be replaced
with a TIP reference as soon as one is ready.

This is meant to be a working document, which gets updated by all stakeholders
to reflect ongoing progress and any changes of plan. It's not a contract or a
promise, just a place to record the intents of an entire community of
developers. Anything in it might be revised, and any intent expressed in it
might well not be fulfilled.  Due to its nature, there will never be any vote
on this TIP. It is more analogous to similar informational TIPs like [[31]](31.md).

# Release Calendar

## Tcl/Tk 8.6a1; Release Date: June 25, 2008

   * [[230]](230.md), Tcl Channel Transformation Reflection API

   * [[257]](257.md), Object Orientation for Tcl

   * [[285]](285.md), Script Cancellation with **interp cancel** and Tcl\_CancelEval

   * [[317]](317.md), Extend **binary** Ensemble with Binary Encodings

## Tcl/Tk 8.6a2; Release Date: August 25, 2008

   * [[304]](304.md), A Standalone **chan pipe** Primitive for Advanced Child IPC

   * NRE core. This is an internal change that allows infinite recursion and
     enables new features \(like **::tcl::unsupported::tailcall**\). Official
     API exposure was in later versions.

## Tcl/Tk 8.6a3; Release Date: October 10, 2008

   * [[195]](195.md), A Unique Prefix Handling Command

   * [[236]](236.md), Absolute Positioning of Canvas Items

   * [[265]](265.md), A Convenient C-side Command Option Parser for Tcl

   * [[308]](308.md), Tcl Database Connectivity \(TDBC\)

   * [[313]](313.md), Inexact Searching in Sorted List

   * [[314]](314.md), Ensembles with Parameters

   * [[315]](315.md), Add pathSeparator to tcl\_platform Array

   * [[316]](316.md), Portable Access Functions for Stat Buffers

   * [[318]](318.md), Extend Default Whitespace in **string trim** Beyond ASCII

   * [[320]](320.md), Improved Variable Handling in the Core Object System

   * [[323]](323.md), Do Nothing Gracefully

   * [[326]](326.md), Add **-stride** Option to **lsort**

   * [[327]](327.md), Proper Tailcalls

   * [[328]](328.md), Coroutines

   * [[330]](330.md), Eliminate interp->result from the Public Headers

   * [[331]](331.md), Allow **lset** to Extend Lists

## Tcl/Tk 8.6b1; Release Date: December 23, 2008

   * [[97]](97.md), Moving Vertices of Canvas Items

   * [[119]](119.md), Angled Text on a Canvas

   * [[197]](197.md), Unfocussed Text Widget Cursor Control

   * [[210]](210.md), Add **tempfile** Subcommand to **file**

   * [[234]](234.md), Add Support For Zlib Compression

   * [[307]](307.md), Make TclTransferResult\(\) Public

   * [[321]](321.md), Add a **tk busy** Command

   * [[322]](322.md), Publish the NRE API

   * [[324]](324.md), A Standard Dialog For Font Selection

   * [[329]](329.md), **Try**/**Catch**/**Finally** syntax

   * [[332]](332.md), Half-Close for Bidirectional Channels

   * [[335]](335.md), An API for Detecting Active Interpreters

   * [[336]](336.md), Supported Access To interp->errorline

   * [[337]](337.md), Make TclBackgroundException\(\) Public

   * [[338]](338.md), Embedder Access to Startup Scripts of \*\_Main\(\)

   * [[341]](341.md), Multiple **dict filter** Patterns

   * [[343]](343.md), A Binary Specifier for **format**/**scan**

## Tcl/Tk 8.6b2; Release Date: August 5, 2011

   * [[50]](50.md), Bundle [incr Tcl] with the Core Tcl distribution

	   > \* Note that this is Itcl-ng \(Itcl 4.0\), and it is done by the external
       packages mechanism.

   * [[162]](162.md), IPv6 Sockets for Tcl

   * [[171]](171.md), Change Default <MouseWheel> Bindings Behavior

   * [[244]](244.md), PNG Photo Image Support for Tk

   * [[348]](348.md), Substituted 'errorstack' / 'traceback'

   * [[353]](353.md), NR-enabled Expressions for Extensions

   * [[354]](354.md), Minor Production-Driven TclOO Revisions

   * [[356]](356.md), NR-enabled Substitutions for Extensions

   * [[357]](357.md), Export TclLoadFile

	   > \* Enables bundling of TDBC drivers with Tcl.

   * [[359]](359.md), Extended Window Manager Hint Support

	   > \* Note that this is also being backported to 8.5 and 8.4; it is in
       response to a change in expectations in third-party software.

   * [[360]](360.md), Modernize X11 Menus

   * [[362]](362.md), Simple 32 and 64 bit Registry Support

   * [[364]](364.md),
     Threading Support: Configuration and Package

   * [[381]](381.md), Call Chain Introspection and Control

## Tcl/Tk 8.6b3; Release Date: September 18, 2012

   * [[106]](106.md), Add Encoding Abilities to the [dde] Command

   * [[376]](376.md), Bundle sqlite3 and tdbc::sqlite3 Packages

   * [[378]](378.md), Fixing the Performance of [[280]](280.md)

   * [[380]](380.md), TclOO Slots for Flexible Declarations

   * [[382]](382.md), Let tk\_getSaveFile ignore file overwrites

   * [[388]](388.md), Extending Unicode literals past the BMP

   * [[395]](395.md), New 'string is entier' Command

   * [[396]](396.md), Symmetric Coroutines, Multiple Args, and yieldto

   * [[397]](397.md), Extensible Object Copying

   * [[398]](398.md), Quickly Exit with Non-Blocking Blocked Channels

   * [[403]](403.md), Web Colors for Tk

   * [[404]](404.md), Let Message Catalogs get the Locale from their File Name

## Tcl/Tk 8.6.0: Release Date: December 20, 2012

   * [[400]](400.md), Setting the Compression Dictionary and Other 'zlib' Updates

   * [[405]](405.md), Add Collecting Loops, the 'lmap' and 'dict map' Commands

   * [[413]](413.md), Unicode Support for 'string is space' and 'string trim'

   * [[416]](416.md), New Options for 'load' - -global and -lazy

### Pending Features

These have been voted in, but not yet implemented.

   * [[399]](399.md), Dynamic Locale Changing for msgcat

	   > \* May be superseded by [[412]](412.md) due to problems found with a lack of
       dynamism in this TIP's API.

These are currently on the schedule to make 8.6, though perhaps not 8.6.0.
[[406]](406.md) and [[412]](412.md) target co-distributed packages, not Tcl itself.

   * [[392]](392.md), Allow Bignums to be Disabled at Runtime on a Per-Interp Basis

	   > \* May make later versions than 8.6.0 and may be backported to 8.5.

   * [[406]](406.md), "C" is for Cookie

   * [[412]](412.md), Dynamic Locale Changing for msgcat with On-Demand File
     Load

	   > \* Replacement for [[399]](399.md).

# Work Roster

See the Wiki page, <http://wiki.tcl.tk/20966>

# Copyright

This document has been placed in the public domain.

Name change from tip/312.tip to tip/312.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

TIP:            312
Title:          Add More Link Types
Version:        $Revision: 1.9 $
Author:         Rene Zaumseil <[email protected]>
Author:         Larry W. Virden <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        26-Jan-2008
Post-History:   
Keywords:       variable,trace
Tcl-Version:    8.7


~ Abstract

This TIP proposes adding a command, '''Tcl_LinkArray''', to allow linking of C
variables to Tcl lists. It also adds more types of linked variable.

~ Rationale

The current C-API allows one to only link single variables. The proposed
''Tcl_LinkArray'' function allows the linking of C-arrays to Tcl list
variables. If the given ''size'' value is 1 then it works like the existing
''Tcl_LinkVar'' function. The automatic creation of needed space when no
''address'' value is provided could be used for testing scenarios.

The new link types also allow one to link from strings and binary arrays to
fixed memory locations.

The use of arrays with a given ''size > 1'' allows a safe and simple C-Tcl
connection. Array overwrites create errors.

~ Specification

This document proposes the following changes to the Tcl core:

~~ New C API

Add a new public ''Tcl_LinkArray'' function to provide links of single
variable and array variables. The new function would have the same parameters
as the ''Tcl_LinkVar'' function, plus an additional ''int size''. If the given
size is 1, then we have the same functionality as before. With ''size'' > 1,
the linked Tcl variable is a list variable. If the given address is NULL then
the function allocates the necessary space on the C side itself.

 > int '''Tcl_LinkArray'''(Tcl_Interp *''interp'', const char *''varName'',
   char *''addr'', int ''type'', int ''size'')

The following link types will be supported:

 > TCL_LINK_INT, TCL_LINK_DOUBLE, TCL_LINK_BOOLEAN, TCL_LINK_STRING,
   TCL_LINK_WIDE_INT, TCL_LINK_CHAR, TCL_LINK_UCHAR, TCL_LINK_SHORT,
   TCL_LINK_USHORT, TCL_LINK_UINT, TCL_LINK_LONG, TCL_LINK_ULONG,
   TCL_LINK_FLOAT, TCL_LINK_WIDE_UINT, TCL_LINK_CHARS, TCL_LINK_BINARY

Of these, TCL_LINK_CHARS and TCL_LINK_BINARY are new, and are as defined
below:

 TCL_LINK_CHARS: The address of the C variable is used as a ''char *''. The
   address remains always the same (different to TCL_LINK_STRING) and contains
   a \0 terminated string. The \0 counts towards the given ''size''. The Tcl
   variable is used as a string and can contain up to ''size -1'' characters.

 TCL_LINK_BINARY: The address of the C variable is used as a ''unsigned char
   *''. The address remains always the same. Read and write operations must
   always contain the full sized binary string.

~ Reference Implementation

See [https://sourceforge.net/support/tracker.php?aid=1992824].

~ Notes

The original TIP proposed a ''link'' command to allow these things to be done
from the script level; this has been removed in the test suite support because
of concerns about safety and security.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|


|
|
|
|




|


|



|

|

|
|



|
|



|
|
|
|

|


|
|
|
|

|
|


|

|

|

|



|


>

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

# TIP 312: Add More Link Types

	Author:         Rene Zaumseil <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        26-Jan-2008
	Post-History:   
	Keywords:       variable,trace
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes adding a command, **Tcl\_LinkArray**, to allow linking of C
variables to Tcl lists. It also adds more types of linked variable.

# Rationale

The current C-API allows one to only link single variables. The proposed
_Tcl\_LinkArray_ function allows the linking of C-arrays to Tcl list
variables. If the given _size_ value is 1 then it works like the existing
_Tcl\_LinkVar_ function. The automatic creation of needed space when no
_address_ value is provided could be used for testing scenarios.

The new link types also allow one to link from strings and binary arrays to
fixed memory locations.

The use of arrays with a given _size > 1_ allows a safe and simple C-Tcl
connection. Array overwrites create errors.

# Specification

This document proposes the following changes to the Tcl core:

## New C API

Add a new public _Tcl\_LinkArray_ function to provide links of single
variable and array variables. The new function would have the same parameters
as the _Tcl\_LinkVar_ function, plus an additional _int size_. If the given
size is 1, then we have the same functionality as before. With _size_ > 1,
the linked Tcl variable is a list variable. If the given address is NULL then
the function allocates the necessary space on the C side itself.

 > int **Tcl\_LinkArray**\(Tcl\_Interp \*_interp_, const char \*_varName_,
   char \*_addr_, int _type_, int _size_\)

The following link types will be supported:

 > TCL\_LINK\_INT, TCL\_LINK\_DOUBLE, TCL\_LINK\_BOOLEAN, TCL\_LINK\_STRING,
   TCL\_LINK\_WIDE\_INT, TCL\_LINK\_CHAR, TCL\_LINK\_UCHAR, TCL\_LINK\_SHORT,
   TCL\_LINK\_USHORT, TCL\_LINK\_UINT, TCL\_LINK\_LONG, TCL\_LINK\_ULONG,
   TCL\_LINK\_FLOAT, TCL\_LINK\_WIDE\_UINT, TCL\_LINK\_CHARS, TCL\_LINK\_BINARY

Of these, TCL\_LINK\_CHARS and TCL\_LINK\_BINARY are new, and are as defined
below:

 TCL\_LINK\_CHARS: The address of the C variable is used as a _char \*_. The
   address remains always the same \(different to TCL\_LINK\_STRING\) and contains
   a \\0 terminated string. The \\0 counts towards the given _size_. The Tcl
   variable is used as a string and can contain up to _size -1_ characters.

 TCL\_LINK\_BINARY: The address of the C variable is used as a _unsigned char
   *_. The address remains always the same. Read and write operations must
   always contain the full sized binary string.

# Reference Implementation

See <https://sourceforge.net/support/tracker.php?aid=1992824> .

# Notes

The original TIP proposed a _link_ command to allow these things to be done
from the script level; this has been removed in the test suite support because
of concerns about safety and security.

# Copyright

This document has been placed in the public domain.

Name change from tip/313.tip to tip/313.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163

TIP:            313
Title:          Inexact Searching in Sorted List
Version:        $Revision: 1.14 $
Author:         Peter Spjuth <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        14-Feb-2008
Post-History:   
Keywords:       Tcl
Tcl-Version:    8.6


~ Abstract

This TIP adds a new switch to '''lsearch''' to do a binary search to find the
insertion point in a sorted list.

~ Rationale

Sometimes, it is necessary to find the location in a sorted list where a
particular new element could be inserted. Either for actual insertion or for
lookups to do interpolation or approximate search in data tables. Given that
the list is already sorted, it is obviously the case that the location should
be located through an O(log N) algorithm that takes advantage of this fact
(binary searching is the most reliable method given that measuring the
"distance" between two strings is a complex and expensive operation in
itself).

The usefulness of the feature is shown by a quick search. I found usages in
the core, in tcllib and in tklib. Given that the infrastructure for a binary
search is already in '''lsearch''', this is a very cheap addition.

One question for the specification is exactly what index should be returned.
Below an increasing list is assumed, things are equivalent for a decreasing.

 1. First where element is greater than key.

 2. Last  where element is less than or equal to key.

 3. First where element is greater than or equal to key.

 4. Last  where element is less than key.

Here, 1 is the use case for a stable insertion sort.

In the core we can find '''::tcl::clock::BSearch''' which returns the index of
the greatest element in $list that is less than or equal to $key, i.e. type 2.
The same can be found in tklib's ::khim::BSearch.

In tcllib we can find '''::struct::prioqueue::__linsertsorted''', which would
use type 1.

Personally I have had use for both 2 and 3.

1 can trivialy be calculated from 2 and vice versa. Same for 3 and 4.

One key difference between 1/2 and 3/4 is that 1/2 return last among equals
while 3/4 returns first among equals. This means that it is easier to lay 3/4
over 1/2 by first doing an exact search. ''i.e.'' by doing both a -sorted and
a -bisect search you get all info needed, in log(N) time, to get either of
1/2/3/4.

Finally, I think it makes sense for '''lsearch''' to return an exact match if
there is one, leading to type 2 being specified in this TIP.

For a decreasing list, things are equivalent. The same relationships between
1/2/3/4 applies, so it is reasonable to select the same there.

I saw the word bisect used for this type of operation, but a better name is
probably possible if someone have a suggestion.

~ Specification

An option '''-bisect''' is added to '''lsearch'''. This is a modifier to
'''-sorted''' and implies '''-sorted''' search mode.

The list to be searched thus must be sorted and how it is sorted is specified
just as for unmodified '''-sorted'''.

For an increasing list, the '''-bisect''' flag makes '''lsearch''' return the
greatest index where the element is less than or equal to the key.

For a decreasing list, the '''-bisect''' flag makes '''lsearch''' return the
greatest index where the element is greater than or equal to the key.

If the key is before the first element, or the list is empty, -1 is returned.

It is illegal to use '''-bisect''' with either '''-all''' or '''-not'''.

Note that '''-inline''' and '''-start''' are still valid, though perhaps not
very useful.

~ Examples

A stable insertion sort:

|set dest {}
|foreach elem $src {
|    set i [lsearch -bisect -integer $dest]
|    set dest [linsert $dest [+ $i 1] $elem]
|}


~ Reference Implementation

http://sourceforge.net/support/tracker.php?aid=1894241

~ Further Use Cases

Some messages on news:comp.lang.tcl provide additional motivation for this
TIP:

From Kevin Kenny: <[email protected]>:

 > [[...]] When I've coded binary search like that, it's generally been as
   part of an interpolation or approximate search procedure. For instance,
   '''::tcl::clock::BSearch''' finds, among other things, the last change of
   time zone at or before a given time. The cubic spline procedure in tcllib
   uses BSearch to find the control point just to the left of the interpolated
   point. There are a great many cases where you want to look up the nearest
   neighbour without inserting anything if there is no exact match.

From Neil Madden: <[email protected]>:

 > Indeed. My own recent experience was in looking up annotations to display
   while playing back some 3D visualisation data (through Togl). A list of
   form {timestamp annotation ts annot ...} was used and the annotation should
   be displayed for any frame from that timestamp up until the next
   annotation. When the user can randomly seek to any position in the data it
   was necessary to find the nearest preceeding annotation. I hand-coded a
   binary search for this. This '''lsearch''' enhancement would have been
   ideal (well, providing I massaged the data into a form suitable for use
   with '''-index''', which I assume this TIP is compatible with).

~ Alternatives

Instead of making '''-bisect''' a modifier to '''-sorted''' it could be a
search mode in itself. This was the original specification in this TIP. Making
it a modifier makes more sense and makes documentation simpler.

~~ Discussion: Alternative Names

Naming the option based on something like "insert", like '''-insertpos''' or
making this an option to '''linsert'''; Since the spec selects variant 2, it
does not return the actual insertion position.

The name '''-nearest''' was proposed. Since the spec does not return the
nearest, it is not that good.

Also proposed was "'''-inexact''' (by analogy with switch -exact)."
"'''-inexact''' is good enough for the title of the TIP, so it should be good
enough for the option name. It may be tricky writing the documentation since
'''-sorted''' already implies '''-exact'''."

"Names that capture the meaning better are too verbose, but maybe they'll
suggest a good name ... -allowmissing -maybeabsent -absent -approximate -fuzzy
-insertionpointifmissing"

"The difference with the new option is that the search term need not be
present in the list. That distinction is what the option name should capture."

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|





|
|

|



|














|



|








|
|


|








|

|
|


|

|


|




|

|


|



|
|
|
|
<
|
>
|

|

|






|

|








|
|



|
|
|

|

|



|

|
|


|


|
|

|








|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163

# TIP 313: Inexact Searching in Sorted List

	Author:         Peter Spjuth <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        14-Feb-2008
	Post-History:   
	Keywords:       Tcl
	Tcl-Version:    8.6
-----

# Abstract

This TIP adds a new switch to **lsearch** to do a binary search to find the
insertion point in a sorted list.

# Rationale

Sometimes, it is necessary to find the location in a sorted list where a
particular new element could be inserted. Either for actual insertion or for
lookups to do interpolation or approximate search in data tables. Given that
the list is already sorted, it is obviously the case that the location should
be located through an O\(log N\) algorithm that takes advantage of this fact
\(binary searching is the most reliable method given that measuring the
"distance" between two strings is a complex and expensive operation in
itself\).

The usefulness of the feature is shown by a quick search. I found usages in
the core, in tcllib and in tklib. Given that the infrastructure for a binary
search is already in **lsearch**, this is a very cheap addition.

One question for the specification is exactly what index should be returned.
Below an increasing list is assumed, things are equivalent for a decreasing.

 1. First where element is greater than key.

 2. Last  where element is less than or equal to key.

 3. First where element is greater than or equal to key.

 4. Last  where element is less than key.

Here, 1 is the use case for a stable insertion sort.

In the core we can find **::tcl::clock::BSearch** which returns the index of
the greatest element in $list that is less than or equal to $key, i.e. type 2.
The same can be found in tklib's ::khim::BSearch.

In tcllib we can find **::struct::prioqueue::\_\_linsertsorted**, which would
use type 1.

Personally I have had use for both 2 and 3.

1 can trivialy be calculated from 2 and vice versa. Same for 3 and 4.

One key difference between 1/2 and 3/4 is that 1/2 return last among equals
while 3/4 returns first among equals. This means that it is easier to lay 3/4
over 1/2 by first doing an exact search. _i.e._ by doing both a -sorted and
a -bisect search you get all info needed, in log\(N\) time, to get either of
1/2/3/4.

Finally, I think it makes sense for **lsearch** to return an exact match if
there is one, leading to type 2 being specified in this TIP.

For a decreasing list, things are equivalent. The same relationships between
1/2/3/4 applies, so it is reasonable to select the same there.

I saw the word bisect used for this type of operation, but a better name is
probably possible if someone have a suggestion.

# Specification

An option **-bisect** is added to **lsearch**. This is a modifier to
**-sorted** and implies **-sorted** search mode.

The list to be searched thus must be sorted and how it is sorted is specified
just as for unmodified **-sorted**.

For an increasing list, the **-bisect** flag makes **lsearch** return the
greatest index where the element is less than or equal to the key.

For a decreasing list, the **-bisect** flag makes **lsearch** return the
greatest index where the element is greater than or equal to the key.

If the key is before the first element, or the list is empty, -1 is returned.

It is illegal to use **-bisect** with either **-all** or **-not**.

Note that **-inline** and **-start** are still valid, though perhaps not
very useful.

# Examples

A stable insertion sort:

	set dest {}
	foreach elem $src {
	    set i [lsearch -bisect -integer $dest]
	    set dest [linsert $dest [+ $i 1] $elem]

	}

# Reference Implementation

<http://sourceforge.net/support/tracker.php?aid=1894241>

# Further Use Cases

Some messages on news:comp.lang.tcl provide additional motivation for this
TIP:

From Kevin Kenny: <[email protected]>:

 > [...] When I've coded binary search like that, it's generally been as
   part of an interpolation or approximate search procedure. For instance,
   **::tcl::clock::BSearch** finds, among other things, the last change of
   time zone at or before a given time. The cubic spline procedure in tcllib
   uses BSearch to find the control point just to the left of the interpolated
   point. There are a great many cases where you want to look up the nearest
   neighbour without inserting anything if there is no exact match.

From Neil Madden: <[email protected]>:

 > Indeed. My own recent experience was in looking up annotations to display
   while playing back some 3D visualisation data \(through Togl\). A list of
   form \{timestamp annotation ts annot ...\} was used and the annotation should
   be displayed for any frame from that timestamp up until the next
   annotation. When the user can randomly seek to any position in the data it
   was necessary to find the nearest preceeding annotation. I hand-coded a
   binary search for this. This **lsearch** enhancement would have been
   ideal \(well, providing I massaged the data into a form suitable for use
   with **-index**, which I assume this TIP is compatible with\).

# Alternatives

Instead of making **-bisect** a modifier to **-sorted** it could be a
search mode in itself. This was the original specification in this TIP. Making
it a modifier makes more sense and makes documentation simpler.

## Discussion: Alternative Names

Naming the option based on something like "insert", like **-insertpos** or
making this an option to **linsert**; Since the spec selects variant 2, it
does not return the actual insertion position.

The name **-nearest** was proposed. Since the spec does not return the
nearest, it is not that good.

Also proposed was "**-inexact** \(by analogy with switch -exact\)."
"**-inexact** is good enough for the title of the TIP, so it should be good
enough for the option name. It may be tricky writing the documentation since
**-sorted** already implies **-exact**."

"Names that capture the meaning better are too verbose, but maybe they'll
suggest a good name ... -allowmissing -maybeabsent -absent -approximate -fuzzy
-insertionpointifmissing"

"The difference with the new option is that the search term need not be
present in the list. That distinction is what the option name should capture."

# Copyright

This document has been placed in the public domain.

Name change from tip/314.tip to tip/314.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
136
137
138
139
140
141
142
143
144
145
146

147
148
149
150
151
152

153
154

155
156

157
158
159
160
161
162

163
164
165
166

167
168

169
170

171
172

173
174
175
176
177

178
179
180
181
182
183
184
185

186
187

188
189

190
191

192
193
194
195

196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

230
231
232
233

234
235
236
237
238
239

240
241
242
243
244
245

246
247
248

249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311

TIP:            314
Title:          Ensembles with Parameters
Version:        $Revision: 1.5 $
Author:         Lars Hellstr�m <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        26-Feb-2008
Post-History:   
Tcl-Version:    8.6


~ Abstract

This TIP proposes that '''namespace ensemble''' commands are generalised so
that they may have arguments before the subcommand name.

~ Rationale

The introduction of '''{*}''' for argument expansion has made it much more
convenient to use command prefixes for callbacks. One particular idiom that
command prefixes provide for is "ClientData" arguments, i.e., the same command
is used for several different callbacks, as exactly what it does or acts on is
controlled by the extra argument(s). Of course, both command prefixes and the
"ClientData" idiom are already the rule for callbacks from the core, but
'''{*}''' will most likely make them more common also for callbacks from Tcl
code.

A disadvantage of this idiom is however that it currently cannot be used if
the base command of a command prefix is to be an ensemble, as the subcommand
name in an ensemble must follow immediately after the base command name.
Callbacks from the core which take a subcommand are rare - the only obvious
example is the reflected channel callback command - but in higher level code
such callbacks are fairly common. Using namespace ensembles for implementing
such callbacks makes the code much more modular than using a procedure would.
Hence it is desirable to remove the restriction that the subcommand name of a
namespace ensemble must appear as the first argument, and instead allow there
to be some number of "parameter" arguments between the base command name and
the subcommand name.

One application of parameter arguments is to use namespace ensembles as a
white-box OO system, where the parameters hold the state of the object. More
explicitly, each object instance in such a system would be a command prefix
consisting of (i) one ensemble command that handles the method dispatch and
(ii) the necessary number of parameter arguments, whose values make up the
state of the object. Being values, such objects are necessarily immutable; it
is however possible to define methods which return a mutated form of the
object. For light-weight objects, this system has the advantage that instances
do not have to be destroyed explicitly, but of course that also means that
they cannot own any resources that require explicit destruction.

Some may argue that ensemble parameters are not necessary because any client
data can be embedded into the prefixes of the '''-map''' dictionary of the
ensemble. This is however only true to the extent that multiword command
prefixes themselves are unnecessary; it is similarly possible to embed extra
arguments into an '''interp alias'''. Both of these "solutions" have the
disadvantage that they create an auxiliary command which one must explicitly
dispose of or leak memory, whereas all memory used by a command prefix is
automatically released when the last reference to it goes away.

~ Specification

A new ensemble option '''-parameters''' is introduced, which takes a list of
parameter names as value and defaults to the empty list. Two C functions for
setting and getting the value of this option are added to the public stubs
table:

 > int '''Tcl_SetEnsembleParameterList'''(Tcl_Interp *''interp'', Tcl_Command
   ''token'', Tcl_Obj *''paramList'')

 > int '''Tcl_GetEnsembleParameterList'''(Tcl_Interp *''interp'', Tcl_Command
   ''token'', Tcl_Obj **''paramListPtr'')

(This is the same pattern as for the other ensemble options, e.g. for the
'''-subcommands''' option's implementation.)

The general structure of a namespace ensemble command call will have the form:

 > ''baseCmd'' {*}''parameterArgs'' ''subCmd'' {*}''otherArgs''

where the number of arguments between the base command and the subcommand is
exactly the same as the number of elements in the value of the
'''-parameters''' option. It is an error to call the ''baseCmd'' with fewer
arguments than the number of parameters plus one. If ''cmdPrefix'' is the
command prefix to which the ensemble ''baseCmd'' maps the ''subCmd'', then the
above call gets translated into

 > {*}''cmdPrefix'' {*}''parameterArgs'' {*}''otherArgs''

~ Examples

An ensemble for arithmetic in integer-modulo-''n'' rings can be implemented as
follows:

| namespace eval intmod {
|     proc + {n args} {expr {[::tcl::mathop::+ {*}$args] % $n}}
|     proc - {n args} {expr {[::tcl::mathop::- {*}$args] % $n}}
|     proc * {n args} {expr {[::tcl::mathop::* {*}$args] % $n}}
|     proc / {n a b} {
|         set c $n
|         set r 0
|         set s 1
|         while {$b} {
|             set q [expr {$c / $b}]
|             set b [expr {$c - $q*[set c $b]}]
|             set s [expr {$r - $q*[set r $s]}]
|         }

|         if {$a % $c == 0} then {
|             return [expr {$r * $a / $c % $n}]
|         } else {
|             return -code error "No such quotient"
|         }
|     }


|     proc 0 {n} {return 0}
|     proc 1 {n} {return 1}
|     namespace ensemble create -parameters n -subcommands {+ - * / 0 1}
|     # That [namespace export] takes patterns as arguments starts
|     # feeling somewhat corny when * is a common command names.
| }


Some example results:

| % intmod 7 + 4 4
| 1

| % intmod 7 - 1
| 6

| % intmod 7 * 3 5
| 1

| % intmod 7 / 3 2
| 5

| % intmod 32003 / 3 2
| 16003
| % intmod 32768 / 3 2
| No such quotient
| % intmod
| wrong # args: should be "intmod n subcommand ?argument ...?"

An ensemble for matrix arithmetic over some ring can be implemented as
follows:

| namespace eval matrix {
|     proc + {ring A B} {
|         if {[llength $A] != [llength $B] ||
|             [llength [lindex $A 0]] != [llength [lindex $B 0]]} then {
|             return -code error -errorcode {ARITH DOMAIN}
|               "Matrix shapes do not match"
|         }

|         set res {}
|         foreach a_row $A b_row $B {
|             set r_row {}
|             foreach a $a_row b $b_row {
|                 lappend r_row [{*}$ring + $a $b]
|             }

|             lappend res $r_row
|         }

|         return $res
|     }

|     proc - {ring A B} {
|         if {[llength $A] != [llength $B] ||
|             [llength [lindex $A 0]] != [llength [lindex $B 0]]} then {
|             return -code error -errorcode {ARITH DOMAIN}
|               "Matrix shapes do not match"
|         }

|         set res {}
|         foreach a_row $A b_row $B {
|             set r_row {}
|             foreach a $a_row b $b_row {

|                 lappend r_row [{*}$ring - $a $b]
|             }

|             lappend res $r_row
|         }

|         return $res
|     }

|     proc * {ring A B} {
|         if {[llength [lindex $A 0]] != [llength $B]} then {
|             return -code error -errorcode {ARITH DOMAIN}
|               "Matrix shapes do not match"
|         }

|         set res {}
|         foreach a_row $A {
|             set r_row {}
|             foreach a $a_row b_row $B {
|                 set r [{*}$ring 0]
|                 foreach b $b_row {
|                     set r [{*}$ring + $r [{*}$ring * $a $b]]
|                 }

|                 lappend r_row $r
|             }

|             lappend res $r_row
|         }

|         return $res
|     }

|     # ...
|     namespace export *
|     namespace ensemble create -parameters ringCmdPrefix
| }


Some more example results:

| % set A {{1 2} {3 4}}
| % matrix {intmod 7} + $A $A
| {2 4} {6 1}
| % set B {{0 2} {1 3}}
| % matrix {intmod 100} * $A $B
| {2 8} {6 16}
| % matrix {intmod 5} * $A $B
| {2 3} {1 1}
| % matrix {intmod 5} - $A $B
| {1 0} {2 1}
| % matrix
| wrong # args: should be "matrix ringCmdPrefix subcommand ?argument ...?"

In the same way, one can define a '''polynomial''' ensemble for arithmetic
with polynomials over some ring. Then one can immediately start doing
calculations with e.g. matrices whose coefficients are polynomials over
integers modulo 2, simply by using the command prefix

| matrix {polynomial {intmod 2}}

Composing constructions this way is a surprisingly quick way of implementing
rather complex mathematical structures!

A trivial mutable object class can be implemented as follows:

| namespace eval mutable_ns {
|     proc get {value} {return $value}
|     proc set {value newvalue} {list [namespace current] $newvalue}
|     namespace export get set
|     namespace ensemble create -parameters value
| }

| proc mutable {initval} {
|     list [namespace which -command mutable_ns] $initval
| }


Some example results:

| % set a [mutable 0]
| ::mutable_ns 0
| % {*}$a get
| 0

| % {*}$a foo
| unknown or ambiguous subcommand "foo": must be get, or set
| % set b [{*}$a set 3] ; # Creates a modified copy
| ::mutable_ns 3
| % {*}$b get
| 3

| % {*}$a get
| 0


~ Rejected Alternatives

Most of the time, only the number of parameters is relevant; their names are
merely used when throwing a "wrong # args" error. Hence an alternative would
be to have taken that number as the value of the '''-parameters''' option, but
requesting a list of names encourages the programmer to provide more
information available for introspection and should help to produce better
error messages.

An alternative principle for forming the mapped-to command could be that the
parameters should remain in the same position in the command. This would mean
that rather than mapping

 > ''baseCmd'' {*}''parameterArgs'' ''subCmd'' {*}''otherArgs''

to

 > {*}''cmdPrefix'' {*}''parameterArgs'' {*}''otherArgs''

one would map it to

 > ['''lindex''' ''cmdPrefix'' 0] {*}''parameterArgs'' {*}['''lrange'''
   ''cmdPrefix'' 1 end] {*}''otherArgs''

but this is slightly more complicated to do, and it seems less useful. For
example, this would prevent using an '''apply''' ''lambda'' form of
''cmdPrefix'' in an ensemble with parameters.

~ Future Extensions

In analogy with the '''-unknown''' handler for an ensemble, it might be useful
to have a handler for ensembles being called with ''too few'' arguments; it is
not uncommon for ensemble-like commands that one in certain cases can omit the
subcommand name. Possibly this functionality could even be integrated into the
'''-unknown''' handler.  There is however nothing in that which is directly
related to the issue of ensembles having parameters, other than that
parameters make it possible to call an ensemble command with way too few
arguments instead of just one too few.

~ Reference Implementation

A reference implementation is available as SF Tcl patch #1901783.
[https://sourceforge.net/support/tracker.php?aid=1901783]

~~ Notes

One detail in this implementation which might require further consideration
because it results in script-level-visible behaviour is the matter of how the
list of parameter names is turned into error messages. Currently that is done
by (effectively) '''join'''ing the list elements, but a possible alternative
is to use the string representation of the list. Joining seems to give better
control to the user of what gets put in the message, but the results are
probably equivalent for all alphanumeric choices of parameter names.

Deep down, this touches upon the matter of how the user may distinguish actual
argument values from formal argument names in syntax error messages. As far as
I can tell, there currently isn't a way of doing that, but perhaps there
should be. In want of clear rules for this, the reference implementation
doesn't seem to fare any worse than what is already in the core.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|


|

|



|

|

















|
|







|


|




|

|




|
|

|
|

|
|



|



|
|
|


|

|

|


|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
<
>
>
|
|
|
|
|
<
>



|
<
>
|
<
>
|
<
>
|
<
>
|
|
|
|
|
|




|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
<
>
|
<
>
|
|
|
|
|
<
>
|
|
|
|
>
<
<
>
|
<
>
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
<
>
|
<
>
|
<
>
|
|
|
<
>



|
|
|
|
|
|
|
|
|
|
|
|

|




|






|
|
|
|
|
<
>
|
|
<
|
>


|
|
|
<
>
|
|
|
|
|
<
>
|
<
|
>
|


|
|








|



|



|
|


|
|

|

|
|


|




|

|
|

|




|










|


>

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
136
137
138
139
140
141
142
143
144

145
146
147
148
149
150

151
152

153
154

155
156
157
158
159
160

161
162
163
164
165
166


167
168

169
170

171
172
173
174
175

176
177
178
179
180
181
182
183

184
185

186
187

188
189

190
191
192
193

194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

228
229
230

231
232
233
234
235
236
237

238
239
240
241
242
243

244
245

246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311

# TIP 314: Ensembles with Parameters

	Author:         Lars Hellström <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        26-Feb-2008
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes that **namespace ensemble** commands are generalised so
that they may have arguments before the subcommand name.

# Rationale

The introduction of **\{\*\}** for argument expansion has made it much more
convenient to use command prefixes for callbacks. One particular idiom that
command prefixes provide for is "ClientData" arguments, i.e., the same command
is used for several different callbacks, as exactly what it does or acts on is
controlled by the extra argument\(s\). Of course, both command prefixes and the
"ClientData" idiom are already the rule for callbacks from the core, but
**\{\*\}** will most likely make them more common also for callbacks from Tcl
code.

A disadvantage of this idiom is however that it currently cannot be used if
the base command of a command prefix is to be an ensemble, as the subcommand
name in an ensemble must follow immediately after the base command name.
Callbacks from the core which take a subcommand are rare - the only obvious
example is the reflected channel callback command - but in higher level code
such callbacks are fairly common. Using namespace ensembles for implementing
such callbacks makes the code much more modular than using a procedure would.
Hence it is desirable to remove the restriction that the subcommand name of a
namespace ensemble must appear as the first argument, and instead allow there
to be some number of "parameter" arguments between the base command name and
the subcommand name.

One application of parameter arguments is to use namespace ensembles as a
white-box OO system, where the parameters hold the state of the object. More
explicitly, each object instance in such a system would be a command prefix
consisting of \(i\) one ensemble command that handles the method dispatch and
\(ii\) the necessary number of parameter arguments, whose values make up the
state of the object. Being values, such objects are necessarily immutable; it
is however possible to define methods which return a mutated form of the
object. For light-weight objects, this system has the advantage that instances
do not have to be destroyed explicitly, but of course that also means that
they cannot own any resources that require explicit destruction.

Some may argue that ensemble parameters are not necessary because any client
data can be embedded into the prefixes of the **-map** dictionary of the
ensemble. This is however only true to the extent that multiword command
prefixes themselves are unnecessary; it is similarly possible to embed extra
arguments into an **interp alias**. Both of these "solutions" have the
disadvantage that they create an auxiliary command which one must explicitly
dispose of or leak memory, whereas all memory used by a command prefix is
automatically released when the last reference to it goes away.

# Specification

A new ensemble option **-parameters** is introduced, which takes a list of
parameter names as value and defaults to the empty list. Two C functions for
setting and getting the value of this option are added to the public stubs
table:

 > int **Tcl\_SetEnsembleParameterList**\(Tcl\_Interp \*_interp_, Tcl\_Command
   _token_, Tcl\_Obj \*_paramList_\)

 > int **Tcl\_GetEnsembleParameterList**\(Tcl\_Interp \*_interp_, Tcl\_Command
   _token_, Tcl\_Obj \*\*_paramListPtr_\)

\(This is the same pattern as for the other ensemble options, e.g. for the
**-subcommands** option's implementation.\)

The general structure of a namespace ensemble command call will have the form:

 > _baseCmd_ \{\*\}_parameterArgs_ _subCmd_ \{\*\}_otherArgs_

where the number of arguments between the base command and the subcommand is
exactly the same as the number of elements in the value of the
**-parameters** option. It is an error to call the _baseCmd_ with fewer
arguments than the number of parameters plus one. If _cmdPrefix_ is the
command prefix to which the ensemble _baseCmd_ maps the _subCmd_, then the
above call gets translated into

 > \{\*\}_cmdPrefix_ \{\*\}_parameterArgs_ \{\*\}_otherArgs_

# Examples

An ensemble for arithmetic in integer-modulo-_n_ rings can be implemented as
follows:

	 namespace eval intmod {
	     proc + {n args} {expr {[::tcl::mathop::+ {*}$args] % $n}}
	     proc - {n args} {expr {[::tcl::mathop::- {*}$args] % $n}}
	     proc * {n args} {expr {[::tcl::mathop::* {*}$args] % $n}}
	     proc / {n a b} {
	         set c $n
	         set r 0
	         set s 1
	         while {$b} {
	             set q [expr {$c / $b}]
	             set b [expr {$c - $q*[set c $b]}]
	             set s [expr {$r - $q*[set r $s]}]

	         }
	         if {$a % $c == 0} then {
	             return [expr {$r * $a / $c % $n}]
	         } else {
	             return -code error "No such quotient"


	         }
	     }
	     proc 0 {n} {return 0}
	     proc 1 {n} {return 1}
	     namespace ensemble create -parameters n -subcommands {+ - * / 0 1}
	     # That [namespace export] takes patterns as arguments starts
	     # feeling somewhat corny when * is a common command names.

	 }

Some example results:

	 % intmod 7 + 4 4

	 1
	 % intmod 7 - 1

	 6
	 % intmod 7 * 3 5

	 1
	 % intmod 7 / 3 2

	 5
	 % intmod 32003 / 3 2
	 16003
	 % intmod 32768 / 3 2
	 No such quotient
	 % intmod
	 wrong # args: should be "intmod n subcommand ?argument ...?"

An ensemble for matrix arithmetic over some ring can be implemented as
follows:

	 namespace eval matrix {
	     proc + {ring A B} {
	         if {[llength $A] != [llength $B] ||
	             [llength [lindex $A 0]] != [llength [lindex $B 0]]} then {
	             return -code error -errorcode {ARITH DOMAIN}
	               "Matrix shapes do not match"

	         }
	         set res {}
	         foreach a_row $A b_row $B {
	             set r_row {}
	             foreach a $a_row b $b_row {
	                 lappend r_row [{*}$ring + $a $b]

	             }
	             lappend res $r_row

	         }
	         return $res

	     }
	     proc - {ring A B} {
	         if {[llength $A] != [llength $B] ||
	             [llength [lindex $A 0]] != [llength [lindex $B 0]]} then {
	             return -code error -errorcode {ARITH DOMAIN}
	               "Matrix shapes do not match"

	         }
	         set res {}
	         foreach a_row $A b_row $B {
	             set r_row {}
	             foreach a $a_row b $b_row {
	                 lappend r_row [{*}$ring - $a $b]


	             }
	             lappend res $r_row

	         }
	         return $res

	     }
	     proc * {ring A B} {
	         if {[llength [lindex $A 0]] != [llength $B]} then {
	             return -code error -errorcode {ARITH DOMAIN}
	               "Matrix shapes do not match"

	         }
	         set res {}
	         foreach a_row $A {
	             set r_row {}
	             foreach a $a_row b_row $B {
	                 set r [{*}$ring 0]
	                 foreach b $b_row {
	                     set r [{*}$ring + $r [{*}$ring * $a $b]]

	                 }
	                 lappend r_row $r

	             }
	             lappend res $r_row

	         }
	         return $res

	     }
	     # ...
	     namespace export *
	     namespace ensemble create -parameters ringCmdPrefix

	 }

Some more example results:

	 % set A {{1 2} {3 4}}
	 % matrix {intmod 7} + $A $A
	 {2 4} {6 1}
	 % set B {{0 2} {1 3}}
	 % matrix {intmod 100} * $A $B
	 {2 8} {6 16}
	 % matrix {intmod 5} * $A $B
	 {2 3} {1 1}
	 % matrix {intmod 5} - $A $B
	 {1 0} {2 1}
	 % matrix
	 wrong # args: should be "matrix ringCmdPrefix subcommand ?argument ...?"

In the same way, one can define a **polynomial** ensemble for arithmetic
with polynomials over some ring. Then one can immediately start doing
calculations with e.g. matrices whose coefficients are polynomials over
integers modulo 2, simply by using the command prefix

	 matrix {polynomial {intmod 2}}

Composing constructions this way is a surprisingly quick way of implementing
rather complex mathematical structures!

A trivial mutable object class can be implemented as follows:

	 namespace eval mutable_ns {
	     proc get {value} {return $value}
	     proc set {value newvalue} {list [namespace current] $newvalue}
	     namespace export get set
	     namespace ensemble create -parameters value

	 }
	 proc mutable {initval} {
	     list [namespace which -command mutable_ns] $initval

	 }

Some example results:

	 % set a [mutable 0]
	 ::mutable_ns 0
	 % {*}$a get

	 0
	 % {*}$a foo
	 unknown or ambiguous subcommand "foo": must be get, or set
	 % set b [{*}$a set 3] ; # Creates a modified copy
	 ::mutable_ns 3
	 % {*}$b get

	 3
	 % {*}$a get

	 0

# Rejected Alternatives

Most of the time, only the number of parameters is relevant; their names are
merely used when throwing a "wrong \# args" error. Hence an alternative would
be to have taken that number as the value of the **-parameters** option, but
requesting a list of names encourages the programmer to provide more
information available for introspection and should help to produce better
error messages.

An alternative principle for forming the mapped-to command could be that the
parameters should remain in the same position in the command. This would mean
that rather than mapping

 > _baseCmd_ \{\*\}_parameterArgs_ _subCmd_ \{\*\}_otherArgs_

to

 > \{\*\}_cmdPrefix_ \{\*\}_parameterArgs_ \{\*\}_otherArgs_

one would map it to

 > [**lindex** _cmdPrefix_ 0] \{\*\}_parameterArgs_ \{\*\}[**lrange**
   _cmdPrefix_ 1 end] \{\*\}_otherArgs_

but this is slightly more complicated to do, and it seems less useful. For
example, this would prevent using an **apply** _lambda_ form of
_cmdPrefix_ in an ensemble with parameters.

# Future Extensions

In analogy with the **-unknown** handler for an ensemble, it might be useful
to have a handler for ensembles being called with _too few_ arguments; it is
not uncommon for ensemble-like commands that one in certain cases can omit the
subcommand name. Possibly this functionality could even be integrated into the
**-unknown** handler.  There is however nothing in that which is directly
related to the issue of ensembles having parameters, other than that
parameters make it possible to call an ensemble command with way too few
arguments instead of just one too few.

# Reference Implementation

A reference implementation is available as SF Tcl patch \#1901783.
<https://sourceforge.net/support/tracker.php?aid=1901783> 

## Notes

One detail in this implementation which might require further consideration
because it results in script-level-visible behaviour is the matter of how the
list of parameter names is turned into error messages. Currently that is done
by \(effectively\) **join**ing the list elements, but a possible alternative
is to use the string representation of the list. Joining seems to give better
control to the user of what gets put in the message, but the results are
probably equivalent for all alphanumeric choices of parameter names.

Deep down, this touches upon the matter of how the user may distinguish actual
argument values from formal argument names in syntax error messages. As far as
I can tell, there currently isn't a way of doing that, but perhaps there
should be. In want of clear rules for this, the reference implementation
doesn't seem to fare any worse than what is already in the core.

# Copyright

This document has been placed in the public domain.

Name change from tip/315.tip to tip/315.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

TIP:		315
Title:		Add pathSeparator to tcl_platform Array
Version:	$Revision: 1.5 $
Author:		Hai Vu <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Created:	04-Apr-2008
Post-History:	


~ Abstract

This TIP proposes a mechanism for determining the platform's path separator.
The path separator is currently ":" in Unix and ";" in DOS/Windows.

~ Rationale

Under Windows, the PATH environment variable consists of many paths, separated
by semicolons (";"). Meanwhile, Unix uses colon to separate the paths (":").
Scripts that need to work on both platforms while parsing platform-specific
PATH-like environment variables (PATH is just the most common of these)
currently need to contain the mapping from platform-type to separator, but
this is not especially flexible and some script authors are also inclined to
forget about this particular difference.

Thus, to aid portability, this TIP proposes adding an element to the
'''tcl_platform''' array, '''pathSeparator''', which describes the path
separator for the current platform.

~ Example Usage

The following example prints each component of the PATH environment on a
separate line:

|set pathList [split $env(PATH) $tcl_platform(pathSeparator)]
|foreach path $pathList {
|    puts $pathList
|}


Alternatively:

|puts [string map [list $tcl_platform(pathSeparator) \n] $env(PATH)]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|




|


|

|





|


|




|
|
|
<
>



|

|


>

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

# TIP 315: Add pathSeparator to tcl_platform Array

	Author:		Hai Vu <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Done
	Created:	04-Apr-2008
	Post-History:	
-----

# Abstract

This TIP proposes a mechanism for determining the platform's path separator.
The path separator is currently ":" in Unix and ";" in DOS/Windows.

# Rationale

Under Windows, the PATH environment variable consists of many paths, separated
by semicolons \(";"\). Meanwhile, Unix uses colon to separate the paths \(":"\).
Scripts that need to work on both platforms while parsing platform-specific
PATH-like environment variables \(PATH is just the most common of these\)
currently need to contain the mapping from platform-type to separator, but
this is not especially flexible and some script authors are also inclined to
forget about this particular difference.

Thus, to aid portability, this TIP proposes adding an element to the
**tcl\_platform** array, **pathSeparator**, which describes the path
separator for the current platform.

# Example Usage

The following example prints each component of the PATH environment on a
separate line:

	set pathList [split $env(PATH) $tcl_platform(pathSeparator)]
	foreach path $pathList {
	    puts $pathList

	}

Alternatively:

	puts [string map [list $tcl_platform(pathSeparator) \n] $env(PATH)]

# Copyright

This document has been placed in the public domain.

Name change from tip/316.tip to tip/316.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

TIP:		316
Title:		Portable Access Functions for Stat Buffers
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Post-History:	
Version:	$Revision: 1.4 $
Author:		Donal K. Fellows <[email protected]>
Created:	02-May-2008


~ Abstract

Tcl exposes the definition of the ''struct stat'' type to users of its C API,
but this can vary between builds. This TIP proposes a set of portable
functions for reading (portable) fields out of those structures so that code
does not need to match the API version when reading the fields (the most
common case by far).

~ Rationale

The ''struct stat'' type used by Tcl can be one of many different types
depending on compile-time options (as a consequence of 64-bit filesystem
support). Tcl conceals these details by wrapping the type as a ''Tcl_StatBuf''
and providing a way to allocate these independently of compiler configuration.
However, there is no way to access the contents of the field without binding
to a particular type i.e. particular compile time configuration of Tcl (and
not necessarily the extension code using the API!)  This TIP proposes a set of
simple access functions to conceal these details and enable the portable
read-only use of the ''Tcl_StatBuf'' type.

~ Proposed Change

This TIP proposes that the following functions will be defined. Each will take
a pointer to a ''Tcl_StatBuf'' as its only argument, and will return the
contents of the field indicated below.

 Tcl_GetFSDeviceFromStat: Returns the ''st_dev'' field as an unsigned integer.

 Tcl_GetFSInodeFromStat: Returns the ''st_ino'' field as an unsigned integer.

 Tcl_GetModeFromStat: Returns the ''st_mode'' field as an unsigned integer.

 Tcl_GetLinkCountFromStat: Returns the ''st_nlink'' field as an integer.

 Tcl_GetUserIdFromStat: Returns the ''st_uid'' field as an integer.

 Tcl_GetGroupIdFromStat: Returns the ''st_gid'' field as an integer.

 Tcl_GetDeviceTypeFromStat: Returns the ''st_rdev'' field as an integer.

 Tcl_GetAccessTimeFromStat: Returns the ''st_atime'' field as a wide integer.

 Tcl_GetModificationTimeFromStat: Returns the ''st_mtime'' field as a wide
 integer.

 Tcl_GetChangeTimeFromStat: Returns the ''st_ctime'' field as a wide integer.

 Tcl_GetSizeFromStat: Returns the ''st_size'' field as an unsigned wide
 integer.

 Tcl_GetBlocksFromStat: Returns the ''st_blocks'' field as an unsigned wide
 integer.

 Tcl_GetBlockSizeFromStat: Returns the ''st_blksize'' field as an unsigned
 integer.

Some platforms may support other fields; these are not universal and are hence
not portable.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
>

|

|

|
|
|

|

|
|
|


|
|

|

|


|


|

|

|

|

|

|

|

|

|


|

|


|


|





|


>

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

# TIP 316: Portable Access Functions for Stat Buffers
	State:		Final
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Done
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	02-May-2008
-----

# Abstract

Tcl exposes the definition of the _struct stat_ type to users of its C API,
but this can vary between builds. This TIP proposes a set of portable
functions for reading \(portable\) fields out of those structures so that code
does not need to match the API version when reading the fields \(the most
common case by far\).

# Rationale

The _struct stat_ type used by Tcl can be one of many different types
depending on compile-time options \(as a consequence of 64-bit filesystem
support\). Tcl conceals these details by wrapping the type as a _Tcl\_StatBuf_
and providing a way to allocate these independently of compiler configuration.
However, there is no way to access the contents of the field without binding
to a particular type i.e. particular compile time configuration of Tcl \(and
not necessarily the extension code using the API!\)  This TIP proposes a set of
simple access functions to conceal these details and enable the portable
read-only use of the _Tcl\_StatBuf_ type.

# Proposed Change

This TIP proposes that the following functions will be defined. Each will take
a pointer to a _Tcl\_StatBuf_ as its only argument, and will return the
contents of the field indicated below.

 Tcl\_GetFSDeviceFromStat: Returns the _st\_dev_ field as an unsigned integer.

 Tcl\_GetFSInodeFromStat: Returns the _st\_ino_ field as an unsigned integer.

 Tcl\_GetModeFromStat: Returns the _st\_mode_ field as an unsigned integer.

 Tcl\_GetLinkCountFromStat: Returns the _st\_nlink_ field as an integer.

 Tcl\_GetUserIdFromStat: Returns the _st\_uid_ field as an integer.

 Tcl\_GetGroupIdFromStat: Returns the _st\_gid_ field as an integer.

 Tcl\_GetDeviceTypeFromStat: Returns the _st\_rdev_ field as an integer.

 Tcl\_GetAccessTimeFromStat: Returns the _st\_atime_ field as a wide integer.

 Tcl\_GetModificationTimeFromStat: Returns the _st\_mtime_ field as a wide
 integer.

 Tcl\_GetChangeTimeFromStat: Returns the _st\_ctime_ field as a wide integer.

 Tcl\_GetSizeFromStat: Returns the _st\_size_ field as an unsigned wide
 integer.

 Tcl\_GetBlocksFromStat: Returns the _st\_blocks_ field as an unsigned wide
 integer.

 Tcl\_GetBlockSizeFromStat: Returns the _st\_blksize_ field as an unsigned
 integer.

Some platforms may support other fields; these are not universal and are hence
not portable.

# Copyright

This document has been placed in the public domain.

Name change from tip/317.tip to tip/317.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

TIP:            317
Title:          Extend binary Ensemble with Binary Encodings
Version:        $Revision: 1.5 $
Author:         Pat Thoyts <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        03-May-2008
Post-History:   
Keywords:       base64,uuencode,hex,transfer encoding
Tcl-Version:    8.6


~ Abstract

This TIP extends the '''binary''' command with implementations in C of
commonly used binary encodings. In particular the ''base64'' encoding is
implemented but the Tcl ensemble scheme [112] can be used to provide simple
extension of the implemented formats.

~ Specification

The '''binary''' command ensemble will be extended to include two new
subcommands, '''encode''' and '''decode'''. Each subcommand will accept two
arguments. The first is the name of an encoding format and the second is the
data to be operated upon.

 > '''binary encode''' ''format ?-option value ...? data''

 > '''binary decode''' ''format ?-option value ...? data''

In keeping with the nature of the '''binary''' command, the ''data'' argument
is treated as a byte array. This means that users should ensure their data is
already in a suitable character encoding before applying a binary encoding.
This is already a requirement for other implementations of this functionality
(e.g. the tcllib and Trf packages).

The initial set of binary encodings consists of '''base64''', '''uuencode'''
and '''hex'''. The implementation of the '''encode''' and '''decode'''
subcommands will make use of the Tcl ensemble command mechanism ([112]) and
will therefore be extensible via the ensemble mechanism.

~ Reference Implementation

A patch against the Tcl HEAD (8.6) is located at
http://sf.net/tracker/?func=detail&aid=1956530&group_id=10894&atid=310894

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|
|


|

|
|



|

|

|



|

|
|
|


|

|
|

|


>

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

# TIP 317: Extend binary Ensemble with Binary Encodings

	Author:         Pat Thoyts <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        03-May-2008
	Post-History:   
	Keywords:       base64,uuencode,hex,transfer encoding
	Tcl-Version:    8.6
-----

# Abstract

This TIP extends the **binary** command with implementations in C of
commonly used binary encodings. In particular the _base64_ encoding is
implemented but the Tcl ensemble scheme [[112]](112.md) can be used to provide simple
extension of the implemented formats.

# Specification

The **binary** command ensemble will be extended to include two new
subcommands, **encode** and **decode**. Each subcommand will accept two
arguments. The first is the name of an encoding format and the second is the
data to be operated upon.

 > **binary encode** _format ?-option value ...? data_

 > **binary decode** _format ?-option value ...? data_

In keeping with the nature of the **binary** command, the _data_ argument
is treated as a byte array. This means that users should ensure their data is
already in a suitable character encoding before applying a binary encoding.
This is already a requirement for other implementations of this functionality
\(e.g. the tcllib and Trf packages\).

The initial set of binary encodings consists of **base64**, **uuencode**
and **hex**. The implementation of the **encode** and **decode**
subcommands will make use of the Tcl ensemble command mechanism \([[112]](112.md)\) and
will therefore be extensible via the ensemble mechanism.

# Reference Implementation

A patch against the Tcl HEAD \(8.6\) is located at
<http://sf.net/tracker/?func=detail&aid=1956530&group\_id=10894&atid=310894>

# Copyright

This document has been placed in the public domain.

Name change from tip/318.tip to tip/318.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

TIP:		318
Title:		Extend Default Whitespace in 'string trim' Beyond ASCII
Version:	$Revision: 1.5 $
Author:		Bill Poser <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Created:	13-May-2008
Post-History:	


~Abstract

This TIP extends the '''string trim''', '''string trimleft''', and '''string
trimright''' subcommands to function properly with non-roman writing systems
by adding non-ASCII space characters to the default list of characters to be
trimmed.

~Rationale

By default '''string trim''' and its single-sided variants remove ASCII
whitespace characters. Some writing systems use other whitespace characters.
Adding these characters to the default list will extend the
Unicode-friendliness of Tcl.

The characters proposed to be added are:

|U+1361  ETHIOPIC WORDSPACE       
|U+1680  OGHAM SPACE MARK
|U+3000  IDEOGRAPHIC SPACE

~Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|



|

|






|
|
|

|


>

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

# TIP 318: Extend Default Whitespace in 'string trim' Beyond ASCII

	Author:		Bill Poser <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Done
	Created:	13-May-2008
	Post-History:	
-----

# Abstract

This TIP extends the **string trim**, **string trimleft**, and **string
trimright** subcommands to function properly with non-roman writing systems
by adding non-ASCII space characters to the default list of characters to be
trimmed.

# Rationale

By default **string trim** and its single-sided variants remove ASCII
whitespace characters. Some writing systems use other whitespace characters.
Adding these characters to the default list will extend the
Unicode-friendliness of Tcl.

The characters proposed to be added are:

	U+1361  ETHIOPIC WORDSPACE       
	U+1680  OGHAM SPACE MARK
	U+3000  IDEOGRAPHIC SPACE

# Copyright

This document has been placed in the public domain.

Name change from tip/319.tip to tip/319.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

TIP:		319
Title:		Implement Backwards Compatibility for ttk Themed Widgets in tk Widgets
Version:	$Revision: 1.4 $
Author:		Eric Taylor <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Created:	04-Jun-2008
Post-History:	


~ Abstract

This TIP calls for the implementation of backward compatibility between ttk
themed widgets and conventional tk widgets. It does this by describing
configuration options that specify how to deal with unsupported options
(error, ignore, or call supplied callbacks) where full compatibility is not
feasible. Configuration should be both global (all widgets) and specific (by
class or individual widget).

~ Rationale

Tk 8.5 now includes a parallel set of widgets, created through calls to
similar widget constructors, but invoked using the namespace '''ttk::'''
prepended to the name of an existing widget. For example, '''ttk::button'''
creates a themed button, while the unqualified '''button''' creates standard
Tk button widgets.

One of the stated purposes of these new widgets is to bring Tk up to the
standards now expected for attractive looking GUI programs. The '''ttk'''
package does this quite well, but only for new programs. Imagine the leverage
we would have if we could upgrade older programs (easily and automatically) to
use these widgets.  While one can use an editor and add in the '''ttk::''' to
each widget creation call (which then begs the question of why we can't have
this done automatically with a simple configuration procedure) one is often
stuck when trying to implement the same behavior since many Tk options which
are currently unsupported in ttk.

In addition, there are packages, such as visual tcl, which write conventional
tk code. These programs cannot easily be converted to use the new widgets, but
still need to be maintained using the vtcl program.

This TIP proposes that all current Tk widget options be supported where
feasible and that the following command be fully implemented to permit older
Tk-oriented programs run unaltered using the themed set of widgets.

|namespace import -force ttk::*

Since the ttk widgets don't have all the same options, there would need to be
some compatibility code that could simulate the old behavior. For example, in
'''button''', there is no longer a '''-background''' color option, nor is
there '''-padx''' and '''-pady'''. Sometimes these missing options can be
implemented, for example, using '''-padding''' would let one implement partial
behavior. While it would be preferable to implement these options directly, an
alternative would be to select a compatability handling mode of ignore, error,
or callback to aid the developer in implementing missing options.

~ Proposal

To that purpose, I propose some kind of configuration option, for example:

 > '''ttk::compatibility'''
   ?'''-onerror''' [['''ignore'''|'''error'''|'''callback''']]?
   ?'''-callback''' ''proc''?
   ?'''-class''' [[''widget-class''|'''all''']]?

When the callback procedure is invoked, it should be passed additional
parameters which would completely identify,

 1. The widget (e.g. '''.frame.button''')

 2. The option that is not directly supported (e.g. '''-pady''')

 3. The value specified for that option (the argument following the
    ''-option'')

 4. Anything else I've forgotten

The above should also be configured globally (all widgets) or on a widget by
widget basis. For individual widgets, there should be a configuration option
for the above.

I would think that most of this should be implementable with pure tcl/tk
proc's.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|




|
|
|

|


|
|
|



|

|
|
|
|











|



|
|
|




|



|
|
|
|




|

|

|
|



|






|


>

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

# TIP 319: Implement Backwards Compatibility for ttk Themed Widgets in tk Widgets

	Author:		Eric Taylor <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Created:	04-Jun-2008
	Post-History:	
-----

# Abstract

This TIP calls for the implementation of backward compatibility between ttk
themed widgets and conventional tk widgets. It does this by describing
configuration options that specify how to deal with unsupported options
\(error, ignore, or call supplied callbacks\) where full compatibility is not
feasible. Configuration should be both global \(all widgets\) and specific \(by
class or individual widget\).

# Rationale

Tk 8.5 now includes a parallel set of widgets, created through calls to
similar widget constructors, but invoked using the namespace **ttk::**
prepended to the name of an existing widget. For example, **ttk::button**
creates a themed button, while the unqualified **button** creates standard
Tk button widgets.

One of the stated purposes of these new widgets is to bring Tk up to the
standards now expected for attractive looking GUI programs. The **ttk**
package does this quite well, but only for new programs. Imagine the leverage
we would have if we could upgrade older programs \(easily and automatically\) to
use these widgets.  While one can use an editor and add in the **ttk::** to
each widget creation call \(which then begs the question of why we can't have
this done automatically with a simple configuration procedure\) one is often
stuck when trying to implement the same behavior since many Tk options which
are currently unsupported in ttk.

In addition, there are packages, such as visual tcl, which write conventional
tk code. These programs cannot easily be converted to use the new widgets, but
still need to be maintained using the vtcl program.

This TIP proposes that all current Tk widget options be supported where
feasible and that the following command be fully implemented to permit older
Tk-oriented programs run unaltered using the themed set of widgets.

	namespace import -force ttk::*

Since the ttk widgets don't have all the same options, there would need to be
some compatibility code that could simulate the old behavior. For example, in
**button**, there is no longer a **-background** color option, nor is
there **-padx** and **-pady**. Sometimes these missing options can be
implemented, for example, using **-padding** would let one implement partial
behavior. While it would be preferable to implement these options directly, an
alternative would be to select a compatability handling mode of ignore, error,
or callback to aid the developer in implementing missing options.

# Proposal

To that purpose, I propose some kind of configuration option, for example:

 > **ttk::compatibility**
   ?**-onerror** [**ignore**\|**error**\|**callback**]?
   ?**-callback** _proc_?
   ?**-class** [_widget-class_\|**all**]?

When the callback procedure is invoked, it should be passed additional
parameters which would completely identify,

 1. The widget \(e.g. **.frame.button**\)

 2. The option that is not directly supported \(e.g. **-pady**\)

 3. The value specified for that option \(the argument following the
    _-option_\)

 4. Anything else I've forgotten

The above should also be configured globally \(all widgets\) or on a widget by
widget basis. For individual widgets, there should be a configuration option
for the above.

I would think that most of this should be implementable with pure tcl/tk
proc's.

# Copyright

This document has been placed in the public domain.

Name change from tip/32.tip to tip/32.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

TIP:            32
Title:          Add Tcl_Obj-enabled counterpart to Tcl_CreateTrace
Version:        $Revision: 1.11 $
Author:         David Cuthbert <[email protected]>
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        23-Mar-2001
Post-History:   
Discussions-To: news:comp.lang.tcl
Keywords:       trace,Tcl_Obj
Tcl-Version:    8.4a4


~ Abstract

This document proposes to add Tcl_Obj support for trace procedures written
in C.

~ Rationale

The ''Tcl_Obj'' system was introduced in version 8.0, making
computations (potentially) much more efficient by eliminating many
type conversions to and from strings.  However, the trace API
continues to require character strings in both command and variable
traces.

In addition, the ''Tcl_CreateTrace'' function interacts rather badly
with the bytecode compiler, since it forbids inlining of functions.
Since many trace applications ignore the built-in functions that would
have been inlined, this restriction is not needed by many
applications.  This TIP proposes to make it optional in the revised API.

The trace mechanism in the Tcl library has been underused for some
time, partly because it is awkward.  While the profiler, tracer and
debugger from TclX and the debugger from Expect have seen some limited
success, they are certainly not familiar to the majority of Tcl users.

The second author of this TIP has experimented with using the trace
mechanism to build a profiler for Tcl that does not depend on source
code instrumentation.  His experience was that:

  * It is very difficult to write useful trace procedures without
    resorting to ''tclInt.h'' -- in particular, the fact that only the
    command name and not the ''Tcl_Command'' token is passed meant
    that ''Tcl_FindCommand'' is needed to do virtually anything
    useful.

  * The profiler often perturbs the run-time behavior of the program,
    often violently.  The reason is twofold.  First, the string
    representation of all of a traced command's arguments must be
    constructed, even though the trace procedure has no need for
    them.  Second, the presence of the trace procedure defeats the
    bytecode compiler.  Since the user of a profiler is unlikely to
    care about each individual built-in command (the common usage is
    to profile the time spent in procedures), turning off inline
    compilation of commands is neither needed nor wanted.

  * The profiler traces returns from commands by subsituting the
    command procedure with one that is internal to the profiler
    itself, and restoring the command procedure upon exit.  Doing so
    requires many needless lookups of the command name, because only
    the name is presented to the trace procedure, and the name is the
    only way to access ''Tcl_GetCommandInfo'' and
    ''Tcl_SetCommandInfo''.  This overhead can be avoided only by
    including ''tclInt.h'' and casting the ''Tcl_Command'' object to a
    ''Command'' object -- in other words, by accessing the
    interpreter's internal data structures from the extension.

This TIP is an effort to rationalize the trace interface to avoid
these difficulties.

~ Specification

The following functions shall be added to the Tcl core:

 1. Tcl_CreateObjTrace

| Tcl_Trace Tcl_CreateObjTrace ( Tcl_Interp*          interp,
|                                int                  level, 
|                                int                  flags,
|                                Tcl_CmdObjTraceProc* objProc,
|                                ClientData           clientData );

  > The ''Tcl_CreateObjTrace'' function adds a trace to the Tcl evaluator.
    The ''interp'' argument is the Tcl interpreter for which tracing is
    being requested.  The ''level'' argument is the maximum depth of
    recursive calls; when the execution depth of the interpreter exceeds
    this number, the trace callback does not execute.  The ''objProc''
    argument is the callback procedure to execute each time a Tcl command
    is evaluated; it is expected to have arguments and result type that
    match ''Tcl_CmdObjTraceProc'' below.  The ''clientData'' argument is
    client data to pass to the ''objProc'' callback.  Finally, the
    ''flags'' argument gives flags that control the tracing.  Initially,
    the only flag supported will be ''TCL_ALLOW_INLINE_COMPILE''.  If this
    flag is set, the bytecode compiler is permitted to compile in-line
    code for the Tcl built-in commands; any command that has been compiled
    in-line will not be traced.

  > The ''Tcl_CreateObjTrace'' function returns a ''trace token'' -- an
    object of opaque type that may be passed to ''Tcl_DeleteTrace'' to
    delete the trace.

  > The ''Tcl_CmdObjTraceProc'' will have the following type signature.

|    typedef int Tcl_CmdObjTraceProc( ClientData     clientData,
|                                     Tcl_Interp*    interp,
|                                     int            level,
|                                     CONST char*    command,
|                                     Tcl_Command    commandInfo,
|                                     int            objc,
|                                     Tcl_Obj *CONST objv[] );

 >  The ''clientData'' parameter is the client data that was passed to
    ''Tcl_CreateObjTrace''.  The ''interp'' parameter designates a Tcl
    interpreter.  The ''level'' parameter specifies the execution level.
    The ''command'' parameter gives the raw UTF-8 text of the command
    being evaluated, before any substitutions have been performed.  The
    ''commandInfo'' parameter is an opaque ''Tcl_Command'' object that
    gives information about the command.  The ''objc'' and ''objv''
    parameters are the command name and parameter vector after
    substitution.

  > The trace procedure is expected to return a standard Tcl status
    return.  If it returns ''TCL_OK'', the command is evaluated
    normally.  If it returns ''TCL_ERROR'', evaluation of the command
    does not take place.  The interpreter result is expected to
    contain an error message.  If it returns any other status, such as
    ''TCL_BREAK'', ''TCL_CONTINUE'' or ''TCL_RETURN'', it is treated
    as if the command had done so.

 1. Tcl_GetCommandInfoFromToken and Tcl_SetCommandInfoFromToken

| int
| Tcl_GetCommandInfoFromToken( Tcl_Command  token,
|                          Tcl_CmdInfo* infoPtr );

| int
| Tcl_SetCommandInfoFromToken( Tcl_Command        token,
|                          CONST Tcl_CmdInfo* infoPtr );

  > The ''Tcl_GetCommandInfoFromToken'' and ''Tcl_SetCommandInfoFromToken''
    functions are precisely parallel to today's ''Tcl_GetCommandInfo''
    and ''Tcl_SetCommandInfo'' procedures, except that they accept an
    opaque ''Tcl_Command'' object instead of a command name.  They are
    provided so that trace procedures (and other extensions that have
    such an object) can adjust command information without having to
    go through two extra lookups in the command hash by applying
    ''Tcl_GetCommandInfo'' to the result of ''Tcl_GetCommandName.''

~ Change History

10 February 2002 - Moved to Final Status with slight revisions in the names
and arguments of Tcl_GetCommandInfoFromToken and Tcl_SetCommandInfoFromToken.

3 November 2001 - Reworked the entire TIP.  Changed the object trace
handling to work with ''Tcl_Command'' objects instead of command
names.  Removed the object-based variable trace procedures.  Since Tcl
variable names really are character strings and not Tcl objects,
object-based variable trace procedures would be ''slower'' than the
string-based ones.

30 March 2001 - Changed return value of objProc to a Tcl_Obj * instead
of int (and using the interpreter result to indicate an error).  This
is more consistent with the current behavior (but without the bug).  -dac

~ Copyright

Copyright � 2000 by David Cuthbert.  Distribution in whole or part,
with or without annotations, is unlimited.

Copyright � 2001 by Kevin B. Kenny.  Distribution in whole or part,
with or without annotations, is unlimited.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|


|

|
|




|















|
|
|








|
|







|
|
|
|





|



|

|
|
|
|
|

|
|
|

|


|
|
|
|




|
|


|

|
|
|
|
|
|
|

|
|
|
|

|
|



|
|
|


|


|

|
|
|

|
|
|

|
|
|
|
|
|

|

|


|


|


|


|
|
|

|

|


|

>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

# TIP 32: Add Tcl_Obj-enabled counterpart to Tcl_CreateTrace

	Author:         David Cuthbert <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        23-Mar-2001
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Keywords:       trace,Tcl_Obj
	Tcl-Version:    8.4a4
-----

# Abstract

This document proposes to add Tcl\_Obj support for trace procedures written
in C.

# Rationale

The _Tcl\_Obj_ system was introduced in version 8.0, making
computations \(potentially\) much more efficient by eliminating many
type conversions to and from strings.  However, the trace API
continues to require character strings in both command and variable
traces.

In addition, the _Tcl\_CreateTrace_ function interacts rather badly
with the bytecode compiler, since it forbids inlining of functions.
Since many trace applications ignore the built-in functions that would
have been inlined, this restriction is not needed by many
applications.  This TIP proposes to make it optional in the revised API.

The trace mechanism in the Tcl library has been underused for some
time, partly because it is awkward.  While the profiler, tracer and
debugger from TclX and the debugger from Expect have seen some limited
success, they are certainly not familiar to the majority of Tcl users.

The second author of this TIP has experimented with using the trace
mechanism to build a profiler for Tcl that does not depend on source
code instrumentation.  His experience was that:

  * It is very difficult to write useful trace procedures without
    resorting to _tclInt.h_ -- in particular, the fact that only the
    command name and not the _Tcl\_Command_ token is passed meant
    that _Tcl\_FindCommand_ is needed to do virtually anything
    useful.

  * The profiler often perturbs the run-time behavior of the program,
    often violently.  The reason is twofold.  First, the string
    representation of all of a traced command's arguments must be
    constructed, even though the trace procedure has no need for
    them.  Second, the presence of the trace procedure defeats the
    bytecode compiler.  Since the user of a profiler is unlikely to
    care about each individual built-in command \(the common usage is
    to profile the time spent in procedures\), turning off inline
    compilation of commands is neither needed nor wanted.

  * The profiler traces returns from commands by subsituting the
    command procedure with one that is internal to the profiler
    itself, and restoring the command procedure upon exit.  Doing so
    requires many needless lookups of the command name, because only
    the name is presented to the trace procedure, and the name is the
    only way to access _Tcl\_GetCommandInfo_ and
    _Tcl\_SetCommandInfo_.  This overhead can be avoided only by
    including _tclInt.h_ and casting the _Tcl\_Command_ object to a
    _Command_ object -- in other words, by accessing the
    interpreter's internal data structures from the extension.

This TIP is an effort to rationalize the trace interface to avoid
these difficulties.

# Specification

The following functions shall be added to the Tcl core:

 1. Tcl\_CreateObjTrace

		 Tcl_Trace Tcl_CreateObjTrace ( Tcl_Interp*          interp,
		                                int                  level, 
		                                int                  flags,
		                                Tcl_CmdObjTraceProc* objProc,
		                                ClientData           clientData );

	  > The _Tcl\_CreateObjTrace_ function adds a trace to the Tcl evaluator.
    The _interp_ argument is the Tcl interpreter for which tracing is
    being requested.  The _level_ argument is the maximum depth of
    recursive calls; when the execution depth of the interpreter exceeds
    this number, the trace callback does not execute.  The _objProc_
    argument is the callback procedure to execute each time a Tcl command
    is evaluated; it is expected to have arguments and result type that
    match _Tcl\_CmdObjTraceProc_ below.  The _clientData_ argument is
    client data to pass to the _objProc_ callback.  Finally, the
    _flags_ argument gives flags that control the tracing.  Initially,
    the only flag supported will be _TCL\_ALLOW\_INLINE\_COMPILE_.  If this
    flag is set, the bytecode compiler is permitted to compile in-line
    code for the Tcl built-in commands; any command that has been compiled
    in-line will not be traced.

	  > The _Tcl\_CreateObjTrace_ function returns a _trace token_ -- an
    object of opaque type that may be passed to _Tcl\_DeleteTrace_ to
    delete the trace.

	  > The _Tcl\_CmdObjTraceProc_ will have the following type signature.

		    typedef int Tcl_CmdObjTraceProc( ClientData     clientData,
		                                     Tcl_Interp*    interp,
		                                     int            level,
		                                     CONST char*    command,
		                                     Tcl_Command    commandInfo,
		                                     int            objc,
		                                     Tcl_Obj *CONST objv[] );

	 >  The _clientData_ parameter is the client data that was passed to
    _Tcl\_CreateObjTrace_.  The _interp_ parameter designates a Tcl
    interpreter.  The _level_ parameter specifies the execution level.
    The _command_ parameter gives the raw UTF-8 text of the command
    being evaluated, before any substitutions have been performed.  The
    _commandInfo_ parameter is an opaque _Tcl\_Command_ object that
    gives information about the command.  The _objc_ and _objv_
    parameters are the command name and parameter vector after
    substitution.

	  > The trace procedure is expected to return a standard Tcl status
    return.  If it returns _TCL\_OK_, the command is evaluated
    normally.  If it returns _TCL\_ERROR_, evaluation of the command
    does not take place.  The interpreter result is expected to
    contain an error message.  If it returns any other status, such as
    _TCL\_BREAK_, _TCL\_CONTINUE_ or _TCL\_RETURN_, it is treated
    as if the command had done so.

 1. Tcl\_GetCommandInfoFromToken and Tcl\_SetCommandInfoFromToken

		 int
		 Tcl_GetCommandInfoFromToken( Tcl_Command  token,
		                          Tcl_CmdInfo* infoPtr );

		 int
		 Tcl_SetCommandInfoFromToken( Tcl_Command        token,
		                          CONST Tcl_CmdInfo* infoPtr );

	  > The _Tcl\_GetCommandInfoFromToken_ and _Tcl\_SetCommandInfoFromToken_
    functions are precisely parallel to today's _Tcl\_GetCommandInfo_
    and _Tcl\_SetCommandInfo_ procedures, except that they accept an
    opaque _Tcl\_Command_ object instead of a command name.  They are
    provided so that trace procedures \(and other extensions that have
    such an object\) can adjust command information without having to
    go through two extra lookups in the command hash by applying
    _Tcl\_GetCommandInfo_ to the result of _Tcl\_GetCommandName._

# Change History

10 February 2002 - Moved to Final Status with slight revisions in the names
and arguments of Tcl\_GetCommandInfoFromToken and Tcl\_SetCommandInfoFromToken.

3 November 2001 - Reworked the entire TIP.  Changed the object trace
handling to work with _Tcl\_Command_ objects instead of command
names.  Removed the object-based variable trace procedures.  Since Tcl
variable names really are character strings and not Tcl objects,
object-based variable trace procedures would be _slower_ than the
string-based ones.

30 March 2001 - Changed return value of objProc to a Tcl\_Obj \* instead
of int \(and using the interpreter result to indicate an error\).  This
is more consistent with the current behavior \(but without the bug\).  -dac

# Copyright

Copyright © 2000 by David Cuthbert.  Distribution in whole or part,
with or without annotations, is unlimited.

Copyright © 2001 by Kevin B. Kenny.  Distribution in whole or part,
with or without annotations, is unlimited.

Name change from tip/320.tip to tip/320.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

TIP:            320
Title:          Improved Variable Handling in the Core Object System
Version:        $Revision: 1.6 $
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        13-Jun-2008
Post-History:   
Keywords:       TclOO
Tcl-Version:    8.6


~ Abstract

This TIP specifies new configuration commands that allow variables to be used
in methods of the core object system without explicit declaration in each
method.

~ Rationale

During the discussions leading up to the vote on [257], it became apparent
that being able to access at least some variables of an object without
explicit declaration in each method was desirable. Doing this would make
working with the core object system much easier in many common cases, and
would also allow for potentially more efficient implementation.

However, there is a balance to be drawn. If every variable of the object was
made available in the method by default (the simplest case) there would
frequently be problems with interactions between the formal arguments of a
superclass's methods and the instance variables of a subclass! That would be
highly undesirable, as it completely breaks the principle of isolation of
class implementations.

There are two ways of dealing with this issue.

 1. Make the variables understood by a particular class be distinct from those
    understood by subclasses of the class.

 2. Only bring those variables into scope that are actually declared by a
    particular class.

Studying the first alternative, there are two ways to actually achieve this:
not putting the variables in a namespace but actually using a separate
structure (poor, because then we would lose the ability to easily use the
variable with many of Tcl's general variable facilities), or modifying the
namespace-visible name of each variable to include some unique string coupled
to the class declaring it. Though I think that the second option is better
than the first (actual implementations would be able to use the
'''oo::object''' class's '''variable''' and '''varname''' methods to hide many
of the details where they are currently exposed at all) I still do not
particularly like it since it would mean that the cases where a class and a
subclass ''want'' to refer to the same variable are very awkward.

Hence I think that there should be a mechanism for declaring what variables a
class has, that those names should be the namespace-visible names of the
variables, and that only those variables that are declared by a particular
class should be ''automatically'' visible in the class's methods (including
the constructor and destructor, of course). As a matter of basic symmetry,
object-level declarations of variables and methods should also be possible.

~ Proposed Change

Every object and every class will have associated with it a list of variable
names. This list will be configurable via a subcommand of '''oo::define''' and
introspectable. Methods (strictly, only procedure-like methods, constructors
and destructors) will then make those variables that were declared at the same
declaration level (i.e. in the same class, or in the object itself for methods
defined on the object) available in the method body without further
declaration or qualification. At declaration time, the type of the variable
(i.e. whether it is an array or a simple variable) will not be defined; that
may be done in the constructor. As there is no (public) C API for declaring a
procedure-like method, there will not be a public C API for declaring the
variables either.

Note that the order in which the declaration of some methods and some
variables for a class or object will not matter.

~~ Declaration

The '''oo::define''' and '''oo::objdefine''' (and also the '''self'''
subcommand of '''oo::define''') will gain a new subcommand: '''variable'''.
This will take zero or more arguments, and those arguments will form the list
of variables that are made available by default. Each argument will need to be
a valid variable local name without parentheses.

Syntax (other uses analogous according to normal behaviour of the class and
object definition commands):

 > '''oo::define''' ''class'' '''variable''' ?''varName ...''?

~~ Introspection

The list of variables declared by a particular class, ''class'', may be
retrieved by:

 > '''info class variables''' ''class''

The list of variables declared by a particular object, ''object'', may be
retrieved by:

 > '''info object variables''' ''object''

Note that the full list of ''all'' variables (matching an optional pattern) in
an object's namespace will be retrievable using '''info object vars'''; this
mechanism is disjoint (though '''info object variables''' will return
variables that can be returned by '''info object vars''').

~ Implementation

https://sourceforge.net/support/tracker.php?aid=2005460

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|

|






|















|
|


|
|
|

|




|
|


|


|
|
|
|
|

|
|






|

|
|




|
|

|

|

|


|

|


|

|
|
|
|

|

|

|


>

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

# TIP 320: Improved Variable Handling in the Core Object System

	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        13-Jun-2008
	Post-History:   
	Keywords:       TclOO
	Tcl-Version:    8.6
-----

# Abstract

This TIP specifies new configuration commands that allow variables to be used
in methods of the core object system without explicit declaration in each
method.

# Rationale

During the discussions leading up to the vote on [[257]](257.md), it became apparent
that being able to access at least some variables of an object without
explicit declaration in each method was desirable. Doing this would make
working with the core object system much easier in many common cases, and
would also allow for potentially more efficient implementation.

However, there is a balance to be drawn. If every variable of the object was
made available in the method by default \(the simplest case\) there would
frequently be problems with interactions between the formal arguments of a
superclass's methods and the instance variables of a subclass! That would be
highly undesirable, as it completely breaks the principle of isolation of
class implementations.

There are two ways of dealing with this issue.

 1. Make the variables understood by a particular class be distinct from those
    understood by subclasses of the class.

 2. Only bring those variables into scope that are actually declared by a
    particular class.

Studying the first alternative, there are two ways to actually achieve this:
not putting the variables in a namespace but actually using a separate
structure \(poor, because then we would lose the ability to easily use the
variable with many of Tcl's general variable facilities\), or modifying the
namespace-visible name of each variable to include some unique string coupled
to the class declaring it. Though I think that the second option is better
than the first \(actual implementations would be able to use the
**oo::object** class's **variable** and **varname** methods to hide many
of the details where they are currently exposed at all\) I still do not
particularly like it since it would mean that the cases where a class and a
subclass _want_ to refer to the same variable are very awkward.

Hence I think that there should be a mechanism for declaring what variables a
class has, that those names should be the namespace-visible names of the
variables, and that only those variables that are declared by a particular
class should be _automatically_ visible in the class's methods \(including
the constructor and destructor, of course\). As a matter of basic symmetry,
object-level declarations of variables and methods should also be possible.

# Proposed Change

Every object and every class will have associated with it a list of variable
names. This list will be configurable via a subcommand of **oo::define** and
introspectable. Methods \(strictly, only procedure-like methods, constructors
and destructors\) will then make those variables that were declared at the same
declaration level \(i.e. in the same class, or in the object itself for methods
defined on the object\) available in the method body without further
declaration or qualification. At declaration time, the type of the variable
\(i.e. whether it is an array or a simple variable\) will not be defined; that
may be done in the constructor. As there is no \(public\) C API for declaring a
procedure-like method, there will not be a public C API for declaring the
variables either.

Note that the order in which the declaration of some methods and some
variables for a class or object will not matter.

## Declaration

The **oo::define** and **oo::objdefine** \(and also the **self**
subcommand of **oo::define**\) will gain a new subcommand: **variable**.
This will take zero or more arguments, and those arguments will form the list
of variables that are made available by default. Each argument will need to be
a valid variable local name without parentheses.

Syntax \(other uses analogous according to normal behaviour of the class and
object definition commands\):

 > **oo::define** _class_ **variable** ?_varName ..._?

## Introspection

The list of variables declared by a particular class, _class_, may be
retrieved by:

 > **info class variables** _class_

The list of variables declared by a particular object, _object_, may be
retrieved by:

 > **info object variables** _object_

Note that the full list of _all_ variables \(matching an optional pattern\) in
an object's namespace will be retrievable using **info object vars**; this
mechanism is disjoint \(though **info object variables** will return
variables that can be returned by **info object vars**\).

# Implementation

<https://sourceforge.net/support/tracker.php?aid=2005460>

# Copyright

This document has been placed in the public domain.

Name change from tip/321.tip to tip/321.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

TIP:            321
Title:          Add a [tk busy] Command
Version:        $Revision: 1.6 $
Author:         Jos Decoster <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        26-Jun-2008
Post-History:   
Keywords:       Tk,BLT,busy
Tcl-Version:    8.6


~ Abstract

The '''blt::busy''' commands can be used to make Tk widget busy, with all user
interaction blocked and the cursor can be changed to e.g. a clock. This TIP
proposes to add this useful feature to Tk.

~ Rationale

BLT has a lot of very useful commands: '''bgexec''', '''busy''', '''vector''',
'''graph''' widget, '''barchart''' widget, ... But getting BLT to work with
the latest releases of Tcl and Tk becomes more and more difficult. Some of the
problems I experienced are:

 * internal Tk structures are mirrored

 * interaction with xft fails, so Tk has to be build without xft support

 * the build process is different from the one used in Tcl and Tk

Discussions on CLT and #tcl indicated that extracting functionality from BLT
and add it to Tcl and Tk might be a good way to make the blt commands
available for every Tcl programmer.

This TIP proposes a way to add the blt::busy command to Tk, based on the code
as found in BLT2.4z and the code as found in busy.kit. While adding the code
to Tk, it was rewritten to use the Tcl_Obj interface and the new option
interface. The interface has also been simplified. The '''blt::release'''
command was not withheld. Because often the same window is made busy again and
again, using '''release''' in stead of '''forget''' might be faster. But when
making an application busy, it's because it'll have to wait for another
operation and/or process to finish which will typically take a much longer
time than the time needed to (re)create the transparent window. The
'''names''' and '''isbusy''' commands were replaced by the new '''current'''
command. The confusing difference between a window which is busy, a window
which was busy but still has the associated transparent window allocated and a
window which was busy but no longer has its associated transparent window
allocated was removed.

The name of this new Tk command as currently implemented is '''tk busy''',
part of the '''tk''' command ensemble. Adding it as an option to the
'''grab''' command might cause confusion as the '''tk busy''' command has the
opposite functionality of the '''grab''' command. It blocks all user
interaction rather than redirecting it to one widget.

~ Specification

The '''tk busy''' command is an ensemble with a special feature that any
unrecognized subcommand that starts with a period is treated as an invokation
of the '''hold''' subcommand upon the widget with that name.

~~ Hold Subcommand

 > '''tk busy''' ''window'' ?''option value''?

 > '''tk busy hold''' ''window'' ?''option value''?

Makes the window (and its descendants in the Tk window hierarchy) appear busy by
ignoring all events sent to the window and its descendants. ''Window'' must be a
valid path name of a Tk widget. A transparent window is put in front of the
specified window. This transparent window is mapped the next time idle tasks are
processed, and the specified window and its descendants will be blocked from
user interactions. Normally update should be called immediately afterward to
insure that the hold operation is in effect before the application starts its
processing. The following configuration options are valid:

 > '''-cursor''' ''cursorName'' 

Specifies the cursor to be displayed when the widget is made busy. CursorName can be in any form accepted by Tk_GetCursor. The default cursor is watch.

~~ Forget Subcommand

 > '''tk busy forget''' ''window''

Releases resources allocated by the '''tk busy''' command for ''window'',
including the transparent window. User events will again be received by the
specified window. Resources are also released when the specified window is
destroyed. ''Window'' must be the name of a widget previously specified in a
'''hold''' operation, otherwise an error is reported.

~~ Current Subcommand

 > '''tk busy current''' ?''pattern''?

Returns the pathnames of all windows that are currently made busy. If a
''pattern'' is given, only the path names of busy windows matching ''pattern''
are returned.

~~ Status Subcommand

 > '''tk busy status''' ''window''

Returns the busy status of a ''window''. If ''window'' presently can not
receive user interactions, 1 is returned, otherwise 0.

~~ Configure Subcommand

 > '''tk busy configure''' ''window'' ?''option''? ?''value ...''?

Queries or modifies the '''tk busy''' command configuration options for
''window''. ''Window'' must be the path name of a widget previously made busy
by the '''hold''' operation. If no options are specified, a list describing
all of the available options for window (see '''Tk_ConfigureInfo''' for
information on the format of this list) is returned. If ''option'' is
specified with no ''value'', then the command returns a list describing the
one named option (this list will be identical to the corresponding sublist of
the value returned if no option is specified). If one or more ''option-value''
pairs are specified, then the command modifies the given widget option(s) to
have the given value(s); in this case the command returns the empty
string. Options may have any of the values accepted by the hold operation.

Please note that the option database is referenced through window. For
example, if the widget .frame is to be made busy, the busy cursor can be
specified for it by either option command:

|        option add *frame.busyCursor gumby
|        option add *Frame.BusyCursor gumby

~~ Cget Subcommand

 > '''tk busy cget''' ''window option''

Queries the '''tk busy''' command configuration options for ''window''.
''Window'' must be the path name of a widget previously made busy by the
'''hold''' operation. The command returns the present value of the specified
''option''. ''Option'' may have any of the values accepted by the '''hold'''
operation.

~ Reference Implementation

See SourceForge patch #1997907
[https://sourceforge.net/support/tracker.php?aid=1997907]. There is no support
for Mac + Aqua in this patch. It compiles on Mac + Aqua and the command will
not return errors but will not resort in a ''busy'' effect. Mac + X11 does
work.

~ Compatibility

Because the command as proposed above has the same interface and behavior as
the '''blt::busy''' command, replacing '''blt::busy''' with '''tk busy''' is
all that's needed to switch to the Tk version of the busy command.

The '''tk busy''' command is not one-by-one compatible with the
'''blt::busy''' command, but typical use ('''hold''' and '''forget''') will
not suffer a lot. Aliases or an ensemble could be used to make transition
easier.

~ Alternatives

The busy command is available as starkit from http://tcl.tk/starkits/busy.kit

An alternative would have been to keep the interface from BLT. This would have
made transition easier, but would have kept the confusing difference between
''forgotten'' and ''released'' busy windows.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|

|
|









|





|
|

|


|
|





|
|
|
|


|

|

|

|

|

|

|
|







|

|

|

|

|


|
|

|

|


|


|

|

|


|

|

|
|
|
|
|
|
|
|
|
|






|
|

|

|

|
|
|
|


|

|
|
|
|


|


|


|
|



|

|



|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

# TIP 321: Add a [tk busy] Command

	Author:         Jos Decoster <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        26-Jun-2008
	Post-History:   
	Keywords:       Tk,BLT,busy
	Tcl-Version:    8.6
-----

# Abstract

The **blt::busy** commands can be used to make Tk widget busy, with all user
interaction blocked and the cursor can be changed to e.g. a clock. This TIP
proposes to add this useful feature to Tk.

# Rationale

BLT has a lot of very useful commands: **bgexec**, **busy**, **vector**,
**graph** widget, **barchart** widget, ... But getting BLT to work with
the latest releases of Tcl and Tk becomes more and more difficult. Some of the
problems I experienced are:

 * internal Tk structures are mirrored

 * interaction with xft fails, so Tk has to be build without xft support

 * the build process is different from the one used in Tcl and Tk

Discussions on CLT and \#tcl indicated that extracting functionality from BLT
and add it to Tcl and Tk might be a good way to make the blt commands
available for every Tcl programmer.

This TIP proposes a way to add the blt::busy command to Tk, based on the code
as found in BLT2.4z and the code as found in busy.kit. While adding the code
to Tk, it was rewritten to use the Tcl\_Obj interface and the new option
interface. The interface has also been simplified. The **blt::release**
command was not withheld. Because often the same window is made busy again and
again, using **release** in stead of **forget** might be faster. But when
making an application busy, it's because it'll have to wait for another
operation and/or process to finish which will typically take a much longer
time than the time needed to \(re\)create the transparent window. The
**names** and **isbusy** commands were replaced by the new **current**
command. The confusing difference between a window which is busy, a window
which was busy but still has the associated transparent window allocated and a
window which was busy but no longer has its associated transparent window
allocated was removed.

The name of this new Tk command as currently implemented is **tk busy**,
part of the **tk** command ensemble. Adding it as an option to the
**grab** command might cause confusion as the **tk busy** command has the
opposite functionality of the **grab** command. It blocks all user
interaction rather than redirecting it to one widget.

# Specification

The **tk busy** command is an ensemble with a special feature that any
unrecognized subcommand that starts with a period is treated as an invokation
of the **hold** subcommand upon the widget with that name.

## Hold Subcommand

 > **tk busy** _window_ ?_option value_?

 > **tk busy hold** _window_ ?_option value_?

Makes the window \(and its descendants in the Tk window hierarchy\) appear busy by
ignoring all events sent to the window and its descendants. _Window_ must be a
valid path name of a Tk widget. A transparent window is put in front of the
specified window. This transparent window is mapped the next time idle tasks are
processed, and the specified window and its descendants will be blocked from
user interactions. Normally update should be called immediately afterward to
insure that the hold operation is in effect before the application starts its
processing. The following configuration options are valid:

 > **-cursor** _cursorName_ 

Specifies the cursor to be displayed when the widget is made busy. CursorName can be in any form accepted by Tk\_GetCursor. The default cursor is watch.

## Forget Subcommand

 > **tk busy forget** _window_

Releases resources allocated by the **tk busy** command for _window_,
including the transparent window. User events will again be received by the
specified window. Resources are also released when the specified window is
destroyed. _Window_ must be the name of a widget previously specified in a
**hold** operation, otherwise an error is reported.

## Current Subcommand

 > **tk busy current** ?_pattern_?

Returns the pathnames of all windows that are currently made busy. If a
_pattern_ is given, only the path names of busy windows matching _pattern_
are returned.

## Status Subcommand

 > **tk busy status** _window_

Returns the busy status of a _window_. If _window_ presently can not
receive user interactions, 1 is returned, otherwise 0.

## Configure Subcommand

 > **tk busy configure** _window_ ?_option_? ?_value ..._?

Queries or modifies the **tk busy** command configuration options for
_window_. _Window_ must be the path name of a widget previously made busy
by the **hold** operation. If no options are specified, a list describing
all of the available options for window \(see **Tk\_ConfigureInfo** for
information on the format of this list\) is returned. If _option_ is
specified with no _value_, then the command returns a list describing the
one named option \(this list will be identical to the corresponding sublist of
the value returned if no option is specified\). If one or more _option-value_
pairs are specified, then the command modifies the given widget option\(s\) to
have the given value\(s\); in this case the command returns the empty
string. Options may have any of the values accepted by the hold operation.

Please note that the option database is referenced through window. For
example, if the widget .frame is to be made busy, the busy cursor can be
specified for it by either option command:

	        option add *frame.busyCursor gumby
	        option add *Frame.BusyCursor gumby

## Cget Subcommand

 > **tk busy cget** _window option_

Queries the **tk busy** command configuration options for _window_.
_Window_ must be the path name of a widget previously made busy by the
**hold** operation. The command returns the present value of the specified
_option_. _Option_ may have any of the values accepted by the **hold**
operation.

# Reference Implementation

See SourceForge patch \#1997907
<https://sourceforge.net/support/tracker.php?aid=1997907> . There is no support
for Mac \+ Aqua in this patch. It compiles on Mac \+ Aqua and the command will
not return errors but will not resort in a _busy_ effect. Mac \+ X11 does
work.

# Compatibility

Because the command as proposed above has the same interface and behavior as
the **blt::busy** command, replacing **blt::busy** with **tk busy** is
all that's needed to switch to the Tk version of the busy command.

The **tk busy** command is not one-by-one compatible with the
**blt::busy** command, but typical use \(**hold** and **forget**\) will
not suffer a lot. Aliases or an ensemble could be used to make transition
easier.

# Alternatives

The busy command is available as starkit from <http://tcl.tk/starkits/busy.kit>

An alternative would have been to keep the interface from BLT. This would have
made transition easier, but would have kept the confusing difference between
_forgotten_ and _released_ busy windows.

# Copyright

This document has been placed in the public domain.

Name change from tip/322.tip to tip/322.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

TIP:            322
Title:          Publish the NRE API
Version:        $Revision: 1.9 $
Author:         Miguel Sofer <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        13-Jul-2008
Post-History:   
Tcl-Version:    8.6


~ Abstract

This TIP exposes an API to allow extension writers to take advantage of Tcl's
Non-Recursive evaluation Engine.

~ Rationale

NRE (for '''N'''on-'''R'''ecursive '''E'''ngine) is a trampoline
implementation for command evaluation and bytecode execution that massively
reduce Tcl's footprint on the C stack. It is conceptually related to stackless
Python.

NRE is fully backwards compatible with script and C extensions and has already
been committed to HEAD. Extensions that use the normal Tcl API run properly
but cannot take advantage of the non-recursivity.

This TIP proposes to publish a small API for extension writers that will allow
them to exploit the new possibilities.

~ Functions to be Exported

The first two functions permit the creation of NRE-enabled commands.
'''Tcl_NRCreateCommand''' creates a command that implements an NRE interface
''nreProc''. As every command needs also a regular ''objProc'', the function
'''Tcl_NRCallObjProc''' is provided as a utility permitting a relatively
simple way to generate the ''objProc'' from the ''nreProc''.

   * Tcl_Command '''Tcl_NRCreateCommand'''(Tcl_Interp *''interp'', const char
     *''cmdName'', Tcl_ObjCmdProc *''proc'', Tcl_ObjCmdProc *''nreProc'',
     ClientData ''clientData'', Tcl_CmdDeleteProc *''deleteProc'')

   * int '''Tcl_NRCallObjProc'''(Tcl_Interp *''interp'', Tcl_ObjCmdProc
     *''objProc'', ClientData ''clientData'', int ''objc'', Tcl_Obj *const
     *''objv''[])

The next three functions provide the API to request an evaluation by the
trampoline, after the caller returned:

   * int '''Tcl_NREvalObj'''(Tcl_Interp *''interp'', Tcl_Obj *''objPtr'', int
     ''flags'')

   * int '''Tcl_NREvalObjv'''(Tcl_Interp *''interp'', int ''objc'', Tcl_Obj
     *const ''objv''[], int ''flags'')

   * int '''Tcl_NRCmdSwap'''(Tcl_Interp *''interp'', Tcl_Command ''cmd'', int
     ''objc'', Tcl_Obj *const ''objv''[])

Finally, there is a function to register a callback that the trampoline has
to execute right after a requested evaluation, typically used for cleanup.

   * void '''Tcl_NRAddCallback'''(Tcl_Interp *''interp'', Tcl_NRPostProc
     *''postProcPtr'', ClientData ''data0'', ClientData ''data1'', ClientData
     ''data2'', ClientData ''data3'')

~ Documentation

NRE's internal functioning is somewhat documented at
http://msofer.com:8080/wiki?name=NRE

An example of how the API is to be used can be found at
http://msofer.com:8080/wiki?name=Exploiting+NRE

The new API will be documented in a manual page ''doc/NRE.3''.

~ Reference Implementation

The API is already available in HEAD (to become Tcl8.6a2); a high level
description is available at
http://msofer.com:8080/wiki?name=NRE+short+explanation

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|




|

|











|


|
|
|
|

|
|
|

|
|
|




|
|

|
|

|
|




|
|
|

|


|


|

|

|

|

|

|


>

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

# TIP 322: Publish the NRE API

	Author:         Miguel Sofer <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        13-Jul-2008
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

This TIP exposes an API to allow extension writers to take advantage of Tcl's
Non-Recursive evaluation Engine.

# Rationale

NRE \(for **N**on-**R**ecursive **E**ngine\) is a trampoline
implementation for command evaluation and bytecode execution that massively
reduce Tcl's footprint on the C stack. It is conceptually related to stackless
Python.

NRE is fully backwards compatible with script and C extensions and has already
been committed to HEAD. Extensions that use the normal Tcl API run properly
but cannot take advantage of the non-recursivity.

This TIP proposes to publish a small API for extension writers that will allow
them to exploit the new possibilities.

# Functions to be Exported

The first two functions permit the creation of NRE-enabled commands.
**Tcl\_NRCreateCommand** creates a command that implements an NRE interface
_nreProc_. As every command needs also a regular _objProc_, the function
**Tcl\_NRCallObjProc** is provided as a utility permitting a relatively
simple way to generate the _objProc_ from the _nreProc_.

   * Tcl\_Command **Tcl\_NRCreateCommand**\(Tcl\_Interp \*_interp_, const char
     *_cmdName_, Tcl\_ObjCmdProc \*_proc_, Tcl\_ObjCmdProc \*_nreProc_,
     ClientData _clientData_, Tcl\_CmdDeleteProc \*_deleteProc_\)

   * int **Tcl\_NRCallObjProc**\(Tcl\_Interp \*_interp_, Tcl\_ObjCmdProc
     *_objProc_, ClientData _clientData_, int _objc_, Tcl\_Obj \*const
     *_objv_[]\)

The next three functions provide the API to request an evaluation by the
trampoline, after the caller returned:

   * int **Tcl\_NREvalObj**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_objPtr_, int
     _flags_\)

   * int **Tcl\_NREvalObjv**\(Tcl\_Interp \*_interp_, int _objc_, Tcl\_Obj
     *const _objv_[], int _flags_\)

   * int **Tcl\_NRCmdSwap**\(Tcl\_Interp \*_interp_, Tcl\_Command _cmd_, int
     _objc_, Tcl\_Obj \*const _objv_[]\)

Finally, there is a function to register a callback that the trampoline has
to execute right after a requested evaluation, typically used for cleanup.

   * void **Tcl\_NRAddCallback**\(Tcl\_Interp \*_interp_, Tcl\_NRPostProc
     *_postProcPtr_, ClientData _data0_, ClientData _data1_, ClientData
     _data2_, ClientData _data3_\)

# Documentation

NRE's internal functioning is somewhat documented at
<http://msofer.com:8080/wiki?name=NRE>

An example of how the API is to be used can be found at
<http://msofer.com:8080/wiki?name=Exploiting\+NRE>

The new API will be documented in a manual page _doc/NRE.3_.

# Reference Implementation

The API is already available in HEAD \(to become Tcl8.6a2\); a high level
description is available at
<http://msofer.com:8080/wiki?name=NRE\+short\+explanation>

# Copyright

This document has been placed in the public domain.

Name change from tip/323.tip to tip/323.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

TIP:		323
Title:		Do Nothing Gracefully
Version:	$Revision: 1.6 $
Author:		Colin McCormack <[email protected]>
Author:		Don Porter <[email protected]>
Author:		Kevin B. Kenny <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	06-Aug-2008
Post-History:
Tcl-Version:	8.6


~ Abstract

A number of Tcl's built-in commands currently raise errors when given
arguments that would cause them to do nothing. This proposal asks that they
instead simply do nothing gracefully.

~ Rationale

With the introduction of {*} syntax in Tcl 8.5 and its ability to convert one
original word into zero words when an empty list is expanded, scripts using
the syntax are forced to check for the empty list when passing expanded
arguments to a command taking variable numbers of arguments, but arbitrarily
rejecting zero arguments. For example,

| variable {*}$dict

will currently fail if $dict has no entries.  Letting no-ops simply be no-ops
rather than errors greatly lightens the programming burden on callers. There
may be some marginal performance benefits as well.

Furthermore, there is no sound reason to constrain the argument count of these
commands to be positive when an argument count of zero has a natural
interpretation as a no-op. There is an elegance in permitting a function to
range coherently over the complete domain.

~ Proposal

The syntax of the following commands shall be revised as described:

 1. '''file delete''' - accept zero pathnames.

 1. '''file mkdir''' - accept zero directories.

 1. '''global''' - accept zero variable names.

 1. '''glob''' - accept zero patterns, returning list of zero matching files
    (with '''-nocomplain''') or "no matches" error.

 1. '''lassign''' - accept zero variable names.
    [https://sourceforge.net/support/tracker.php?aid=1671880]

 1. '''linsert''' - accept zero elements.
    [https://sourceforge.net/support/tracker.php?aid=1672056]

 1. '''lrepeat''' - accept both ''number'' = 0 and zero elements.
    [https://sourceforge.net/support/tracker.php?aid=1671951]

 1. '''my variable''' - accept zero variable names.

 1. '''namespace upvar''' - accept zero variable names.

 1. '''tcl::tm::path add''' - accept zero paths.

 1. '''tcl::tm::path remove''' - accept zero paths.

 1. '''variable''' - accept zero variable names.
    [https://sourceforge.net/support/tracker.php?aid=1881284]

~ Compatibilty

The proposed changes convert errors into no-ops.  There should be no
compatibility concerns with those. 

~ Implementation

When an implementation patch is completed, it will be logged in the SF Tracker
and noted here.

~ Exclusions

Some other candidates for this treatment are intentionally left out of this
proposal where for various reasons their conversion is complicated in some
way, or the benefits of conversion are not as clear cut. These other commands
might still be revised in a similar way, but are left for other TIPs to
accomplish it so that this TIP can focus only on the low-hanging fruit.

 1. '''after idle'''

 1. '''dict exists'''

 1. '''dict set d''' ''val''	(no ''key'' argument)

 1. '''dict unset d''' ''val''	(no ''key'' argument)

 1. '''dict update d''' ''script''	(no ''key varName'' arguments)

 1. '''eval'''

 1. '''expr'''

 1. '''file join'''

 1. '''interp eval'''

 1. '''namespace eval'''

 1. '''parray''' [https://sourceforge.net/support/tracker.php?aid=1739221]
    This feature request is more about tolerating errors than about expanding
    acceptance over a complete input domain. Not in the spirit of this TIP.

 1. '''uplevel'''

 1. '''upvar''' - presence of the optional ''level'' argument makes this
    one messy.

~ Epilogue

Proposed changes to '''string first''', '''string last''', and
'''string replace''' in earlier revisions of the TIP that were approved
by the vote have been rescinded after testing during the implementation
phase revealed greater than expected issues with the incompatibilities
those changes introduced.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|





|

|





|










|



|

|

|

|
|

|
|

|
|

|
|

|

|

|

|

|
|

|




|




|







|

|

|

|

|

|

|

|

|

|

|



|

|


|

|
|




|


>

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

# TIP 323: Do Nothing Gracefully

	Author:		Colin McCormack <[email protected]>
	Author:		Don Porter <[email protected]>
	Author:		Kevin B. Kenny <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	06-Aug-2008
	Post-History:
	Tcl-Version:	8.6
-----

# Abstract

A number of Tcl's built-in commands currently raise errors when given
arguments that would cause them to do nothing. This proposal asks that they
instead simply do nothing gracefully.

# Rationale

With the introduction of \{\*\} syntax in Tcl 8.5 and its ability to convert one
original word into zero words when an empty list is expanded, scripts using
the syntax are forced to check for the empty list when passing expanded
arguments to a command taking variable numbers of arguments, but arbitrarily
rejecting zero arguments. For example,

	 variable {*}$dict

will currently fail if $dict has no entries.  Letting no-ops simply be no-ops
rather than errors greatly lightens the programming burden on callers. There
may be some marginal performance benefits as well.

Furthermore, there is no sound reason to constrain the argument count of these
commands to be positive when an argument count of zero has a natural
interpretation as a no-op. There is an elegance in permitting a function to
range coherently over the complete domain.

# Proposal

The syntax of the following commands shall be revised as described:

 1. **file delete** - accept zero pathnames.

 1. **file mkdir** - accept zero directories.

 1. **global** - accept zero variable names.

 1. **glob** - accept zero patterns, returning list of zero matching files
    \(with **-nocomplain**\) or "no matches" error.

 1. **lassign** - accept zero variable names.
    <https://sourceforge.net/support/tracker.php?aid=1671880> 

 1. **linsert** - accept zero elements.
    <https://sourceforge.net/support/tracker.php?aid=1672056> 

 1. **lrepeat** - accept both _number_ = 0 and zero elements.
    <https://sourceforge.net/support/tracker.php?aid=1671951> 

 1. **my variable** - accept zero variable names.

 1. **namespace upvar** - accept zero variable names.

 1. **tcl::tm::path add** - accept zero paths.

 1. **tcl::tm::path remove** - accept zero paths.

 1. **variable** - accept zero variable names.
    <https://sourceforge.net/support/tracker.php?aid=1881284> 

# Compatibilty

The proposed changes convert errors into no-ops.  There should be no
compatibility concerns with those. 

# Implementation

When an implementation patch is completed, it will be logged in the SF Tracker
and noted here.

# Exclusions

Some other candidates for this treatment are intentionally left out of this
proposal where for various reasons their conversion is complicated in some
way, or the benefits of conversion are not as clear cut. These other commands
might still be revised in a similar way, but are left for other TIPs to
accomplish it so that this TIP can focus only on the low-hanging fruit.

 1. **after idle**

 1. **dict exists**

 1. **dict set d** _val_	\(no _key_ argument\)

 1. **dict unset d** _val_	\(no _key_ argument\)

 1. **dict update d** _script_	\(no _key varName_ arguments\)

 1. **eval**

 1. **expr**

 1. **file join**

 1. **interp eval**

 1. **namespace eval**

 1. **parray** <https://sourceforge.net/support/tracker.php?aid=1739221> 
    This feature request is more about tolerating errors than about expanding
    acceptance over a complete input domain. Not in the spirit of this TIP.

 1. **uplevel**

 1. **upvar** - presence of the optional _level_ argument makes this
    one messy.

# Epilogue

Proposed changes to **string first**, **string last**, and
**string replace** in earlier revisions of the TIP that were approved
by the vote have been rescinded after testing during the implementation
phase revealed greater than expected issues with the incompatibilities
those changes introduced.

# Copyright

This document has been placed in the public domain.

Name change from tip/324.tip to tip/324.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163

164
165
166
167

168
169
170
171

172
173
174
175

176
177
178

179
180
181

182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200

TIP:            324
Title:          A Standard Dialog For Font Selection
Version:        $Revision: 1.7 $
Author:         Adrian Robert <[email protected]>
Author:         Daniel A. Steffen <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        08-Aug-2008
Post-History:   
Keywords:       Tk
Obsoletes:      213
Tcl-Version:    8.6


~ Abstract

This TIP proposes the addition of a font selection dialog to the set of common
dialogs already available in Tk. Where possible, this dialog will be
implemented using the host platform's standard dialogs.

~ Rationale

A number of platforms (including Windows and Mac OS X) have standard dialogs
for common user-oriented tasks, for which Tk provides an interface via commands
such as '''tk_getOpenFile''' and '''tk_chooseColor'''.
Another dialog that these platforms provide and which some Tk programs would
find useful is a ''standard font selector''.
This TIP proposes adding a command to Tk to allow access to the platform
font selection dialog where available, or to a dialog implemented in Tcl
otherwise.

Unlike the existing dialog commands, the new font dialog command will not
return a result, as on some platforms (Mac OS X) the standard font dialog is
modeless while on others (Windows) it is modal. To accommodate this difference,
all user interaction with the dialog will be communicated to the caller via
callbacks or virtual events. To emphasize this difference in operation between
the new command and the existing Tk dialog commands the proposed name is '''tk
fontchooser''' instead of e.g. '''tk_chooseFont'''.

~ Proposal

Tk shall have a new command ensemble '''tk fontchooser''' with the following
syntax:

 > '''tk fontchooser configure''' ?''-option value -option value ...''?

set or query one or more of the configurations options below (analogous to Tk
widget configuration).

 > '''tk fontchooser show'''

show the font selection dialog. Depending on the platform, may return
immediately or only once the dialog has been withdrawn.

 > '''tk fontchooser hide'''

hide the font selection dialog if it is visible and cause any pending
'''tk fontchooser show''' command to return.

~~Configuration Options

 -parent: specifies/returns the parent window of the font selection dialog
 (similar to the ''-parent'' option to other dialogs).

 -title: specifies/returns the title of the dialog. Has no effect on platforms
 where the font selection dialog does not support titles.

 -font: specifies/returns the font that is currently selected in the dialog if
 it is visible, or that will be initially selected when the dialog is shown (if
 supported by the platform). Can be set to the empty string to indicate that no
 font should be selected. Fonts can be specified in any form given by the "FONT
 DESCRIPTION" section in font(n).

 -command: specifies/returns the command prefix to be called when a font
 selection has been made by the user. The command prefix is evaluated at the
 global level after having the specification of the selected font appended. On
 platforms where the font selection dialog offers the user control of further
 font attributes (such as color), additional key/value pairs may be appended
 before evaluation. Can be set to the empty string to indicate that no callback
 should be invoked. Fonts are specified by a list of form [[3]] of the "FONT
 DESCRIPTION" section in font(n) (i.e. a list of the form ''{family size style
 ?style ...?}'').

 -visible: read-only option that returns a boolean indicating whether the font
 selection dialog is currently visible. Attempting to set this option results
 in an error.

~~Events

<<TkFontchooserVisibility>>

 > virtual event sent to the dialog parent whenever the visibility of the font
 selection dialog changes, both as a result of user action (e.g. disposing of
 the dialog via OK/Cancel button or close box) and of the '''tk fontchooser
 show/hide''' commands being called. Binding scripts can determine the current
 visibility of the dialog by querying the ''-visible'' configuration option.

<<TkFontchooserFontChanged>>

 > virtual event sent to the dialog parent whenever the font selection dialog
 is visible and the selected font changes, both as a result of user action and
 of the ''-font'' configuration option being set. Binding scripts can determine
 the currently selected font by querying the ''-font'' configuration option.

~ Notes

Whenever a platform provides a suitable font dialog in its  API, Tk
shall not use a script-based alternative, even if this means missing
out on features like the title or dynamic updating of the font during
the selection process. This will help to ensure Tk applications meet
platform-specific user-interface design guidelines.

Callers should not expect a result from '''tk fontchooser show''' and may not
assume that the dialog has been withdrawn or closed when the command returns.
All user interaction with the dialog is communicated to the caller via the
''-command'' callback and the ''<<TkFontchooser*>>'' virtual events. It is
implementation dependent which exact user actions result in the callback being
called resp. the virtual events being sent. Where an Apply or OK button is
present in the dialog, it is expected for that button to trigger the
''-command'' callback and ''<<TkFontchooserFontChanged>>'' virtual event.
However, on some implementations other user actions may also have that effect;
on Mac OS X for instance, the standard font selection dialog immediately
reflects all user choices to the caller.

In the presence of multiple widgets intended to be influenced by the font
selection dialog, care needs to be taken to correctly handle focus changes: the
font selected in the dialog should always match the current font of the widget
with the focus, and the ''-command'' callback should only act on the widget
with the focus. The recommended practice is to set font dialog ''-font'' and
''-command'' configuration options in per-widget ''<FocusIn>'' handlers (and if
necessary to unset them - i.e. set to the empty string - in corresponding
''<FocusOut>'' handlers). This is particularly important for implementors of
library code using the font selection dialog, to avoid conflicting with
application code that may also want to use the dialog.

Because the font selection dialog is application-global, in the presence of
multiple interpreters calling '''tk fontchooser''', only the ''-command''
callback set by the interpreter that most recently called '''tk fontchooser
configure''' or '''tk fontchooser show''' will be invoked in response to user
action and only the ''-parent'' set by that interpreter will receive
''<<TkFontchooser*>>'' virtual events.

The font dialog implementation may only store (and return) '''font actual'''
data as the value of the ''-font'' configuration option. This can be an issue
when ''-font'' is set to a named font, if that font is subsequently changed,
the font dialog ''-font'' option needs to be set again to ensure its selected
font matches the new value of the named font.

~ Example

The following example demonstrates the recommended practice of updating the
font dialog configuration with the focus:

| proc tip324demo {} {
|     wm title . "TIP324 Demo"
|     tk fontchooser configure -parent .
|     button .b -command fcToggle -takefocus 0; fcVisibility .b
|     bind . <<TkFontchooserVisibility>> [list fcVisibility .b]
|     foreach w {.t1 .t2} {
|         text $w -width 20 -height 4 -borderwidth 1 -relief solid
|         bind $w <FocusIn> [list fcFocus $w]
|         $w insert end "Text Widget $w"
|     }

|     .t1 configure -font {Courier 14}
|     .t2 configure -font {Times 16}
|     pack .b .t1 .t2; focus .t1
| }

| proc fcToggle {} {
|     tk fontchooser [expr {[tk fontchooser configure -visible] ?
|             "hide" : "show"}]
| }

| proc fcVisibility {w} {
|     $w configure -text [expr {[tk fontchooser configure -visible] ?
|             "Hide Font Dialog" : "Show Font Dialog"}]
| }

| proc fcFocus {w} {
|     tk fontchooser configure -font [$w cget -font] -command [list fcFont $w]
| }

| proc fcFont {w font args} {
|     $w configure -font [font actual $font]
| }

| tip324demo

~ Alternatives

[213] was an earlier proposal for a font selection dialog API, it was withdrawn
when it became clear that it was incompatible with platforms where the standard
font dialog is modeless.

Alternative names for the new command have been proposed: '''tk::choosefont''',
'''tk::chooseFont''', '''tk::fontChooser''', '''tk_chooseFont'''.

~ Reference Implementation

Tk Patch 1477426
[http://sourceforge.net/support/tracker.php?aid=1477426]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|





|

|

|

|





|
|


|
|

|

|


|

|
|

|




|


|

|


|





|
|

|





|

|
|
|





|




|
|
|
|





|
|

|







|


|



|







|
|
|

|




|
|
|
|
|

|
|
|
|


|




|
|
|
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
<
>
|
|
|
<
>
|
|
<
>
|
|
<
>
|

|

|



|
|

|


|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161

162
163
164
165

166
167
168
169

170
171
172
173

174
175
176

177
178
179

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200

# TIP 324: A Standard Dialog For Font Selection

	Author:         Adrian Robert <[email protected]>
	Author:         Daniel A. Steffen <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        08-Aug-2008
	Post-History:   
	Keywords:       Tk
	Obsoletes:      213
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes the addition of a font selection dialog to the set of common
dialogs already available in Tk. Where possible, this dialog will be
implemented using the host platform's standard dialogs.

# Rationale

A number of platforms \(including Windows and Mac OS X\) have standard dialogs
for common user-oriented tasks, for which Tk provides an interface via commands
such as **tk\_getOpenFile** and **tk\_chooseColor**.
Another dialog that these platforms provide and which some Tk programs would
find useful is a _standard font selector_.
This TIP proposes adding a command to Tk to allow access to the platform
font selection dialog where available, or to a dialog implemented in Tcl
otherwise.

Unlike the existing dialog commands, the new font dialog command will not
return a result, as on some platforms \(Mac OS X\) the standard font dialog is
modeless while on others \(Windows\) it is modal. To accommodate this difference,
all user interaction with the dialog will be communicated to the caller via
callbacks or virtual events. To emphasize this difference in operation between
the new command and the existing Tk dialog commands the proposed name is **tk
fontchooser** instead of e.g. **tk\_chooseFont**.

# Proposal

Tk shall have a new command ensemble **tk fontchooser** with the following
syntax:

 > **tk fontchooser configure** ?_-option value -option value ..._?

set or query one or more of the configurations options below \(analogous to Tk
widget configuration\).

 > **tk fontchooser show**

show the font selection dialog. Depending on the platform, may return
immediately or only once the dialog has been withdrawn.

 > **tk fontchooser hide**

hide the font selection dialog if it is visible and cause any pending
**tk fontchooser show** command to return.

## Configuration Options

 -parent: specifies/returns the parent window of the font selection dialog
 \(similar to the _-parent_ option to other dialogs\).

 -title: specifies/returns the title of the dialog. Has no effect on platforms
 where the font selection dialog does not support titles.

 -font: specifies/returns the font that is currently selected in the dialog if
 it is visible, or that will be initially selected when the dialog is shown \(if
 supported by the platform\). Can be set to the empty string to indicate that no
 font should be selected. Fonts can be specified in any form given by the "FONT
 DESCRIPTION" section in font\(n\).

 -command: specifies/returns the command prefix to be called when a font
 selection has been made by the user. The command prefix is evaluated at the
 global level after having the specification of the selected font appended. On
 platforms where the font selection dialog offers the user control of further
 font attributes \(such as color\), additional key/value pairs may be appended
 before evaluation. Can be set to the empty string to indicate that no callback
 should be invoked. Fonts are specified by a list of form [[3]](3.md) of the "FONT
 DESCRIPTION" section in font\(n\) \(i.e. a list of the form _\{family size style
 ?style ...?\}_\).

 -visible: read-only option that returns a boolean indicating whether the font
 selection dialog is currently visible. Attempting to set this option results
 in an error.

## Events

<<TkFontchooserVisibility>>

 > virtual event sent to the dialog parent whenever the visibility of the font
 selection dialog changes, both as a result of user action \(e.g. disposing of
 the dialog via OK/Cancel button or close box\) and of the **tk fontchooser
 show/hide** commands being called. Binding scripts can determine the current
 visibility of the dialog by querying the _-visible_ configuration option.

<<TkFontchooserFontChanged>>

 > virtual event sent to the dialog parent whenever the font selection dialog
 is visible and the selected font changes, both as a result of user action and
 of the _-font_ configuration option being set. Binding scripts can determine
 the currently selected font by querying the _-font_ configuration option.

# Notes

Whenever a platform provides a suitable font dialog in its  API, Tk
shall not use a script-based alternative, even if this means missing
out on features like the title or dynamic updating of the font during
the selection process. This will help to ensure Tk applications meet
platform-specific user-interface design guidelines.

Callers should not expect a result from **tk fontchooser show** and may not
assume that the dialog has been withdrawn or closed when the command returns.
All user interaction with the dialog is communicated to the caller via the
_-command_ callback and the _<<TkFontchooser\*>>_ virtual events. It is
implementation dependent which exact user actions result in the callback being
called resp. the virtual events being sent. Where an Apply or OK button is
present in the dialog, it is expected for that button to trigger the
_-command_ callback and _<<TkFontchooserFontChanged>>_ virtual event.
However, on some implementations other user actions may also have that effect;
on Mac OS X for instance, the standard font selection dialog immediately
reflects all user choices to the caller.

In the presence of multiple widgets intended to be influenced by the font
selection dialog, care needs to be taken to correctly handle focus changes: the
font selected in the dialog should always match the current font of the widget
with the focus, and the _-command_ callback should only act on the widget
with the focus. The recommended practice is to set font dialog _-font_ and
_-command_ configuration options in per-widget _<FocusIn>_ handlers \(and if
necessary to unset them - i.e. set to the empty string - in corresponding
_<FocusOut>_ handlers\). This is particularly important for implementors of
library code using the font selection dialog, to avoid conflicting with
application code that may also want to use the dialog.

Because the font selection dialog is application-global, in the presence of
multiple interpreters calling **tk fontchooser**, only the _-command_
callback set by the interpreter that most recently called **tk fontchooser
configure** or **tk fontchooser show** will be invoked in response to user
action and only the _-parent_ set by that interpreter will receive
_<<TkFontchooser\*>>_ virtual events.

The font dialog implementation may only store \(and return\) **font actual**
data as the value of the _-font_ configuration option. This can be an issue
when _-font_ is set to a named font, if that font is subsequently changed,
the font dialog _-font_ option needs to be set again to ensure its selected
font matches the new value of the named font.

# Example

The following example demonstrates the recommended practice of updating the
font dialog configuration with the focus:

	 proc tip324demo {} {
	     wm title . "TIP324 Demo"
	     tk fontchooser configure -parent .
	     button .b -command fcToggle -takefocus 0; fcVisibility .b
	     bind . <<TkFontchooserVisibility>> [list fcVisibility .b]
	     foreach w {.t1 .t2} {
	         text $w -width 20 -height 4 -borderwidth 1 -relief solid
	         bind $w <FocusIn> [list fcFocus $w]
	         $w insert end "Text Widget $w"

	     }
	     .t1 configure -font {Courier 14}
	     .t2 configure -font {Times 16}
	     pack .b .t1 .t2; focus .t1

	 }
	 proc fcToggle {} {
	     tk fontchooser [expr {[tk fontchooser configure -visible] ?
	             "hide" : "show"}]

	 }
	 proc fcVisibility {w} {
	     $w configure -text [expr {[tk fontchooser configure -visible] ?
	             "Hide Font Dialog" : "Show Font Dialog"}]

	 }
	 proc fcFocus {w} {
	     tk fontchooser configure -font [$w cget -font] -command [list fcFont $w]

	 }
	 proc fcFont {w font args} {
	     $w configure -font [font actual $font]

	 }
	 tip324demo

# Alternatives

[[213]](213.md) was an earlier proposal for a font selection dialog API, it was withdrawn
when it became clear that it was incompatible with platforms where the standard
font dialog is modeless.

Alternative names for the new command have been proposed: **tk::choosefont**,
**tk::chooseFont**, **tk::fontChooser**, **tk\_chooseFont**.

# Reference Implementation

Tk Patch 1477426
<http://sourceforge.net/support/tracker.php?aid=1477426> 

# Copyright

This document has been placed in the public domain.

Name change from tip/325.tip to tip/325.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

TIP:		325
Title:		System Tray Access
Version:	$Revision: 1.2 $
Author:		David N. Welton <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Created:	25-Aug-2008
Post-History:	
Keywords:	Tk, desktop integration


~ Abstract

Modern operating systems have a "system tray", where programs may place an
icon to indicate program status. This TIP proposes that Tk should adopt some
existing code in order to permit cross platform access to this functionality.

~ Existing code

 * Windows: winico

 * Linux: tktray

 * Mac: ???

Existing code is sufficient, and utilizes an acceptable license in order to
repurpose it for a systray command.

~ Interface

To be determined by the TCT, but along the lines of what tktray provides:

 > '''tktray::icon''' ''pathName'' ?''options''?

Create a new icon for the system tray. The application managing the system
tray is notified about the new icon. It normally results in the icon being
added to the tray. If there is no system tray at the icon creation time, the
icon will be invisible. When a new system tray appears, the icon will be added
to it. Options:

 -class: WM_CLASS attribute for the icon window. Tray manager may use
         class name to remember icon position or other attributes.

 -image: image to show in the system tray. The value must be the name of a
         photo image. Transparency data of the photo are used to set the
         window's shape. The icon will be automatically redrawn or resized
         appropriately on any image modifications.

 -visible: boolean value indicating whether the icon must be visible. The
         system tray manager continues to manage the icon whether it is
         visible or not. Thus when invisible icon becomes visible, its
         position on the system tray is likely to remain the same.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|










|



|







|












|


>

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

# TIP 325: System Tray Access

	Author:		David N. Welton <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Created:	25-Aug-2008
	Post-History:	
	Keywords:	Tk, desktop integration
-----

# Abstract

Modern operating systems have a "system tray", where programs may place an
icon to indicate program status. This TIP proposes that Tk should adopt some
existing code in order to permit cross platform access to this functionality.

# Existing code

 * Windows: winico

 * Linux: tktray

 * Mac: ???

Existing code is sufficient, and utilizes an acceptable license in order to
repurpose it for a systray command.

# Interface

To be determined by the TCT, but along the lines of what tktray provides:

 > **tktray::icon** _pathName_ ?_options_?

Create a new icon for the system tray. The application managing the system
tray is notified about the new icon. It normally results in the icon being
added to the tray. If there is no system tray at the icon creation time, the
icon will be invisible. When a new system tray appears, the icon will be added
to it. Options:

 -class: WM\_CLASS attribute for the icon window. Tray manager may use
         class name to remember icon position or other attributes.

 -image: image to show in the system tray. The value must be the name of a
         photo image. Transparency data of the photo are used to set the
         window's shape. The icon will be automatically redrawn or resized
         appropriately on any image modifications.

 -visible: boolean value indicating whether the icon must be visible. The
         system tray manager continues to manage the icon whether it is
         visible or not. Thus when invisible icon becomes visible, its
         position on the system tray is likely to remain the same.

# Copyright

This document has been placed in the public domain.

Name change from tip/326.tip to tip/326.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

TIP:		326
Title:		Add -stride Option to lsort
Version:	$Revision: 1.5 $
Author:		Kieran Elby <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Created:	01-Sep-2008
Keywords:	Tcl, lsort, sorting
Post-History:


~ Abstract

This TIP adds a new option, '''-stride''', to '''lsort''' to request that a
list be treated as consisting of repeated groups of elements (as opposed to
sublists), and that the the groups be sorted according to a chosen element
within each group.

~ Rationale

Flat name-value pair lists are common in Tcl - consider the output of '''array
get''' and '''dict create''' or the input to '''foreach'''.

It is surprising then that there is no command to directly sort such a list by
either the name or the value elements, while preserving the name-value
mapping.

Doing so currently requires turning a name-value pair list into a list of
sublists, using the '''lsort''' ''-index'' option to sort them, then
flattening the list again, which is rather fiddly and inefficient.

While sorting name-value pair lists is no doubt the most common use case,
lists containing groups of more than two elements are also reasonably common,
and so providing support for groups of any size seems useful and no harder to
implement.

The option format follows the Feature Request here:
https://sourceforge.net/support/tracker.php?aid=747083

~ Proposed Change

A new option, '''-stride''', taking one parameter, ''grpSize'' will be added
to the '''lsort''' command.

If '''-stride''' is supplied, the list will be treated as consisting of groups
of ''grpSize'' elements, and the groups will be sorted by either their first
element or, if the '''-index''' option is used, by the element within each
group given by the first index passed to '''-index''' (which is then ignored
by '''-index''').

Elements always remain in the same position within their group.

The list length must be a multiple of ''grpSize'', which in turn must be at
least 2.

~ Examples

| lsort -stride 2 {carrot 10 apple 50 banana 25}

returns "apple 50 banana 25 carrot 10"

| lsort -stride 2 -index 1 -integer {carrot 10 apple 50 banana 25}

returns "carrot 10 banana 25 apple 50"

| lsort -stride 3 -index {0 1} {{Bob Smith} 25 Audi {Jane Doe} 40 Ford}

returns "{Jane Doe} 40 Ford {Bob Smith} 25 Audi" (since Smith, which is at
index 1 of element 0 of the first group comes after Doe, which is at the same
position in the next group of 3.)

~ Reference Implementation

Available online at https://sourceforge.net/support/tracker.php?aid=2082681

~ Compatibility

Since this is a new and unambiguous option, and since the distinction between
the options and the list to sort is clear, no compatibility problems are
expected.

~ Limitations

Only one element in each group can be used for comparison; it's not possible
to compare groups element-by-element.

~ Further Thoughts

There may be some merit in adding a similar option to '''lsearch'''.

The name-value pair case is common enough that an argument could be made for
adding '''-pairname''' and '''-pairvalue''' options as synonyms for '''-stride
2 -index 0''' and '''-stride 2 -index 1''' respectively.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|
|


|

|
|






|








|

|

|
|

|
|
|
|
|



|


|

|



|



|

|

|

|

|

|





|




|

|


|
|

|


>

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

# TIP 326: Add -stride Option to lsort

	Author:		Kieran Elby <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Done
	Created:	01-Sep-2008
	Keywords:	Tcl, lsort, sorting
	Post-History:
-----

# Abstract

This TIP adds a new option, **-stride**, to **lsort** to request that a
list be treated as consisting of repeated groups of elements \(as opposed to
sublists\), and that the the groups be sorted according to a chosen element
within each group.

# Rationale

Flat name-value pair lists are common in Tcl - consider the output of **array
get** and **dict create** or the input to **foreach**.

It is surprising then that there is no command to directly sort such a list by
either the name or the value elements, while preserving the name-value
mapping.

Doing so currently requires turning a name-value pair list into a list of
sublists, using the **lsort** _-index_ option to sort them, then
flattening the list again, which is rather fiddly and inefficient.

While sorting name-value pair lists is no doubt the most common use case,
lists containing groups of more than two elements are also reasonably common,
and so providing support for groups of any size seems useful and no harder to
implement.

The option format follows the Feature Request here:
<https://sourceforge.net/support/tracker.php?aid=747083>

# Proposed Change

A new option, **-stride**, taking one parameter, _grpSize_ will be added
to the **lsort** command.

If **-stride** is supplied, the list will be treated as consisting of groups
of _grpSize_ elements, and the groups will be sorted by either their first
element or, if the **-index** option is used, by the element within each
group given by the first index passed to **-index** \(which is then ignored
by **-index**\).

Elements always remain in the same position within their group.

The list length must be a multiple of _grpSize_, which in turn must be at
least 2.

# Examples

	 lsort -stride 2 {carrot 10 apple 50 banana 25}

returns "apple 50 banana 25 carrot 10"

	 lsort -stride 2 -index 1 -integer {carrot 10 apple 50 banana 25}

returns "carrot 10 banana 25 apple 50"

	 lsort -stride 3 -index {0 1} {{Bob Smith} 25 Audi {Jane Doe} 40 Ford}

returns "\{Jane Doe\} 40 Ford \{Bob Smith\} 25 Audi" \(since Smith, which is at
index 1 of element 0 of the first group comes after Doe, which is at the same
position in the next group of 3.\)

# Reference Implementation

Available online at <https://sourceforge.net/support/tracker.php?aid=2082681>

# Compatibility

Since this is a new and unambiguous option, and since the distinction between
the options and the list to sort is clear, no compatibility problems are
expected.

# Limitations

Only one element in each group can be used for comparison; it's not possible
to compare groups element-by-element.

# Further Thoughts

There may be some merit in adding a similar option to **lsearch**.

The name-value pair case is common enough that an argument could be made for
adding **-pairname** and **-pairvalue** options as synonyms for **-stride
2 -index 0** and **-stride 2 -index 1** respectively.

# Copyright

This document has been placed in the public domain.

Name change from tip/327.tip to tip/327.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

TIP:            327
Title:          Proper Tailcalls
Version:        $Revision: 1.8 $
Author:         Miguel Sofer <[email protected]>
Author:         David S. Cargo <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        20-Sep-2008
Post-History:   
Keywords:       tailcall,NRE
Tcl-Version:    8.6


~ Abstract

This TIP recommends adding proper tailcalls to Tcl.

~ Proposal

We propose to add a new command:

 > '''tailcall''' ''cmd'' ?''arg ...''?

The command can only be invoked in a procedure or lambda body.

The effect of this command is very similar to:

 > '''return [[uplevel 1 [[list [[namespace which''' ''cmd'' ''']]'''
   ?''arg ...''?''']]]]'''

with the sole exception that the invocation of ''cmd'' happens ''after'' the
currently executing body returns and is not visible in Tcl's call stack.

~ Rationale

The new Non-Recursive Engine (NRE) implemented in Tcl 8.6 allows support for a
number of interesting features that have previously been difficult or
impossible to implement efficiently in Tcl. One such feature is support for
''proper tailcalls'', an important feature for functional-style programming.
The new command allows unbounded recursion and enables programming in
''continuation passing style''.

~ Effect on Tcl's Call Stack

'''tailcall''' is implemented as a new command, as opposed to an optimization
that would be done automatically by the bytecode compiler, due to the effect
it has on Tcl's call stack.

Consider the following example:

| proc showStack {} {
|     set depth [info frame]
|     set res {}
|     for {set i 1} {$i <= $depth} {incr i} {
| 	lappend res [info frame $i]
|     }

|     return $res
| }

| 
| proc one cmd {join [$cmd] \n}
| proc two {} {uplevel 1 showStack}
| proc three {} {tailcall showStack}

When run at the interactive prompt, we obtain

| % one two
| type eval line 1 cmd {one two} level 2
| type proc line -1 cmd {$cmd} proc ::one level 1
| type proc line 1 cmd {uplevel 1 showStack} proc ::two
| type eval line 1 cmd showStack proc ::two
| type proc line 5 cmd {info frame $i} proc ::showStack level 0
| % one three
| type eval line 1 cmd {one three} level 2
| type proc line -1 cmd {$cmd} proc ::one level 1
| type proc line 5 cmd {info frame $i} proc ::showStack level 0
| % 


Remark how '''tailcall''' completely removed the proc ''three'' from Tcl's
call stack. This effect is also apparent on error traces.

~ Implementation

An experimental implementation of tailcalls is available in Tcl 8.6a2 in CVS
on sourceforge, in the ::tcl::unsupported namespace.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|



|



|





|
|

|


|

|


|

|

|

|





|
|
|
|
|
<
>
|
<
>
|
|
|
|



|
|
|
|
|
|
|
|
|
|
<
|
>
|


|




|


>

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

# TIP 327: Proper Tailcalls

	Author:         Miguel Sofer <[email protected]>
	Author:         David S. Cargo <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        20-Sep-2008
	Post-History:   
	Keywords:       tailcall,NRE
	Tcl-Version:    8.6
-----

# Abstract

This TIP recommends adding proper tailcalls to Tcl.

# Proposal

We propose to add a new command:

 > **tailcall** _cmd_ ?_arg ..._?

The command can only be invoked in a procedure or lambda body.

The effect of this command is very similar to:

 > **return [uplevel 1 [list [namespace which** _cmd_ **]**
   ?_arg ..._?**]]**

with the sole exception that the invocation of _cmd_ happens _after_ the
currently executing body returns and is not visible in Tcl's call stack.

# Rationale

The new Non-Recursive Engine \(NRE\) implemented in Tcl 8.6 allows support for a
number of interesting features that have previously been difficult or
impossible to implement efficiently in Tcl. One such feature is support for
_proper tailcalls_, an important feature for functional-style programming.
The new command allows unbounded recursion and enables programming in
_continuation passing style_.

# Effect on Tcl's Call Stack

**tailcall** is implemented as a new command, as opposed to an optimization
that would be done automatically by the bytecode compiler, due to the effect
it has on Tcl's call stack.

Consider the following example:

	 proc showStack {} {
	     set depth [info frame]
	     set res {}
	     for {set i 1} {$i <= $depth} {incr i} {
	 	lappend res [info frame $i]

	     }
	     return $res

	 }
	 
	 proc one cmd {join [$cmd] \n}
	 proc two {} {uplevel 1 showStack}
	 proc three {} {tailcall showStack}

When run at the interactive prompt, we obtain

	 % one two
	 type eval line 1 cmd {one two} level 2
	 type proc line -1 cmd {$cmd} proc ::one level 1
	 type proc line 1 cmd {uplevel 1 showStack} proc ::two
	 type eval line 1 cmd showStack proc ::two
	 type proc line 5 cmd {info frame $i} proc ::showStack level 0
	 % one three
	 type eval line 1 cmd {one three} level 2
	 type proc line -1 cmd {$cmd} proc ::one level 1
	 type proc line 5 cmd {info frame $i} proc ::showStack level 0

	 % 

Remark how **tailcall** completely removed the proc _three_ from Tcl's
call stack. This effect is also apparent on error traces.

# Implementation

An experimental implementation of tailcalls is available in Tcl 8.6a2 in CVS
on sourceforge, in the ::tcl::unsupported namespace.

# Copyright

This document has been placed in the public domain.

Name change from tip/328.tip to tip/328.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196


197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233

234
235
236
237
238

239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301


302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335

336
337
338
339
340
341
342
343

344
345
346
347

348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371

372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450

TIP:            328
Title:          Coroutines
Version:        $Revision: 1.6 $
Author:         Miguel Sofer <[email protected]>
Author:         Neil Madden <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        07-Sep-2008
Post-History:   
Keywords:       Coroutine,continuation,event-loop,NRE
Tcl-Version:    8.6


~ Abstract

This TIP recommends adding a coroutine mechanism to Tcl, loosely modelled on
those present in Lua.

~ Rationale

The new Non-Recursive Engine (NRE) implemented in Tcl 8.6 allows support for a
number of interesting features which have previously been difficult or
impossible to implement efficiently in Tcl. One such feature is support for
''coroutines'', which generalise the notion of subroutine by allowing a
command to return multiple times. Conceptually, a coroutine allows a command
to suspend its current execution and return (or ''yield'') a value to its
caller. The caller may later ''resume'' the coroutine at the point where it
previously yielded, allowing it to perform further work and potentially yield
further values. Coroutines have applications to a number of areas, in
particular they allow a more natural representation of certain programming
tasks when using the event loop, such as interacting with a Tk graphical user
interface, performing asynchronous remote procedure calls, communicating
between threads, and lightweight cooperative multitasking. These use-cases are
discussed in more detail in the next section, along with a look at the
limitations of the proposed approach, particularly in comparison to the
closely related concept of ''continuations''.

It should be noted that coroutines (or continuations) add no extra power to
the language. Every computation that can be expressed with corouines can be
expressed using existing features of the language by writing code in so-called
''continuation-passing style'' (CPS), which is the style of code used in loops
and other control constructs. Rather, the benefit of coroutines is that it
allows certain problems to be expressed more succinctly in cases where the CPS
form is tedious to construct, or would require extensive refactoring of
existing code. For instance, we can consider the following simple program that
asks a user for two numbers and then displays their sum:

| proc tell msg { puts $msg }
| proc ask question {
|     puts -nonewline "$question "
|     flush stdout
|     gets stdin
| }

| proc main {} {
|     set x [ask "First number:"]
|     set y [ask "Second number:"]
|     tell "Sum = [expr {$x + $y}]"
| }

| main

In converting this code to work with a Tk GUI or some other asynchronous
interface (such as a Web application) would generally require restructing the
'''ask''' procedure to take a callback, and then restructuring the main
application logic to supply these callbacks. This restructuring when moving
from a synchronous to an asynchronous interface hinders such refactoring and
also causes the application logic to become fragmented into a number of
callback procedures. While anonymous procedures introduced in Tcl 8.5 can
mitigate these drawbacks to some extent, there is still some obfuscation of
the original code. The coroutine mechanism proposed would allow the interface
of the '''tell''' and '''ask''' procedures to remain unchanged, and the main
application logic to remain identical (beyond some trivial wrapping). It is
this ability of coroutines to convert synchronous code to work in an
asynchronous manner with minimal changes to the application logic that is the
main motivating use-case for their consideration. Coroutines can also benefit
new asynchronous code that is written from scratch, as the familiar ''direct
style'' of coding that they enable is clearer to understand in many cases, and
to some extent hides the complexity of the underlying asynchronous model. This
added expressiveness helps the Tcl programmer to separate logic from control
(Kowalksi, 1979).

The particular style of coroutines proposed are loosely based on the
equivalent mechanism implemented in the Lua programming language (Lua, 2004).
In particular, the coroutines implemented are ''asymmetric'' (yield and resume
are separate commands), and ''stackful'' (yield can be called from any stack
depth in the coroutine body). Asymmetric coroutines (similar to
''generators'') can simulate symmetric coroutines and vice-versa.

~ New Commands and Subcommands

 > '''coroutine''' ''coroCmdName'' '''cmd''' ?''arg ...''?

 > '''yield''' ?''value''?

 > ''coroCmdName'' ?''value''?

 > '''info coroutine'''

'''coroutine''' evaluates the Tcl command 

 > '''uplevel #0 [[list''' ''cmd'' ?''arg ...''?''']]''' 

until it returns or a yield is encountered. If '''yield''' is found then a
command named ''coroCmdName'' will be created with special behaviour as
described below.

'''yield''' suspends execution of the coroutine and returns ''returnValue'' to
the coroutine caller (not the creator, which may be long dead) as the return
value of the '''coroutine''' or '''coroCmdName''' invocation. It is an error
to invoke yield outside of a coroutine's body. It is possible to yield from
within a nested call, but under some circumstances yield can return an error
(see Limitations).

''coroCmdName'' resumes execution of the suspended coroutine. Execution of the
suspended coroutine resumes with returnValue being the return value of the
yield that last suspended execution. ''coroCmdName'' is garbage-collected: the
command and all internal structs are deleted when the coroutine returns. A
suspended coroutine is properly cleaned up when its command is rename'd to the
empty string.

'''info coroutine''' returns the fully qualified name of the command that will
resume the currently executing coroutine if it yields. In other words, it
returns ''coroCmdName'' when invoked in a suspendable environment, and the
empty string otherwise.

Whenever  '''coroCmdName''' is invoked and the coroutine itself is running,
Tcl's call stack looks exactly as if 

 > '''uplevel #0 [[list''' ''cmd'' ?''arg ...''?''']]''' 

had been invoked instead. This structure is properly reflected in '''info
level''', '''info frame''' and the error stack.

~ Use Cases

In this section we review a number of motivating use-cases for coroutines.

~~ Tk Graphical User Interfaces

As mentioned in the introduction, one particularly useful application of
continuations in Tcl is to allow essentially asynchronous operations, using
the event loop, to provide a familiar interface, much like synchronous
operations. The example '''tell''' and '''ask''' interface can be written
using yields to return control temporarily to the event loop until a result is
available. This is similar to use of '''vwait''', but avoids creating a nested
event loop, with all the problems that entails:

| proc tell msg { tk_messageBox -message $msg }
| proc ask question {
|     toplevel .ask
|     pack [label .ask.l -text $question] [entry .ask.e]
|     raise .ask; focus .ask.e
|     bind .ask.e <Return> [list apply {cb {
|         set ans [.ask.e get]
|         destroy .ask
|         $cb $ans
|     }} [info coroutine]]
|     yield
| }

| # ... main as before ...
| coroutine main-coro main

The original '''main''' procedure can be reused as-is. The only constraint is
that it must be launched as a coroutine using the '''coroutine''' command. The
operation of the code should be straight-forward to understand, as it is
mostly standard Tk code. The '''ask''' command simply creates a Tk dialog box
and registers the current coroutine as an event callback for when the user
enters a number. Finally the procedure calls '''yield''' which suspends the
current coroutine (in this case the main procedure) and allows the event loop
to run.  Once the user has entered a value and hit Return the coroutine is
invoked with the value. This resumes the main procedure, returing this value
as the return value of '''ask'''. From the point of view of the main routine
it is as if the ask procedure worked exactly like the synchronous,
console-based example.

~~ Complex Iterators

Another common use of coroutines is to support efficient traversal of complex
data structures. Here the coroutine is used to implement a stateful
''iterator'' for the data structure. In Tcl, one of the most natural and
simple ways of writing a traversal interface for a data structure is as a
custom control structure or loop. For instance, we can write a simple command
for traversing a binary search tree in-order, applying a function to each
value:

| # Constructor functions for our BST
| proc cons {name args} { proc $name $args { info level 0 } }
| cons Empty
| cons Branch left val right
| 
| proc bst-map {f tree} {
|     if {[lindex $tree 0] eq "Branch"} {
|         bst-map $f [lindex $tree 1]
|         {*}$f [lindex $tree 2]
|         bst-map $f [lindex $tree 3]
|     }
| }


| # Print every value in the tree in order
| bst-map puts $tree

While such interfaces are convenient for traversing a single data structure,
they are more difficult to use when traversing multiple structures
simultaneously, as when merging trees. A coroutine interface allows such
custom loops to be easily converted into stateful iterators, allowing a merge
to be written in a reasonably straight-forward fashion:

| proc bst-merge-map {f t1 t2} {
|     set a [coroutine l bst-map yield $t1]
|     set b [coroutine r bst-map yield $t2]
|     while {[valid l] || [valid r]} {
|         if {[valid l] && (![valid r] || $a < $b)} {
|             {*}$f $a; set a [l]
|         } else {
|             {*}$f $b; set b [r]
|         }
|     }
| }



| proc valid cmd { llength [info commands $cmd] }
| bst-merge-map puts $t1 $t2

The benefit here is that the simple single-tree traversal function can be
reused for merging multiple trees, simply by wrapping it in a coroutine.

~~ Asynchronous Communications

Similar to the use of coroutines for event-based GUI programming, we can also
use the mechanism for asynchronous networking, such as fetching data over
HTTP, making remote procedure calls, and message-passing between threads. For
example, asynchronous HTTP requests become as simple as synchronous ones:

| proc get url {
|     http::geturl $url -command [info coroutine]
|     yield
| }

| proc main {} {
|     set t [get http://wiki.tcl.tk/4]
|     puts [http::data $t]
|     http::cleanup $t
| }

| coroutine m main

This common pattern of registering the current coroutine as a callback and
then yielding can be used to accomplish a wide variety of such tasks.

~ Limitations

The coroutine implementation depends on the NRE enhancements recently made to
the Tcl core. In particular, in order to capture a coroutine it is essential
that all commands currently on the evaluation stack are NRE-aware. This is the
case for most core Tcl commands, but at the time of writing few extensions
will have made this transition. In these cases, trying to capture a coroutine
while in an evaluation context containing a non-NRE-aware C command will
result in an error. This situation is currently unavoidable, but we believe
that it will improve over time as extensions are adapted to take advantage of
the new features that NRE enables. In the meantime, the coroutine mechanism is
still useful in a wide variety of situations, and the cases where it is not
applicable should be easy to detect, as the code will fail immediately on
trying to capture a coroutine. Nevertheless, library writers should be aware
of the situation and avoid over reliance on coroutines. It is easy to wrap
coroutine interfaces around existing callback-based library routines (as in
the HTTP example).

Coroutines are roughly equivalent in expressive power to ''one-shot
continuations''. A continuation is simply a function that represents the rest
of a computation. Continuations can be explicitly created, as in continuation-
passing style (CPS) code, but some languages (notably Lisp and Scheme) allow
the current execution context to be automatically captured as a continuation
with a similar effect to coroutines. Such continuations can either be invoked
once (a one-shot continuation) or several times (multi-shot). One-shot
continuations can be used for much the same tasks that we have identified in
this TIP, and can also be used to implement coroutines. Coroutines can
likewise implement one-shot continuations. Multi-shot continuations, however,
are strictly more expressive than either coroutines or one-shot continuations
as they allow the same continuation to be resumed multiple times. In contrast,
when a coroutine yields it can only be resumed once, and then must call yield
again. An example of a construct that cannot be implemented using coroutines
is a nondeterministic choice operator:

| set x [choose 1 2 3 4]
| set y [choose 3 9 7]
| if {$x**2 != $y} { fail }
| puts "x=$x,y=$y"

Intuitively, we would like this code to eventually succeed with values ''x =
3'' and ''y = 9''. However it is not possible to implement '''choose''' using
coroutines as we can only yield from inside the choose statement once, and
then are forced to yield instead from within '''fail''', which is incorrect. A
multi-shot continuation is capable of implementing '''choose''' as it can
resume the ''same'' continuation multiple times with different values,
essentially allowing the code to jump back to the appropriate choose statement
for each back-track.

While a non-deterministic choice operator is an interesting use-case, it is
not considered a primary motivation for this TIP. Such nondeterministic
searches can be implemented using loops or custom control structures and
exceptions (this essentially amounts to using CPS). For instance:

| foreach x {1 2 3 4} {
|     foreach y {3 9 7} {
|         if {$x**2 == $y} { puts "x=$x,y=$z" }
|     }
| }



Furthermore, support for multi-shot continuations is believed to be more
expensive to implement than coroutines, as the execution environment has to be
copied for each continuation point, whereas a coroutine reuses the same
environment for multiple yield/resume pairs. It is believed that the vast
majority of useful use-cases will fall into the expressive power of
coroutines. However, this limitation is real and should be taken into account
when considering this TIP.

A final apparent limitation of the proposed mechanism is that it only supports
passing a single argument when resuming a coroutine. The reason for this is
simply that '''yield''' only returns a single result, and so a single argument
is all that is required. It is believed that this will be sufficient for the
majority of use-cases. However, in cases where multiple arguments are
required, it is straight-forward to wrap the coroutine resume command so that
these are passed as a list:

| proc resume {coro args} { $coro $args }

The coroutine body can then use '''lassign''', '''lindex''' or some other
means to extract the arguments. This can be used, for instance, when using a
coroutine for variable tracing, such as in Colin Macleod's coroutine-enabled
version of '''vwait''' that avoids nesting event loops
[http://wiki.tcl.tk/21555]:

| proc co_vwait varName {
|     upvar $varName var
|     set callback [list resume [info coroutine]]
|     trace add    variable var write $callback
|     yield
|     trace remove variable var write $callback
| }

Along similar lines, the '''yield''' and ''coroCmdName'' commands currently do

not offer support for communicating exceptions to/from coroutines. As with
multiple arguments, this can be addressed by passing a dictionary of options
(as produced by '''catch''') as well as a value:

| proc exyield {value args} {
|     lassign [yield [list $value $args]] value opts
|     return -options $opts $value
| }

| proc exresume {coro value args} {
|     lassign [$coro [list $value $args]] value args
|     return -options $opts $value
| }

| # Usage
| proc mycoro {} { exyield $val -code error -errorcode $somecode ... }

It is expected that such wrappers can be added to Tcllib for now. Adding
support for these options directly to the yield and resume command interfaces
could be done in the future by a further TIP, if the functionality is deemed
sufficiently critical.

~ Alternatives

An alternative syntax for coroutines is described in (Lua, 2004) based on a
symmetric '''yield''' command. In this approach, '''yield''' takes as an extra
argument the name of a coroutine to pass control to, rather than implicitly
transferring control back to the caller. This eliminates the need for a
separate ''resume'' interface (the ''coroCmdName'' in the current TIP).
However, we believe that the asymmetric interface is more intuitive for most
tasks, and the fact that coroutines are stateful entities requires them to
have some named representation in any case, so this may as well be used as a
resume command.  It is possible to simulate symmetric coroutines with the
current proposal using a simple loop:

| proc run-coros {coro value} {
|     while 1 { lassign [$coro $value] coro value }
| }

| proc symyield {coro value} { yield [list $coro $value] }

An alternative to a coroutine mechanism would be to adopt some form of
''continuations'' into Tcl. As described previously, a continuation is a
command that captures the current state of a computation (i.e. the current
control stack and execution environment) and saves it so that it can be
resumed later. In this respect, a continuation is similar to a coroutine.
There are a number of varieties of continuations described in the literature
(see [http://library.readscheme.org/page6.html] for a collection of
references), with different expressive powers. ''Escape continuations'' only
allow jumping to a context which is still on the stack. Such continuations are
equivalent in power to exceptions, which Tcl already has. ''One-shot''
continuations can only be resumed once and are then discarded. As previously
stated, such continuations are equivalent to coroutines as any particular
'''yield''' can only be resumed once. ''Multi-shot'' continuations allow the
same continuation to be resumed multiple times. These continuations go beyond
the power of coroutines, and allow examples such as the nondeterministic
choice operator to be implemented. Multi-shot continuations are however rather
more expensive to implement, as each yield point requires creating a fresh
copy of the execution environment, whereas a coroutine can reuse the same
environment copy for multiple yield/resumes as it knows it cannot be resumed
more than once for a single yield. A further refinement is the idea of
''delimited continuations'' which capture only a certain portion of the
execution context (stack), rather than everything. Delimited continuations can
simulate normal continuations by simply capturing the entire dynamic extent,
but they have the advantage that they can also return a value, allowing them
to be composed. Coroutines are also of this form, where the extent of the
coroutine is limited to where the '''coroutine''' command was originally
called from. The coroutine mechanism proposed is therefore of roughly
equivalent power to a ''one-shot delimited continuation''. Such a mechanism is
strictly less powerful than a multi-shot continuation implementation, but it
is believed that it is sufficient to cover the vast majority of useful
use-cases, while remaining relatively simple to understand, and efficient to
implement.

Lars Hellstr�m has also proposed an alternative control mechanism for Tcl
(Hellstr�m, 2008), which is essentially a form of multi-shot full (non
delimited) continuation, based on an interface of two commands: '''suspend'''
and '''resume'''. The '''suspend''' command captures the current evaluation
context into a continuation and then throws this as an exception with a
special TCL_SUSPEND return code, allowing it to be caught and later resumed.
The interface supports communicating values and exceptions to the resumed
continuation. While the interface is potentially more expressive than the
coroutine mechanism here, the proposed implementation involves destroying the
stack as it is captured when the TCL_SUSPEND exception propagates. This
presents a number of practical problems, such as the destruction of local
variables (and thus the firing of unset traces), and the overall inefficiency
of the approach.  As coroutines thus captured are stateless objects they can
be implemented as plain Tcl values (i.e., strings), albeit potentially quite
large and complex ones. This provides the usual advantages of easy
serialisation and transfer, while suffering the usual drawbacks of lack of
encapsulation (potentially exposing implementation details) and potential
inefficiencies due to shimmering or excess copying of data (a general problem
of multi-shot continuations). While some of these problems can be limited or
overcome entirely, it is our view that the current coroutines proposal covers
a great deal of the expected use-cases in a much simpler and more efficient
manner.

~ Implementation

An experimental implementation of the coroutine mechanism is available in Tcl
8.6a2 in CVS on sourceforge. The implementation is available in the
::tcl::unsupported namespace, exposing the ''coroutine'', ''yield'', and
''infoCoroutine'' commands.

~ References

(Kowalski, 1979) Robert Kowalski, "Algorithm = logic + control",
''Communications of the ACM'' 22(7), pp. 424-436, 1979.

(Lua, 2004) Ana L�cia De Moura, Roberto Ierusalimschy, "Revisting Coroutines",
Tech Report, 2004. http://www.inf.puc-rio.br/~roberto/docs/MCC15-04.pdf

(Hellstr�m, 2008) Lars Hellstr�m, "Suspend and Resume",
http://wiki.tcl.tk/21537

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|




|

|


|

|
|








|

|


|






|
|
|
|
|
<
>
|
|
|
|
<
>
|


|
|






|
|



|
|


|


|
|
|
|
|

|

|

|

|

|

|

|

|
|


|
|
|


|

|

|




|

|


|


|

|
|

|



|




|

|


|
|
|
|
|
|
|
|
|
|
|
<
>
|
|

|
|

|

|
|


|



|



|





|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
|







|
|
|
|
|
|
|
|
<
<
<
>
>
>
|
|




|






|
|
|
<
>
|
|
|
|
<
>
|




|














|
|

|
|

|


|









|
|
|
|

|
|

|
|
|






|

|
|
|
<
<
>
>











|





|

|


|
|

|
|
|
|
|
|
<
|
|
>


|

|
|
|
<
>
|
|
|
<
>
|
|






|

|
|


|






|
|
<
>
|


|
|
|


|
|

|


|







|
|



|

|





|
|
|
|

|



|

|

|


|
|
|




|



|
|

|

|
|

|
|

|
|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193


194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231

232
233
234
235
236

237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298


299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

332
333
334
335
336
337
338
339
340
341

342
343
344
345

346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369

370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450

# TIP 328: Coroutines

	Author:         Miguel Sofer <[email protected]>
	Author:         Neil Madden <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        07-Sep-2008
	Post-History:   
	Keywords:       Coroutine,continuation,event-loop,NRE
	Tcl-Version:    8.6
-----

# Abstract

This TIP recommends adding a coroutine mechanism to Tcl, loosely modelled on
those present in Lua.

# Rationale

The new Non-Recursive Engine \(NRE\) implemented in Tcl 8.6 allows support for a
number of interesting features which have previously been difficult or
impossible to implement efficiently in Tcl. One such feature is support for
_coroutines_, which generalise the notion of subroutine by allowing a
command to return multiple times. Conceptually, a coroutine allows a command
to suspend its current execution and return \(or _yield_\) a value to its
caller. The caller may later _resume_ the coroutine at the point where it
previously yielded, allowing it to perform further work and potentially yield
further values. Coroutines have applications to a number of areas, in
particular they allow a more natural representation of certain programming
tasks when using the event loop, such as interacting with a Tk graphical user
interface, performing asynchronous remote procedure calls, communicating
between threads, and lightweight cooperative multitasking. These use-cases are
discussed in more detail in the next section, along with a look at the
limitations of the proposed approach, particularly in comparison to the
closely related concept of _continuations_.

It should be noted that coroutines \(or continuations\) add no extra power to
the language. Every computation that can be expressed with corouines can be
expressed using existing features of the language by writing code in so-called
_continuation-passing style_ \(CPS\), which is the style of code used in loops
and other control constructs. Rather, the benefit of coroutines is that it
allows certain problems to be expressed more succinctly in cases where the CPS
form is tedious to construct, or would require extensive refactoring of
existing code. For instance, we can consider the following simple program that
asks a user for two numbers and then displays their sum:

	 proc tell msg { puts $msg }
	 proc ask question {
	     puts -nonewline "$question "
	     flush stdout
	     gets stdin

	 }
	 proc main {} {
	     set x [ask "First number:"]
	     set y [ask "Second number:"]
	     tell "Sum = [expr {$x + $y}]"

	 }
	 main

In converting this code to work with a Tk GUI or some other asynchronous
interface \(such as a Web application\) would generally require restructing the
**ask** procedure to take a callback, and then restructuring the main
application logic to supply these callbacks. This restructuring when moving
from a synchronous to an asynchronous interface hinders such refactoring and
also causes the application logic to become fragmented into a number of
callback procedures. While anonymous procedures introduced in Tcl 8.5 can
mitigate these drawbacks to some extent, there is still some obfuscation of
the original code. The coroutine mechanism proposed would allow the interface
of the **tell** and **ask** procedures to remain unchanged, and the main
application logic to remain identical \(beyond some trivial wrapping\). It is
this ability of coroutines to convert synchronous code to work in an
asynchronous manner with minimal changes to the application logic that is the
main motivating use-case for their consideration. Coroutines can also benefit
new asynchronous code that is written from scratch, as the familiar _direct
style_ of coding that they enable is clearer to understand in many cases, and
to some extent hides the complexity of the underlying asynchronous model. This
added expressiveness helps the Tcl programmer to separate logic from control
\(Kowalksi, 1979\).

The particular style of coroutines proposed are loosely based on the
equivalent mechanism implemented in the Lua programming language \(Lua, 2004\).
In particular, the coroutines implemented are _asymmetric_ \(yield and resume
are separate commands\), and _stackful_ \(yield can be called from any stack
depth in the coroutine body\). Asymmetric coroutines \(similar to
_generators_\) can simulate symmetric coroutines and vice-versa.

# New Commands and Subcommands

 > **coroutine** _coroCmdName_ **cmd** ?_arg ..._?

 > **yield** ?_value_?

 > _coroCmdName_ ?_value_?

 > **info coroutine**

**coroutine** evaluates the Tcl command 

 > **uplevel \#0 [list** _cmd_ ?_arg ..._?**]** 

until it returns or a yield is encountered. If **yield** is found then a
command named _coroCmdName_ will be created with special behaviour as
described below.

**yield** suspends execution of the coroutine and returns _returnValue_ to
the coroutine caller \(not the creator, which may be long dead\) as the return
value of the **coroutine** or **coroCmdName** invocation. It is an error
to invoke yield outside of a coroutine's body. It is possible to yield from
within a nested call, but under some circumstances yield can return an error
\(see Limitations\).

_coroCmdName_ resumes execution of the suspended coroutine. Execution of the
suspended coroutine resumes with returnValue being the return value of the
yield that last suspended execution. _coroCmdName_ is garbage-collected: the
command and all internal structs are deleted when the coroutine returns. A
suspended coroutine is properly cleaned up when its command is rename'd to the
empty string.

**info coroutine** returns the fully qualified name of the command that will
resume the currently executing coroutine if it yields. In other words, it
returns _coroCmdName_ when invoked in a suspendable environment, and the
empty string otherwise.

Whenever  **coroCmdName** is invoked and the coroutine itself is running,
Tcl's call stack looks exactly as if 

 > **uplevel \#0 [list** _cmd_ ?_arg ..._?**]** 

had been invoked instead. This structure is properly reflected in **info
level**, **info frame** and the error stack.

# Use Cases

In this section we review a number of motivating use-cases for coroutines.

## Tk Graphical User Interfaces

As mentioned in the introduction, one particularly useful application of
continuations in Tcl is to allow essentially asynchronous operations, using
the event loop, to provide a familiar interface, much like synchronous
operations. The example **tell** and **ask** interface can be written
using yields to return control temporarily to the event loop until a result is
available. This is similar to use of **vwait**, but avoids creating a nested
event loop, with all the problems that entails:

	 proc tell msg { tk_messageBox -message $msg }
	 proc ask question {
	     toplevel .ask
	     pack [label .ask.l -text $question] [entry .ask.e]
	     raise .ask; focus .ask.e
	     bind .ask.e <Return> [list apply {cb {
	         set ans [.ask.e get]
	         destroy .ask
	         $cb $ans
	     }} [info coroutine]]
	     yield

	 }
	 # ... main as before ...
	 coroutine main-coro main

The original **main** procedure can be reused as-is. The only constraint is
that it must be launched as a coroutine using the **coroutine** command. The
operation of the code should be straight-forward to understand, as it is
mostly standard Tk code. The **ask** command simply creates a Tk dialog box
and registers the current coroutine as an event callback for when the user
enters a number. Finally the procedure calls **yield** which suspends the
current coroutine \(in this case the main procedure\) and allows the event loop
to run.  Once the user has entered a value and hit Return the coroutine is
invoked with the value. This resumes the main procedure, returing this value
as the return value of **ask**. From the point of view of the main routine
it is as if the ask procedure worked exactly like the synchronous,
console-based example.

## Complex Iterators

Another common use of coroutines is to support efficient traversal of complex
data structures. Here the coroutine is used to implement a stateful
_iterator_ for the data structure. In Tcl, one of the most natural and
simple ways of writing a traversal interface for a data structure is as a
custom control structure or loop. For instance, we can write a simple command
for traversing a binary search tree in-order, applying a function to each
value:

	 # Constructor functions for our BST
	 proc cons {name args} { proc $name $args { info level 0 } }
	 cons Empty
	 cons Branch left val right
	 
	 proc bst-map {f tree} {
	     if {[lindex $tree 0] eq "Branch"} {
	         bst-map $f [lindex $tree 1]
	         {*}$f [lindex $tree 2]
	         bst-map $f [lindex $tree 3]


	     }
	 }
	 # Print every value in the tree in order
	 bst-map puts $tree

While such interfaces are convenient for traversing a single data structure,
they are more difficult to use when traversing multiple structures
simultaneously, as when merging trees. A coroutine interface allows such
custom loops to be easily converted into stateful iterators, allowing a merge
to be written in a reasonably straight-forward fashion:

	 proc bst-merge-map {f t1 t2} {
	     set a [coroutine l bst-map yield $t1]
	     set b [coroutine r bst-map yield $t2]
	     while {[valid l] || [valid r]} {
	         if {[valid l] && (![valid r] || $a < $b)} {
	             {*}$f $a; set a [l]
	         } else {
	             {*}$f $b; set b [r]



	         }
	     }
	 }
	 proc valid cmd { llength [info commands $cmd] }
	 bst-merge-map puts $t1 $t2

The benefit here is that the simple single-tree traversal function can be
reused for merging multiple trees, simply by wrapping it in a coroutine.

## Asynchronous Communications

Similar to the use of coroutines for event-based GUI programming, we can also
use the mechanism for asynchronous networking, such as fetching data over
HTTP, making remote procedure calls, and message-passing between threads. For
example, asynchronous HTTP requests become as simple as synchronous ones:

	 proc get url {
	     http::geturl $url -command [info coroutine]
	     yield

	 }
	 proc main {} {
	     set t [get http://wiki.tcl.tk/4]
	     puts [http::data $t]
	     http::cleanup $t

	 }
	 coroutine m main

This common pattern of registering the current coroutine as a callback and
then yielding can be used to accomplish a wide variety of such tasks.

# Limitations

The coroutine implementation depends on the NRE enhancements recently made to
the Tcl core. In particular, in order to capture a coroutine it is essential
that all commands currently on the evaluation stack are NRE-aware. This is the
case for most core Tcl commands, but at the time of writing few extensions
will have made this transition. In these cases, trying to capture a coroutine
while in an evaluation context containing a non-NRE-aware C command will
result in an error. This situation is currently unavoidable, but we believe
that it will improve over time as extensions are adapted to take advantage of
the new features that NRE enables. In the meantime, the coroutine mechanism is
still useful in a wide variety of situations, and the cases where it is not
applicable should be easy to detect, as the code will fail immediately on
trying to capture a coroutine. Nevertheless, library writers should be aware
of the situation and avoid over reliance on coroutines. It is easy to wrap
coroutine interfaces around existing callback-based library routines \(as in
the HTTP example\).

Coroutines are roughly equivalent in expressive power to _one-shot
continuations_. A continuation is simply a function that represents the rest
of a computation. Continuations can be explicitly created, as in continuation-
passing style \(CPS\) code, but some languages \(notably Lisp and Scheme\) allow
the current execution context to be automatically captured as a continuation
with a similar effect to coroutines. Such continuations can either be invoked
once \(a one-shot continuation\) or several times \(multi-shot\). One-shot
continuations can be used for much the same tasks that we have identified in
this TIP, and can also be used to implement coroutines. Coroutines can
likewise implement one-shot continuations. Multi-shot continuations, however,
are strictly more expressive than either coroutines or one-shot continuations
as they allow the same continuation to be resumed multiple times. In contrast,
when a coroutine yields it can only be resumed once, and then must call yield
again. An example of a construct that cannot be implemented using coroutines
is a nondeterministic choice operator:

	 set x [choose 1 2 3 4]
	 set y [choose 3 9 7]
	 if {$x**2 != $y} { fail }
	 puts "x=$x,y=$y"

Intuitively, we would like this code to eventually succeed with values _x =
3_ and _y = 9_. However it is not possible to implement **choose** using
coroutines as we can only yield from inside the choose statement once, and
then are forced to yield instead from within **fail**, which is incorrect. A
multi-shot continuation is capable of implementing **choose** as it can
resume the _same_ continuation multiple times with different values,
essentially allowing the code to jump back to the appropriate choose statement
for each back-track.

While a non-deterministic choice operator is an interesting use-case, it is
not considered a primary motivation for this TIP. Such nondeterministic
searches can be implemented using loops or custom control structures and
exceptions \(this essentially amounts to using CPS\). For instance:

	 foreach x {1 2 3 4} {
	     foreach y {3 9 7} {
	         if {$x**2 == $y} { puts "x=$x,y=$z" }


	     }
	 }

Furthermore, support for multi-shot continuations is believed to be more
expensive to implement than coroutines, as the execution environment has to be
copied for each continuation point, whereas a coroutine reuses the same
environment for multiple yield/resume pairs. It is believed that the vast
majority of useful use-cases will fall into the expressive power of
coroutines. However, this limitation is real and should be taken into account
when considering this TIP.

A final apparent limitation of the proposed mechanism is that it only supports
passing a single argument when resuming a coroutine. The reason for this is
simply that **yield** only returns a single result, and so a single argument
is all that is required. It is believed that this will be sufficient for the
majority of use-cases. However, in cases where multiple arguments are
required, it is straight-forward to wrap the coroutine resume command so that
these are passed as a list:

	 proc resume {coro args} { $coro $args }

The coroutine body can then use **lassign**, **lindex** or some other
means to extract the arguments. This can be used, for instance, when using a
coroutine for variable tracing, such as in Colin Macleod's coroutine-enabled
version of **vwait** that avoids nesting event loops
<http://wiki.tcl.tk/21555> :

	 proc co_vwait varName {
	     upvar $varName var
	     set callback [list resume [info coroutine]]
	     trace add    variable var write $callback
	     yield
	     trace remove variable var write $callback

	 }

Along similar lines, the **yield** and _coroCmdName_ commands currently do
not offer support for communicating exceptions to/from coroutines. As with
multiple arguments, this can be addressed by passing a dictionary of options
\(as produced by **catch**\) as well as a value:

	 proc exyield {value args} {
	     lassign [yield [list $value $args]] value opts
	     return -options $opts $value

	 }
	 proc exresume {coro value args} {
	     lassign [$coro [list $value $args]] value args
	     return -options $opts $value

	 }
	 # Usage
	 proc mycoro {} { exyield $val -code error -errorcode $somecode ... }

It is expected that such wrappers can be added to Tcllib for now. Adding
support for these options directly to the yield and resume command interfaces
could be done in the future by a further TIP, if the functionality is deemed
sufficiently critical.

# Alternatives

An alternative syntax for coroutines is described in \(Lua, 2004\) based on a
symmetric **yield** command. In this approach, **yield** takes as an extra
argument the name of a coroutine to pass control to, rather than implicitly
transferring control back to the caller. This eliminates the need for a
separate _resume_ interface \(the _coroCmdName_ in the current TIP\).
However, we believe that the asymmetric interface is more intuitive for most
tasks, and the fact that coroutines are stateful entities requires them to
have some named representation in any case, so this may as well be used as a
resume command.  It is possible to simulate symmetric coroutines with the
current proposal using a simple loop:

	 proc run-coros {coro value} {
	     while 1 { lassign [$coro $value] coro value }

	 }
	 proc symyield {coro value} { yield [list $coro $value] }

An alternative to a coroutine mechanism would be to adopt some form of
_continuations_ into Tcl. As described previously, a continuation is a
command that captures the current state of a computation \(i.e. the current
control stack and execution environment\) and saves it so that it can be
resumed later. In this respect, a continuation is similar to a coroutine.
There are a number of varieties of continuations described in the literature
\(see <http://library.readscheme.org/page6.html>  for a collection of
references\), with different expressive powers. _Escape continuations_ only
allow jumping to a context which is still on the stack. Such continuations are
equivalent in power to exceptions, which Tcl already has. _One-shot_
continuations can only be resumed once and are then discarded. As previously
stated, such continuations are equivalent to coroutines as any particular
**yield** can only be resumed once. _Multi-shot_ continuations allow the
same continuation to be resumed multiple times. These continuations go beyond
the power of coroutines, and allow examples such as the nondeterministic
choice operator to be implemented. Multi-shot continuations are however rather
more expensive to implement, as each yield point requires creating a fresh
copy of the execution environment, whereas a coroutine can reuse the same
environment copy for multiple yield/resumes as it knows it cannot be resumed
more than once for a single yield. A further refinement is the idea of
_delimited continuations_ which capture only a certain portion of the
execution context \(stack\), rather than everything. Delimited continuations can
simulate normal continuations by simply capturing the entire dynamic extent,
but they have the advantage that they can also return a value, allowing them
to be composed. Coroutines are also of this form, where the extent of the
coroutine is limited to where the **coroutine** command was originally
called from. The coroutine mechanism proposed is therefore of roughly
equivalent power to a _one-shot delimited continuation_. Such a mechanism is
strictly less powerful than a multi-shot continuation implementation, but it
is believed that it is sufficient to cover the vast majority of useful
use-cases, while remaining relatively simple to understand, and efficient to
implement.

Lars Hellström has also proposed an alternative control mechanism for Tcl
\(Hellström, 2008\), which is essentially a form of multi-shot full \(non
delimited\) continuation, based on an interface of two commands: **suspend**
and **resume**. The **suspend** command captures the current evaluation
context into a continuation and then throws this as an exception with a
special TCL\_SUSPEND return code, allowing it to be caught and later resumed.
The interface supports communicating values and exceptions to the resumed
continuation. While the interface is potentially more expressive than the
coroutine mechanism here, the proposed implementation involves destroying the
stack as it is captured when the TCL\_SUSPEND exception propagates. This
presents a number of practical problems, such as the destruction of local
variables \(and thus the firing of unset traces\), and the overall inefficiency
of the approach.  As coroutines thus captured are stateless objects they can
be implemented as plain Tcl values \(i.e., strings\), albeit potentially quite
large and complex ones. This provides the usual advantages of easy
serialisation and transfer, while suffering the usual drawbacks of lack of
encapsulation \(potentially exposing implementation details\) and potential
inefficiencies due to shimmering or excess copying of data \(a general problem
of multi-shot continuations\). While some of these problems can be limited or
overcome entirely, it is our view that the current coroutines proposal covers
a great deal of the expected use-cases in a much simpler and more efficient
manner.

# Implementation

An experimental implementation of the coroutine mechanism is available in Tcl
8.6a2 in CVS on sourceforge. The implementation is available in the
::tcl::unsupported namespace, exposing the _coroutine_, _yield_, and
_infoCoroutine_ commands.

# References

\(Kowalski, 1979\) Robert Kowalski, "Algorithm = logic \+ control",
_Communications of the ACM_ 22\(7\), pp. 424-436, 1979.

\(Lua, 2004\) Ana Lûcia De Moura, Roberto Ierusalimschy, "Revisting Coroutines",
Tech Report, 2004. <http://www.inf.puc-rio.br/~roberto/docs/MCC15-04.pdf>

\(Hellström, 2008\) Lars Hellström, "Suspend and Resume",
<http://wiki.tcl.tk/21537>

# Copyright

This document has been placed in the public domain.

Name change from tip/329.tip to tip/329.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
136
137
138
139
140
141
142
143
144
145
146

147
148
149
150
151

152
153
154
155

156
157
158
159
160
161
162
163
164

165
166
167
168
169
170
171
172


173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209

TIP:            329
Title:          Try/Catch/Finally syntax
Version:        $Revision: 1.9 $
Author:         Trevor Davel <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        22-Sep-2008
Post-History:   
Discussions-To: http://wiki.tcl.tk/21608
Obsoletes:      89
Tcl-Version:    8.6


~ Abstract

This TIP proposes the addition of new core commands to improve the exception
handling mechanism. It supercedes [89] by providing support for the error
options dictionary introduced in Tcl 8.5 by [90].

~ Rationale

See [89] for general rationale for enhancing exception handling.

The '''try''' syntax presented here is not intended to replace '''catch''', but 
to simplify the expression of existing exception/error handling techniques, 
leading to greater code clarity and less error-prone workarounds for 
'''finally''' blocks. There is no deficiency in the functionality of Tcl's 
exception handling mechanisms - what is lacking is a more readable syntax and a 
standard for behaviour across packages for the common case of catching a subset 
errors or exceptions that are thrown from within a particular block of code.

In Tcl 8.4 exceptions could be caught using '''catch''', and exception
information was available via the '''catch''' return value and resultvar. If
the return value was TCL_ERROR (1) then the globals '''::errorCode''' and
'''::errorInfo''' would be set according to the exception raised. [89] was
written to work with this model, such that a catch handler (in a
'''try...catch''') would be able to capture the resultvar, errorCode and
errorInfo.

Tcl 8.5 implements [90] which extends '''catch''' to allow an additional
dictionary of options (error information) to be captured. These options
supercede the '''::errorInfo''' and '''::errorCode''' globals (though those
are still supported for backward compatibility). It is therefore logical to
extend/correct the syntax of [89] to support the options dictionary in
preference to the older mechanism for capturing exception information.

Benefits of adding this functionality to the core:

 * Bring to Tcl a construct commonly understood and widely used in other
   languages.

 * A standard for identifying categories/classes of errors, which will improve
   interoperability between packages.

 * A byte-coded implementation would be significantly faster than the Tcl
   implementation that is presented.

~ Specification

 > '''try''' ''body'' ?''handler'' ...? ?'''finally''' ''body''?

 > '''throw''' ''type message''

The '''try''' body is evaluated in the caller's scope. The handlers are 
searched in order of declaration until a matching one is found, and the 
associated body is executed. If no matching handler is found then '''try''' 
returns the result of the '''try''' body (exceptions will propagate up the 
stack as usual); otherwise '''try''' returns the result of the handler body
(exceptions will propagate up the stack as usual).

Only one handler body (that of the first matching handler) will be executed. If 
the handler body is the literal string "'''-'''" then the body for the 
subsequent handler will be used instead. It is an error for the last handler's 
body to be a literal "'''-'''".

The '''finally''' body (if present) will be executed last, and is always
executed whatever the results of the try and handler bodies (excepting
resource exhaustion or cancellation). If the '''finally''' body returns an
exceptional code then this will become the result of '''try''', otherwise the
result of the '''finally''' body is ignored.

Since the '''trap''' handlers in the '''try''' control structure are filtered
based on the exception's '''-errorcode''', it makes sense to have a command
that will encourage the use of error codes when throwing an exception.
'''throw''' is merely a reordering of the arguments of the '''error'''
command. ''type'' is treated as a list by '''trap''' (see below), which
maintains compatibility with the description of ::errorCode given in
'''tclvars'''.

~~Handlers

Each handler is identified by a keyword. The fields following the keyword 
indicate what exceptions or errors are matched by the handler, the variables 
into which the result of the '''try''' body will be assigned (in the caller's 
scope), and the body of the handler.

 > '''on''' ''code {?resultVar ?optionsVar?} body''

The '''on''' handler allows exact matching against the exceptional return code
(the integer value that would be returned by '''catch'''). The ''code'' may be 
given as an integer or one of the magic keywords '''ok''' (0), '''error''' (1),
'''return''' (2), '''break''' (3), '''continue''' (4).

 > '''trap''' ''pattern {?resultVar ?optionsVar?} body''

The '''trap''' handler allows list prefix matching against the
'''-errorcode''' from the options when the exceptional return code is
TCL_ERROR (1). Given a ''pattern'' and an ''errorcode'', a list prefix match
is successful if for every element in ''pattern'' there is a corresponding and
identical element in ''errorcode''. Trailing elements in ''errorcode'' are
ignored.

Notes & clarifications:

 * Handlers are searched in order of declaration (left-to-right). One
   consequence of this search order is that an '''on error''' handler will
   supercede all subsequent '''trap''' handlers.

 * Any unhandled exception propagates.

 * The result of the last executed body (other than the '''finally''' body) is
   the result of the '''try'''. Exceptions in any ''handler'' body or in the
   '''finally''' replace the existing exception and propagate.

 * If any exception is replaced (by an exception in a handler body or in the
   '''finally''' body) then the new exception shall introduce into its options
   dictionary the field '''-during''' that contains the options dict of the
   exception that was replaced.

 * If any errorcode happens to be not a list, a '''trap''' handler will be
   unable to process it. However, this should only happen in cases where there
   is a bug or other problem elsewhere, since '''return''' is documented to
   require the errorcode to be a list.

~ Examples

Simple example of '''try'''/''handler''/'''finally''' logic in Tcl using
currently available syntax:

| proc read_hex_file {fname} {
|    set f [open $fname "r"]
|    set data {}
|    set code [catch {
|       while { [gets $f line] >= 0 } {
|          append data [binary format H* $line]
|       }

|    } em opts]
|    if { $code != 0 } {
|       dict set opts -code 1
|       set em "Could not process file '$fname': $em"
|    }

|    close $f
|    return -options $opts $em
| }


And the same example rewritten to use [['''try''']]:

| proc read_hex_file {fname} {
|    set f [open $fname "r"]
|    set data {}
|    try  {
|       while { [gets $f line] >= 0 } {
|         append data [binary format H* $line]
|       }

|    } trap {POSIX} {} {
|       puts "POSIX-type error"
|    } on error {em} {
|       error "Could not process file '$fname': $em"
|    } finally {
|       close $f
|    }
| }



This illustrates how the intent of the code is more clearly expressed by
[['''try''']].

~ References

 * Tcl 8.4 catch [http://www.tcl.tk/man/tcl8.4/TclCmd/catch.htm]

 * Tcl 8.5 catch [http://www.tcl.tk/man/tcl8.5/TclCmd/catch.htm]

~ Rejected Alternatives

Various alternatives are discussed on the wiki [http://wiki.tcl.tk/21608]
along with reasons for their rejection.

~ Future Extensions

No specific future exceptions are planned, but '''try''' could be extended
by adding new handler keywords and/or introducing new varnames to the variables
list that is associated with each handler.

It is recommended that new handlers maintain the established convention:

 > '''keyword''' ''criteria {?resultVar ?optionsVar?} body''

~ Reference Implementation

A reference implementation can be found at [http://www.crypt.co.za/pub/try-1.tcl]

~ Thanks

Thanks in particular to DKF, NEM and JE for their feedback and suggestions
on this TIP.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|


|
|

|

|

|


|




|
|
|
|
|
|


|
|
|
|
|













|

|

|

|

|
|
|
|

|
|

|

|
|
|
|
|

|
|

|
|

|

|



|
|

|

|
|
|
|

|

|
|
|
|
|




|
|
|



|
|
|

|
|
|


|

|


|

|


|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
<
|
>
|

|
|
|
|
|
|
<
>
|
|
|
|
|
|
<
<
>
>


|

|

|

|

|

|


|

|





|

|

|

|




|


>

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
136
137
138
139
140
141
142
143
144

145
146
147
148
149

150
151
152

153
154
155
156
157
158
159
160
161
162

163
164
165
166
167
168
169


170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209

# TIP 329: Try/Catch/Finally syntax

	Author:         Trevor Davel <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        22-Sep-2008
	Post-History:   
	Discussions-To: http://wiki.tcl.tk/21608
	Obsoletes:      89
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes the addition of new core commands to improve the exception
handling mechanism. It supercedes [[89]](89.md) by providing support for the error
options dictionary introduced in Tcl 8.5 by [[90]](90.md).

# Rationale

See [[89]](89.md) for general rationale for enhancing exception handling.

The **try** syntax presented here is not intended to replace **catch**, but 
to simplify the expression of existing exception/error handling techniques, 
leading to greater code clarity and less error-prone workarounds for 
**finally** blocks. There is no deficiency in the functionality of Tcl's 
exception handling mechanisms - what is lacking is a more readable syntax and a 
standard for behaviour across packages for the common case of catching a subset 
errors or exceptions that are thrown from within a particular block of code.

In Tcl 8.4 exceptions could be caught using **catch**, and exception
information was available via the **catch** return value and resultvar. If
the return value was TCL\_ERROR \(1\) then the globals **::errorCode** and
**::errorInfo** would be set according to the exception raised. [[89]](89.md) was
written to work with this model, such that a catch handler \(in a
**try...catch**\) would be able to capture the resultvar, errorCode and
errorInfo.

Tcl 8.5 implements [[90]](90.md) which extends **catch** to allow an additional
dictionary of options \(error information\) to be captured. These options
supercede the **::errorInfo** and **::errorCode** globals \(though those
are still supported for backward compatibility\). It is therefore logical to
extend/correct the syntax of [[89]](89.md) to support the options dictionary in
preference to the older mechanism for capturing exception information.

Benefits of adding this functionality to the core:

 * Bring to Tcl a construct commonly understood and widely used in other
   languages.

 * A standard for identifying categories/classes of errors, which will improve
   interoperability between packages.

 * A byte-coded implementation would be significantly faster than the Tcl
   implementation that is presented.

# Specification

 > **try** _body_ ?_handler_ ...? ?**finally** _body_?

 > **throw** _type message_

The **try** body is evaluated in the caller's scope. The handlers are 
searched in order of declaration until a matching one is found, and the 
associated body is executed. If no matching handler is found then **try** 
returns the result of the **try** body \(exceptions will propagate up the 
stack as usual\); otherwise **try** returns the result of the handler body
\(exceptions will propagate up the stack as usual\).

Only one handler body \(that of the first matching handler\) will be executed. If 
the handler body is the literal string "**-**" then the body for the 
subsequent handler will be used instead. It is an error for the last handler's 
body to be a literal "**-**".

The **finally** body \(if present\) will be executed last, and is always
executed whatever the results of the try and handler bodies \(excepting
resource exhaustion or cancellation\). If the **finally** body returns an
exceptional code then this will become the result of **try**, otherwise the
result of the **finally** body is ignored.

Since the **trap** handlers in the **try** control structure are filtered
based on the exception's **-errorcode**, it makes sense to have a command
that will encourage the use of error codes when throwing an exception.
**throw** is merely a reordering of the arguments of the **error**
command. _type_ is treated as a list by **trap** \(see below\), which
maintains compatibility with the description of ::errorCode given in
**tclvars**.

## Handlers

Each handler is identified by a keyword. The fields following the keyword 
indicate what exceptions or errors are matched by the handler, the variables 
into which the result of the **try** body will be assigned \(in the caller's 
scope\), and the body of the handler.

 > **on** _code \{?resultVar ?optionsVar?\} body_

The **on** handler allows exact matching against the exceptional return code
\(the integer value that would be returned by **catch**\). The _code_ may be 
given as an integer or one of the magic keywords **ok** \(0\), **error** \(1\),
**return** \(2\), **break** \(3\), **continue** \(4\).

 > **trap** _pattern \{?resultVar ?optionsVar?\} body_

The **trap** handler allows list prefix matching against the
**-errorcode** from the options when the exceptional return code is
TCL\_ERROR \(1\). Given a _pattern_ and an _errorcode_, a list prefix match
is successful if for every element in _pattern_ there is a corresponding and
identical element in _errorcode_. Trailing elements in _errorcode_ are
ignored.

Notes & clarifications:

 * Handlers are searched in order of declaration \(left-to-right\). One
   consequence of this search order is that an **on error** handler will
   supercede all subsequent **trap** handlers.

 * Any unhandled exception propagates.

 * The result of the last executed body \(other than the **finally** body\) is
   the result of the **try**. Exceptions in any _handler_ body or in the
   **finally** replace the existing exception and propagate.

 * If any exception is replaced \(by an exception in a handler body or in the
   **finally** body\) then the new exception shall introduce into its options
   dictionary the field **-during** that contains the options dict of the
   exception that was replaced.

 * If any errorcode happens to be not a list, a **trap** handler will be
   unable to process it. However, this should only happen in cases where there
   is a bug or other problem elsewhere, since **return** is documented to
   require the errorcode to be a list.

# Examples

Simple example of **try**/_handler_/**finally** logic in Tcl using
currently available syntax:

	 proc read_hex_file {fname} {
	    set f [open $fname "r"]
	    set data {}
	    set code [catch {
	       while { [gets $f line] >= 0 } {
	          append data [binary format H* $line]

	       }
	    } em opts]
	    if { $code != 0 } {
	       dict set opts -code 1
	       set em "Could not process file '$fname': $em"

	    }
	    close $f
	    return -options $opts $em

	 }

And the same example rewritten to use [**try**]:

	 proc read_hex_file {fname} {
	    set f [open $fname "r"]
	    set data {}
	    try  {
	       while { [gets $f line] >= 0 } {
	         append data [binary format H* $line]

	       }
	    } trap {POSIX} {} {
	       puts "POSIX-type error"
	    } on error {em} {
	       error "Could not process file '$fname': $em"
	    } finally {
	       close $f


	    }
	 }

This illustrates how the intent of the code is more clearly expressed by
[**try**].

# References

 * Tcl 8.4 catch <http://www.tcl.tk/man/tcl8.4/TclCmd/catch.htm> 

 * Tcl 8.5 catch <http://www.tcl.tk/man/tcl8.5/TclCmd/catch.htm> 

# Rejected Alternatives

Various alternatives are discussed on the wiki <http://wiki.tcl.tk/21608> 
along with reasons for their rejection.

# Future Extensions

No specific future exceptions are planned, but **try** could be extended
by adding new handler keywords and/or introducing new varnames to the variables
list that is associated with each handler.

It is recommended that new handlers maintain the established convention:

 > **keyword** _criteria \{?resultVar ?optionsVar?\} body_

# Reference Implementation

A reference implementation can be found at <http://www.crypt.co.za/pub/try-1.tcl> 

# Thanks

Thanks in particular to DKF, NEM and JE for their feedback and suggestions
on this TIP.

# Copyright

This document has been placed in the public domain.

Name change from tip/33.tip to tip/33.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
136
137
138
139
140
141

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

200
201

202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249

250
251
252
253
254
255
256
257

258
259
260
261
262
263

264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280

281
282
283
284
285
286
287

288
289
290
291
292
293
294
295

296
297
298
299
300
301

302
303
304
305
306
307
308
309
310
311
312
313
314

315
316
317

318
319
320

321
322
323
324
325
326
327

328
329
330
331
332
333
334
335

336
337
338
339
340

341
342
343
344
345
346
347
348
349
350
351
352
353
354

355
356
357
358
359
360
361
362
363
364
365

366
367
368
369
370
371


372
373
374
375
376
377
378
379
380
381
382
383
384
385


386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405

406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521

522
523
524
525

526
527

528
529
530
531
532
533
534
535
536
537
538
539

540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555



556
557
558
559

560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588

589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666

TIP:            33
Title:          Add 'lset' Command to Assign to List Elements.
Version:        $Revision: 1.13 $
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        15-May-2001
Post-History:   
Discussions-To: news:comp.lang.tcl,mailto:[email protected]
Tcl-Version:    8.4


~ Abstract

Most popular programming languages provide some sort of indexed array
construct, where array subscripts are integers.  Tcl's lists are
implemented internally as indexed arrays, but it is difficult to use
them as such because there is no convenient way to assign to
individual elements.  This TIP proposes a new command, ''lset'', to
rectify this limitation.

~ Rationale

The implementation of lists in Tcl has evolved far beyond the original
conception.  While lists were originally conceived to be strings with
a particular syntax that allowed them to be parsed as lists, the
internal representation of a list is now an array of pointers to
''Tcl_Obj'' structures.

Tcl programmers, for the most part, have not taken advantage of this
evolution.  Code that uses hash tables where linear arrays would be a
more appropriate structure is still extremely common.  Moreover, it is
difficult to update lists in place, even if their internal
representations are known not to be shared.  One example of this
difficulty is seen in the discussions
[http://purl.org/thecliff/tcl/wiki/941]
of how best to shuffle a list of items.  The discussion began with a
na�ve implementation of Jon Bentley's method of performing random
swaps:

|  proc shuffle1 { list } {
|      set n [llength $list]
|      for { set i 0 } { $i < $n } { incr i } {
|          set j [expr {int(rand()*$n)}]
|          set temp [lindex $list $j]
|          set list [lreplace $list $j $j [lindex $list $i]]
|          set list [lreplace $list $i $i $temp]
|      }

|      return $list
|  }


Aside from the fact that the syntax obscures what the program is
doing, the implementation suffers from an obscure performance problem.
When the ''lreplace'' calls in the ''shuffle1'' procedure are
executed, the internal representation of ''list'' has two references:
the value of the variable, and the parameter passed to ''lreplace''.
The multiple references force ''lreplace'' to copy the list, leading
to quadratic performance when large lists are shuffled.

It is possible, albeit difficult, to alleviate this problem by careful
management of the lifetime of ''Tcl_Obj'' structures, but this change
complicates the code.  The simplest way to fix the performance is
probably to use Donal Fellows's implementation of the ''K''
combinator:

| proc K { x y } { set x }

which allows the caller of ''lreplace'' to extract the value of
''list'', change the value of ''list'' so that the extracted value is
unshared, and then pass the extracted value as a parameter to
''lreplace:''

|  proc shuffle1a { list } {
|      set n [llength $list]
|      for { set i 0 } { $i < $n } { incr i } {
|          set j [expr {int(rand()*$n)}]
|          set temp1 [lindex $list $j]
|          set temp2 [lindex $list $i]
|          set list [lreplace [K $list [set list {}]] $j $j $temp2]
|          set list [lreplace [K $list [set list {}]] $i $i $temp1]
|      }

|      return $list
|  }


Now the performance of the code is ''O(n)'' where ''n'' is the length
of the list, but the programmer's intent has been seriously obscured!
Moreover, the performance is still rather poor: Tcl makes an atrocious
showing, for instance, in Doug Bagley's 'Great Computer Language
Shootout' [http://www.bagley.org/~doug/shootout/].

~ Specification

This TIP proposes an 'lset' command with the syntax:

|  lset varName indexList value

or

|  lset varName index1 index2... value

where:

 > ''varName'' is the name of a variable in the caller's scope.

 > If ''objc==4'', then the ''indexList'' parameter is interpreted as
   a list of ''index'' arguments; if ''objc>4'', then the ''index''
   arguments are inline on the command line.

 > In either case, Each ''index'' argument is an index in the content
   of ''varName'' or one of its sublists (see below).  The format of
   ''index'' is either an integer whose value is at least zero and
   less than the length of the corresponding list, or else the literal
   string ''end'', optionally followed with a hyphen and an integer
   whose value is at least zero and less than the length of the
   corresponding list.

 > ''value'' is a value that is to be stored as a list element.

The return value of the command, if successful, is the new value
of ''varName.''

The simplest form of the command:

|  lset varName index value

replaces, in place, the ''index'' element of ''varName'' with the
specified ''value''.  For example, the code:

|  set x {a b c}
|  lset x 1 d

results in ''x'' having the value ''a d c''.  The result, except
for performance considerations and the details of error reporting,
is roughly the same as the Tcl code:

|  proc lset { varName index value } {
|      upvar 1 $varName list
|      set list [lreplace $list $index $index $value]
|      return $list
|  }


except that where the ''lreplace'' command permits indices outside the
existing list elements, the proposed ''lset'' command forbids them.

If multiple ''index'' arguments are supplied to the ''lset'' command,
they refer to successive sublists in a hierarchical fashion.  Thus,

|   lset varName $i $j value

or, equivalently,

|   lset varName [list $i $j] value

asks to change the value of the ''j''th element in the ''i''th sublist
of ''varName''.  Hence, the code:

|   set x {{a b c} {d e f} {g h i}}
|   lset x 1 1 j; # -or- lset x {1 1} j

changes the value of ''x'' to

|   {a b c} {d j f} {g h i}

and the code

|   set y {{{a b} {c d}} {{e f} {g h}}}
|   lset y 1 0 1 i; # -or- lset y {1 0 1} i

changes the value of ''y'' to

|   {{a b} {c d}} {{e i} {g h}}

This notation also dovetails prettily with the extension of the
''lindex'' command proposed in [22].  The command

|   lindex $y 1 0 1; # -or- lindex y {1 0 1}

will extract the element that is set by the command

|   lset $y 1 0 1 $value

The ''lset'' command will throw an error and leave the variable
unchanged if it is presented with fewer than three arguments, if any
of the ''index'' arguments is out of range or ill-formed, or if any of
the data being manipulated cannot be converted to lists.  It will
throw an error after modifying the variable if any write trace on the
variable fails.

With the proposed ''lset'' command, the procedure to shuffle a list
becomes much more straightforward:

|  proc shuffle1b { list } {
|      set n [llength $list]
|      for { set i 0 } { $i < $n } { incr i } {
|          set j [expr {int(rand()*$n)}]
|          set temp [lindex $list $j]
|          lset list $j [lindex $list $i]
|          lset list $i $temp
|      }

|      return $list
|  }


The given implementation copies the list only once, the first time
that the line:

|          lset list $j [lindex $list $i]

is executed.  Thereafter, the list is an unshared object, and the
replacements are performed in place.

~ Reference Implementation

The author has implemented a simpler variant of the proposed command
as an object command, and also proposes to bytecode compile it,
although the implementation of bytecode compilation is incomplete.
The reference implementation also does not yet expand ''objv[[2]]''
as a list in the case where ''objc==4,'' and is known to have memory
leaks where ill-formed index arguments are presented.  It is given
here as ''concept code'' and to present its impact on performance of
some common list operations.  (Obviously, it will be completed and
reviewed with the relevant maintainers prior to being committed to the
Core.)

The core of the implementation is the following procedure:

|int
|Tcl_LsetObjCmd( clientData, interp, objc, objv )
|    ClientData clientData;      /* Not used. */
|    Tcl_Interp *interp;         /* Current interpreter. */
|    int objc;                   /* Number of arguments. */
|    Tcl_Obj *CONST objv[];      /* Argument values. */
|{

|
|    Tcl_Obj* listPtr;           /* Pointer to the list being altered. */
|    Tcl_Obj* subListPtr;        /* Pointer to a sublist of the list */
|    Tcl_Obj* finalValuePtr;     /* Value finally assigned to the variable */
|    int index;                  /* Index of the element being replaced */
|    int result;                 /* Result to return from this function */
|    int listLen;                /* Length of a list being examined */
|    Tcl_Obj** elemPtrs;         /* Pointers to the elements of a
|                                 * list being examined */
|    int i;
|
|    /* Check parameter count */
|
|    if ( objc < 4 ) {
|        Tcl_WrongNumArgs( interp, 1, objv, "listVar index ?index...? value" );
|        return TCL_ERROR;
|    }

|
|    /* Look up the list variable */
|
|    listPtr = Tcl_ObjGetVar2( interp, objv[ 1 ], (Tcl_Obj*) NULL,
|                              TCL_LEAVE_ERR_MSG );
|    if ( listPtr == NULL ) {
|        return TCL_ERROR;
|    }

|
|    /* Make sure that the list value is unshared. */
|
|    if ( Tcl_IsShared( listPtr ) ) {
|        listPtr = Tcl_DuplicateObj( listPtr );
|    }

|
|    finalValuePtr = listPtr;
|
|    /*
|     * If there are multiple 'index' args, handle each arg except the
|     * last by diving into a sublist.
|     */
|
|    for ( i = 2; ; ++i ) {
|
|        /* Take apart the list */
|
|        result = Tcl_ListObjGetElements( interp, listPtr,
|                                         &listLen, &elemPtrs );
|        if ( result != TCL_OK ) {
|            return result;
|        }

|
|        /* Derive the index of the requested sublist */
|
|        result = TclGetIntForIndex( interp, objv[i], (listLen - 1), &index );
|        if ( result != TCL_OK ) {
|            return result;
|        }

|
|        if ( ( index < 0 ) || ( index >= listLen ) ) {
|
|            Tcl_SetObjResult( interp,
|                              Tcl_NewStringObj( "list index out of range",
|                                                -1 ) );
|            return TCL_ERROR;
|        }

|
|        /* Break out of the loop if we've extracted the innermost sublist. */
|
|        if ( i >= ( objc - 2 ) ) {
|            break;
|        }

|
|        /*
|         * Extract the appropriate sublist, and make sure that it is unshared.
|         */
|
|        subListPtr = elemPtrs[ index ];
|        if ( Tcl_IsShared( subListPtr ) ) {
|            subListPtr = Tcl_DuplicateObj( subListPtr );
|            result = Tcl_ListObjSetElement( interp, listPtr, index,
|                                            subListPtr );
|            if ( result != TCL_OK ) {
|                return TCL_ERROR;
|            }

|        } else {
|            Tcl_InvalidateStringRep( listPtr );
|        }

|
|        listPtr = subListPtr;
|    }

|
|    /* Store the result in the list element */
|
|    result = Tcl_ListObjSetElement( interp, listPtr, index, objv[objc-1] );
|    if ( result != TCL_OK ) {
|        return result;
|    }

|
|    /* Finally, update the variable so that traces fire. */
|
|    listPtr = Tcl_ObjSetVar2( interp, objv[1], NULL, finalValuePtr,
|                              TCL_LEAVE_ERR_MSG );
|    if ( listPtr == NULL ) {
|        return TCL_ERROR;
|    }

|       
|    Tcl_SetObjResult( interp, listPtr );
|    return result;
|
|}


The procedure depends on a new service function,
''Tcl_ListObjSetElement'':

|int
|Tcl_ListObjSetElement( interp, listPtr, index, valuePtr )
|    Tcl_Interp* interp;         /* Tcl interpreter; used for error reporting
|                                 * if not NULL */
|    Tcl_Obj* listPtr;           /* List object in which element should be
|                                 * stored */
|    int index;                  /* Index of element to store */
|    Tcl_Obj* valuePtr;          /* Tcl object to store in the designated
|                                 * list element */
|{

|    int result;                 /* Return value from this function */
|    List* listRepPtr;           /* Internal representation of the list
|                                 * being modified */
|    Tcl_Obj** elemPtrs;         /* Pointers to elements of the list */
|    int elemCount;              /* Number of elements in the list */
|
|    /* Ensure that the listPtr parameter designates an unshared list */
|
|    if ( Tcl_IsShared( listPtr ) ) {
|        panic( "Tcl_ListObjSetElement called with shared object" );
|    }

|    if ( listPtr->typePtr != &tclListType ) {
|        result = SetListFromAny( interp, listPtr );
|        if ( result != TCL_OK ) {
|            return result;
|        }
|    }


|    listRepPtr = (List*) listPtr->internalRep.otherValuePtr;
|    elemPtrs = listRepPtr->elements;
|    elemCount = listRepPtr->elemCount;
|
|    /* Ensure that the index is in bounds */
|
|    if ( index < 0 || index >= elemCount ) {
|        if ( interp != NULL ) {
|            Tcl_SetObjResult( interp,
|                              Tcl_NewStringObj( "list index out of range",
|                                                -1 ) );
|            return TCL_ERROR;
|        }
|    }


|
|    /* Add a reference to the new list element */
|
|    Tcl_IncrRefCount( valuePtr );
|
|    /* Remove a reference from the old list element */
|
|    Tcl_DecrRefCount( elemPtrs[ index ] );
|
|    /* Stash the new object in the list */
|
|    elemPtrs[ index ] = valuePtr;
|
|    /* Invalidate and free any old string representation */
|
|    Tcl_InvalidateStringRep( listPtr );
|
|    return TCL_OK;
|    
|}


Even without bytecode compilation, the performance improvement of
array-based applications that can be achieved by the ''lset'' command
is substantial.  The following table shows run times in microseconds
(on a 550 MHz Pentium III laptop, running a modified Tcl 8.4 on
Windows NT 4.0, Service Pack #6) of the three implementations of
''shuffle'' that appear in this TIP.

|                    RUN TIMES IN MICROSECONDS
|
|                                Version
|                     shuffle1       shuffle1a       shuffle1b
|                     (Naive)      (K combinator)  (lset command)
| List length
|        1                 26               32              27            
|       10                108              152             101
|      100               1627             1462             936
|     1000             117831            14789            9574
|    10000       Test stopped           152853           96912

Similar (30-50%) improvements are observed on many of the array
related benchmarks that have been proposed.  Bytecode compilation is
expected to produce even greater improvements.

Another area where ''lset'' can achieve a major performance gain is in
memory usage.  The author of this TIP has benchmarked competing
implementations of heapsort, one using Tcl arrays, and the other using
''lset'' to manipulate lists as linear arrays.  When sorting 80000
elements, the Tcl-array-based implementation used 12.7 megabytes of
memory; the list-based implementation was faster and used only 5.6
megabytes.  The explanation is simple: each entry in the hash table
requires an allocated block of twenty bytes of memory, plus the space
required for the hash key.  The hash key is a string, and requires at
least six bytes.  When both of these objects are aligned and padded
with the overheads imposed by ''ckalloc'', they require about 80 bytes of
memory on the Windows NT platform.  The memory cost of an element of a
Tcl list, by comparison, is four bytes to hold the pointer to the
object.

~ Discussion

There are several objections that can be foreseen to this proposal.

   * ''Why implement the command in the Core and not as an extension?''

   > In a word, ''performance.''  At the present state of Tcl
     development, only Core commands can be bytecoded.  The cost of
     the hash table lookups in the ''Tcl_ObjGetVar2'' and
     ''Tcl_ObjSetVar2'' calls is significant, and can be eliminated
     from many common usages by the bytecode compiler.  Since this
     command is likely to appear in inner loops, it is important to
     squeeze every bit of possible performance out of it.

   * ''Why a new command in the global namespace?''

   > The author of this TIP feels that having a single added command
     that is parallel to the existing list commands is not polluting
     the namespace excessively.  It would be a shame if this proposal
     founders upon the Naming of Names.

   * ''Why a new command, rather than including this functionality in
     the proposed functionality of an extensible command for list
     manipulation?''

   > The author of this TIP has yet to see a formal proposal of any
     extensible list manipulation command; the closest thing appears
     to be Andreas Kupries's ''listx'' package
     [http://www.oche.de/~akupries/tcltk.html].  Given the size and
     complexity of any such modification, it is unlikely that it will
     be available in the Core in time for an 8.4 release.  The
     performance improvements achievable by the ''lset'' command are
     needed urgently.

   * ''Isn't this [29] warmed over?''

   > Several objectors to [29] indicated that they were willing to
     consider list element assignment implemented as a new command.

   * ''Doesn't this proposal depend on multiple ''index'' arguments to
     ''lindex'' ([22])?

   > This proposal can stand alone.  If multiple ''index'' arguments
     to ''lindex'' are also accepted, the resulting symmetry is
     pleasing.  Having multiple ''index'' args to ''lset'' is much
     more important, because it is horribly difficult to implement
     equivalent functionality in pure Tcl without introducing
     excessive calls to ''Tcl_DuplicateObj''.  In fact, the reference
     implementation of ''lset'' presented in this TIP was motivated by
     the fact that its author gave up on the task and resorted to C.

~ Implementation Notes

Having two versions of the syntax for the ''lset'' command is perhaps
unattractive, but neither can be left out effectively.

The syntax where the indices are packaged as a single list allows a
''cursor'' into complex list structure to be maintained in a single
variable.  The list element that the cursor designates can be altered
with a single call to the ''lset'' command, without needing to resort
to ''eval'' (a command that is both expensive and dangerous) to expand
the indices inline.

The syntax where each index is a first-class object is motivated by
the performance of array-based algorithms.  Programmers who are using
lists as arrays know exactly how many subscripts they have, and in
fact are generally iterating through them.  A typical sort of usage
might be the na�ve matrix multiplication shown below.

| # Construct a matrix with 'rows' rows and 'columns' columns
| # having an initial value of 'initCellValue' in each cell.
| 
| proc matrix { rows columns { initCellValue {} } } {
|     set oneRow {}
|     for { set i 0 } { $i < $columns } { incr i } {
|         lappend oneRow $initCellValue
|     }

|     set matrix {}
|     for { set i 0 } { $i < $rows } { incr i } {
|         lappend matrix $oneRow
|     }

|     return $matrix
| }

| 
| # Multiply two matrices
| 
| proc matmult { x y } {
| 
|     set m [llength $x];                 # Number of rows of left matrix
|     set n [llength [lindex $x 0]];      # Number of columns of left matrix
| 
|     if { $n != [llength $y] } {
|         return -code error "rank error: left operand has $n columns\
|                             while right operand has [llength $y] rows"
|     }

| 
|     set k [llength [lindex $y 0]];      # Number of columns of right matrix
| 
|     # Construct a matrix to hold the product
| 
|     set product [matrix $m $k]
| 
|     for { set i 0 } { $i < $m } { incr i } {
|         for { set j 0 } { $j < $k } { incr j } {
|             lset product $i $j 0.0
|             for { set r 0 } { $r < $n } { incr r } {
|                 set term [expr { [lindex $x $i $r] * [lindex $y $r $j] }]
|                 lset product $i $j [expr { [lindex $product $i $j] + $term }]
|             }
|         }
|     }



| 
|     return $product
| }


Note how we have an [[lset]] operation in the innermost loop, executed
(m*n*k) times.

If in this instance, we have to write:

|                 set indices [list $i $j]
|                 lset product $indices \
|                     [expr { [lindex $product $indices] + $term }]

in place of the [[lset]] shown above, we add the cost of forming the
list of indices to the cost of the inner loop.  This cost is not to be
sneezed at -- it's two expensive calls to ''ckalloc.''  (The cost can
be avoided, at some cost in readability, by maintaning a variable
containing the index list, and altering its elements with other uses
of [[lset]].)

Richard Suchenwirth suggested the compromise that appears in this
proposal.  This scheme will perilous to performance if implemented
naively.  If the implementation of [[lset]] simply calls
''Tcl_ListObjGetElements'', look what happens to the inner loop of our
''shuffle1b'' procedure:

|      for { set i 0 } { $i < $n } { incr i } {
|          set j [expr {int(rand()*$n)}]
|          set temp [lindex $list $j]
|          lset list $j [lindex $list $i]
|          lset list $i $temp
|      }


   * Initially, {set i 0} sets i to the constant "0"; it is a string.

   * Evaluating the conditional {$i < $n} will shimmer i to an integer;
     now it's an integer.  (We had to do a call to strtol here.)

   * The [[lindex $list $i]] call now has to consider $i as a list of
     indices, and shimmers it to the list.  This discards the internal
     rep, parses the string rep into a list, and then reconverts its
     first element to an integer.

   * OK, now the 'lset' is happy, and no further shimmering occurs...

   * ... until we get to the {incr i}.  Now we go back to the string rep
     once again, shimmer it to an integer (yet another call to strtol),
     and invalidate the string rep because we've incremented the integer.

   * Now we get back into the [[lindex]] once again, and need a list
     rep.  This time, we have to format the integer as a string, parse
     it as a list, take the object representing element 0, and reparse
     that as an integer.

This sequence has converted the integer to and from a string, and
performed four calls to ''ckalloc'', but resulted in the same integer
that we started with!

It is possible for a sufficiently smart compromise implementation
to avoid all this shimmering.  In the case where ''objc==4'', the
''lset'' command must:

 1. Test whether ''objv[[2]]'' designates an object whose internal
    representation holds an integer.  If so, simply use it as an index.

 2. Test whether ''objv[[2]]'' designates an object whose internal
    representation holds a list.  If so, perform the recursive
    extraction of indexed elements from sublists described above.

 3. Form the string representation of ''objv[[2]]'' and test whether
    it is ''end'' or ''end-'' followed by an integer.  If so, use it
    as an index.

 4. Attempt to coerce ''objv[[2]]'' to an integer; if successful, use
    the result as an integer.

 5. Attempt to coerce ''objv[[2]]'' to a list; if successful, use
    the result as an index list.

 6. Report a malformed ''index'' argument; the ''indexList'' parameter
    is not a well-formed list.

This logic handles all the cases of singleton lists transparently; it
is effectively a simple-minded type inference that optimizes away
needless conversions.  With it in place, none of the ''lset'' examples
shown in this TIP will suffer from type shimmering.

In the event that the related [22] is approved, the logic for parsing
an index list will likely be combined with that used in the ''lindex''
command.

Bytecoding variadic commands like ''lset'' presents some interesting
technical challenges; a discussion in progress on the Tcl'ers Wiki
[http://wiki.tcl.tk/1604] is recording the design
decisions being made for bytecoding ''lset'' so that they can be
applied to similar commands in the future.

~ See Also

[22], [29].

~ Change History

This TIP has undergone several revisions by the original author.
The most significant was made on 20 May 2001, where the syntax was
revised to allow for either several indices inline on the command line
or a list of indices.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|


|





|







|

|


|
|
|
|
|
|
|
<
>
|
<
|
>


|
|
|
|



|

|


|

|
|

|

|
|
|
|
|
|
|
|
<
>
|
<
|
>
|



|

|



|



|



|

|
|


|
|
|

|



|


|



|

|
|

|
|

|



|
|
|
|
<
|
>
|
|

|


|



|

|
|

|
|

|

|



|
|

|

|


|

|



|

|

|




|


|
|
|
|
|
|
|
<
>
|
<
>




|




|




|
|

|
|

|



|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
<
>
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>


|

|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>


|

|
|
|

|
|
|
|
|
|
|
|
|
|
|

|



|


|






|




|



|

|

|
|




|

|




|

|

|

|
|


|


|

|


|
|

|
|
|


|
|


|

|



|

|
|






|

|
|
|
|
|
|
|
<
>
|
|
|
<
>
|
<
>
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<
>
>
>
|
|
<
|
>
|
|



|
|
|

|

|


|



|
|
|

|
|
|
|
|
<
|
>
|

|
|

|






|
|


|





|



|
|

|


|



|
|


|


|


|




|


|
|


|

|
|


|

|

|






|


>

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
136
137
138

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197

198
199

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230

231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247

248
249
250
251
252
253
254
255

256
257
258
259
260
261

262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278

279
280
281
282
283
284
285

286
287
288
289
290
291
292
293

294
295
296
297
298
299

300
301
302
303
304
305
306
307
308
309
310
311
312

313
314
315

316
317
318

319
320
321
322
323
324
325

326
327
328
329
330
331
332
333

334
335
336
337
338

339
340
341
342
343
344
345
346
347
348
349
350
351
352

353
354
355
356
357
358
359
360
361
362
363

364
365
366
367
368


369
370
371
372
373
374
375
376
377
378
379
380
381
382


383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403

404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519

520
521
522
523

524
525

526
527
528
529
530
531
532
533
534
535
536
537

538
539
540
541
542
543
544
545
546
547
548
549
550
551



552
553
554
555
556

557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585

586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666

# TIP 33: Add 'lset' Command to Assign to List Elements.

	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        15-May-2001
	Post-History:   
	Discussions-To: news:comp.lang.tcl,mailto:[email protected]
	Tcl-Version:    8.4
-----

# Abstract

Most popular programming languages provide some sort of indexed array
construct, where array subscripts are integers.  Tcl's lists are
implemented internally as indexed arrays, but it is difficult to use
them as such because there is no convenient way to assign to
individual elements.  This TIP proposes a new command, _lset_, to
rectify this limitation.

# Rationale

The implementation of lists in Tcl has evolved far beyond the original
conception.  While lists were originally conceived to be strings with
a particular syntax that allowed them to be parsed as lists, the
internal representation of a list is now an array of pointers to
_Tcl\_Obj_ structures.

Tcl programmers, for the most part, have not taken advantage of this
evolution.  Code that uses hash tables where linear arrays would be a
more appropriate structure is still extremely common.  Moreover, it is
difficult to update lists in place, even if their internal
representations are known not to be shared.  One example of this
difficulty is seen in the discussions
<http://purl.org/thecliff/tcl/wiki/941> 
of how best to shuffle a list of items.  The discussion began with a
naïve implementation of Jon Bentley's method of performing random
swaps:

	  proc shuffle1 { list } {
	      set n [llength $list]
	      for { set i 0 } { $i < $n } { incr i } {
	          set j [expr {int(rand()*$n)}]
	          set temp [lindex $list $j]
	          set list [lreplace $list $j $j [lindex $list $i]]
	          set list [lreplace $list $i $i $temp]

	      }
	      return $list

	  }

Aside from the fact that the syntax obscures what the program is
doing, the implementation suffers from an obscure performance problem.
When the _lreplace_ calls in the _shuffle1_ procedure are
executed, the internal representation of _list_ has two references:
the value of the variable, and the parameter passed to _lreplace_.
The multiple references force _lreplace_ to copy the list, leading
to quadratic performance when large lists are shuffled.

It is possible, albeit difficult, to alleviate this problem by careful
management of the lifetime of _Tcl\_Obj_ structures, but this change
complicates the code.  The simplest way to fix the performance is
probably to use Donal Fellows's implementation of the _K_
combinator:

	 proc K { x y } { set x }

which allows the caller of _lreplace_ to extract the value of
_list_, change the value of _list_ so that the extracted value is
unshared, and then pass the extracted value as a parameter to
_lreplace:_

	  proc shuffle1a { list } {
	      set n [llength $list]
	      for { set i 0 } { $i < $n } { incr i } {
	          set j [expr {int(rand()*$n)}]
	          set temp1 [lindex $list $j]
	          set temp2 [lindex $list $i]
	          set list [lreplace [K $list [set list {}]] $j $j $temp2]
	          set list [lreplace [K $list [set list {}]] $i $i $temp1]

	      }
	      return $list

	  }

Now the performance of the code is _O\(n\)_ where _n_ is the length
of the list, but the programmer's intent has been seriously obscured!
Moreover, the performance is still rather poor: Tcl makes an atrocious
showing, for instance, in Doug Bagley's 'Great Computer Language
Shootout' <http://www.bagley.org/~doug/shootout/> .

# Specification

This TIP proposes an 'lset' command with the syntax:

	  lset varName indexList value

or

	  lset varName index1 index2... value

where:

 > _varName_ is the name of a variable in the caller's scope.

 > If _objc==4_, then the _indexList_ parameter is interpreted as
   a list of _index_ arguments; if _objc>4_, then the _index_
   arguments are inline on the command line.

 > In either case, Each _index_ argument is an index in the content
   of _varName_ or one of its sublists \(see below\).  The format of
   _index_ is either an integer whose value is at least zero and
   less than the length of the corresponding list, or else the literal
   string _end_, optionally followed with a hyphen and an integer
   whose value is at least zero and less than the length of the
   corresponding list.

 > _value_ is a value that is to be stored as a list element.

The return value of the command, if successful, is the new value
of _varName._

The simplest form of the command:

	  lset varName index value

replaces, in place, the _index_ element of _varName_ with the
specified _value_.  For example, the code:

	  set x {a b c}
	  lset x 1 d

results in _x_ having the value _a d c_.  The result, except
for performance considerations and the details of error reporting,
is roughly the same as the Tcl code:

	  proc lset { varName index value } {
	      upvar 1 $varName list
	      set list [lreplace $list $index $index $value]
	      return $list

	  }

except that where the _lreplace_ command permits indices outside the
existing list elements, the proposed _lset_ command forbids them.

If multiple _index_ arguments are supplied to the _lset_ command,
they refer to successive sublists in a hierarchical fashion.  Thus,

	   lset varName $i $j value

or, equivalently,

	   lset varName [list $i $j] value

asks to change the value of the _j_th element in the _i_th sublist
of _varName_.  Hence, the code:

	   set x {{a b c} {d e f} {g h i}}
	   lset x 1 1 j; # -or- lset x {1 1} j

changes the value of _x_ to

	   {a b c} {d j f} {g h i}

and the code

	   set y {{{a b} {c d}} {{e f} {g h}}}
	   lset y 1 0 1 i; # -or- lset y {1 0 1} i

changes the value of _y_ to

	   {{a b} {c d}} {{e i} {g h}}

This notation also dovetails prettily with the extension of the
_lindex_ command proposed in [[22]](22.md).  The command

	   lindex $y 1 0 1; # -or- lindex y {1 0 1}

will extract the element that is set by the command

	   lset $y 1 0 1 $value

The _lset_ command will throw an error and leave the variable
unchanged if it is presented with fewer than three arguments, if any
of the _index_ arguments is out of range or ill-formed, or if any of
the data being manipulated cannot be converted to lists.  It will
throw an error after modifying the variable if any write trace on the
variable fails.

With the proposed _lset_ command, the procedure to shuffle a list
becomes much more straightforward:

	  proc shuffle1b { list } {
	      set n [llength $list]
	      for { set i 0 } { $i < $n } { incr i } {
	          set j [expr {int(rand()*$n)}]
	          set temp [lindex $list $j]
	          lset list $j [lindex $list $i]
	          lset list $i $temp

	      }
	      return $list

	  }

The given implementation copies the list only once, the first time
that the line:

	          lset list $j [lindex $list $i]

is executed.  Thereafter, the list is an unshared object, and the
replacements are performed in place.

# Reference Implementation

The author has implemented a simpler variant of the proposed command
as an object command, and also proposes to bytecode compile it,
although the implementation of bytecode compilation is incomplete.
The reference implementation also does not yet expand _objv[[2]](2.md)_
as a list in the case where _objc==4,_ and is known to have memory
leaks where ill-formed index arguments are presented.  It is given
here as _concept code_ and to present its impact on performance of
some common list operations.  \(Obviously, it will be completed and
reviewed with the relevant maintainers prior to being committed to the
Core.\)

The core of the implementation is the following procedure:

	int
	Tcl_LsetObjCmd( clientData, interp, objc, objv )
	    ClientData clientData;      /* Not used. */
	    Tcl_Interp *interp;         /* Current interpreter. */
	    int objc;                   /* Number of arguments. */
	    Tcl_Obj *CONST objv[];      /* Argument values. */

	{
	
	    Tcl_Obj* listPtr;           /* Pointer to the list being altered. */
	    Tcl_Obj* subListPtr;        /* Pointer to a sublist of the list */
	    Tcl_Obj* finalValuePtr;     /* Value finally assigned to the variable */
	    int index;                  /* Index of the element being replaced */
	    int result;                 /* Result to return from this function */
	    int listLen;                /* Length of a list being examined */
	    Tcl_Obj** elemPtrs;         /* Pointers to the elements of a
	                                 * list being examined */
	    int i;
	
	    /* Check parameter count */
	
	    if ( objc < 4 ) {
	        Tcl_WrongNumArgs( interp, 1, objv, "listVar index ?index...? value" );
	        return TCL_ERROR;

	    }
	
	    /* Look up the list variable */
	
	    listPtr = Tcl_ObjGetVar2( interp, objv[ 1 ], (Tcl_Obj*) NULL,
	                              TCL_LEAVE_ERR_MSG );
	    if ( listPtr == NULL ) {
	        return TCL_ERROR;

	    }
	
	    /* Make sure that the list value is unshared. */
	
	    if ( Tcl_IsShared( listPtr ) ) {
	        listPtr = Tcl_DuplicateObj( listPtr );

	    }
	
	    finalValuePtr = listPtr;
	
	    /*
	     * If there are multiple 'index' args, handle each arg except the
	     * last by diving into a sublist.
	     */
	
	    for ( i = 2; ; ++i ) {
	
	        /* Take apart the list */
	
	        result = Tcl_ListObjGetElements( interp, listPtr,
	                                         &listLen, &elemPtrs );
	        if ( result != TCL_OK ) {
	            return result;

	        }
	
	        /* Derive the index of the requested sublist */
	
	        result = TclGetIntForIndex( interp, objv[i], (listLen - 1), &index );
	        if ( result != TCL_OK ) {
	            return result;

	        }
	
	        if ( ( index < 0 ) || ( index >= listLen ) ) {
	
	            Tcl_SetObjResult( interp,
	                              Tcl_NewStringObj( "list index out of range",
	                                                -1 ) );
	            return TCL_ERROR;

	        }
	
	        /* Break out of the loop if we've extracted the innermost sublist. */
	
	        if ( i >= ( objc - 2 ) ) {
	            break;

	        }
	
	        /*
	         * Extract the appropriate sublist, and make sure that it is unshared.
	         */
	
	        subListPtr = elemPtrs[ index ];
	        if ( Tcl_IsShared( subListPtr ) ) {
	            subListPtr = Tcl_DuplicateObj( subListPtr );
	            result = Tcl_ListObjSetElement( interp, listPtr, index,
	                                            subListPtr );
	            if ( result != TCL_OK ) {
	                return TCL_ERROR;

	            }
	        } else {
	            Tcl_InvalidateStringRep( listPtr );

	        }
	
	        listPtr = subListPtr;

	    }
	
	    /* Store the result in the list element */
	
	    result = Tcl_ListObjSetElement( interp, listPtr, index, objv[objc-1] );
	    if ( result != TCL_OK ) {
	        return result;

	    }
	
	    /* Finally, update the variable so that traces fire. */
	
	    listPtr = Tcl_ObjSetVar2( interp, objv[1], NULL, finalValuePtr,
	                              TCL_LEAVE_ERR_MSG );
	    if ( listPtr == NULL ) {
	        return TCL_ERROR;

	    }
	       
	    Tcl_SetObjResult( interp, listPtr );
	    return result;
	

	}

The procedure depends on a new service function,
_Tcl\_ListObjSetElement_:

	int
	Tcl_ListObjSetElement( interp, listPtr, index, valuePtr )
	    Tcl_Interp* interp;         /* Tcl interpreter; used for error reporting
	                                 * if not NULL */
	    Tcl_Obj* listPtr;           /* List object in which element should be
	                                 * stored */
	    int index;                  /* Index of element to store */
	    Tcl_Obj* valuePtr;          /* Tcl object to store in the designated
	                                 * list element */

	{
	    int result;                 /* Return value from this function */
	    List* listRepPtr;           /* Internal representation of the list
	                                 * being modified */
	    Tcl_Obj** elemPtrs;         /* Pointers to elements of the list */
	    int elemCount;              /* Number of elements in the list */
	
	    /* Ensure that the listPtr parameter designates an unshared list */
	
	    if ( Tcl_IsShared( listPtr ) ) {
	        panic( "Tcl_ListObjSetElement called with shared object" );

	    }
	    if ( listPtr->typePtr != &tclListType ) {
	        result = SetListFromAny( interp, listPtr );
	        if ( result != TCL_OK ) {
	            return result;


	        }
	    }
	    listRepPtr = (List*) listPtr->internalRep.otherValuePtr;
	    elemPtrs = listRepPtr->elements;
	    elemCount = listRepPtr->elemCount;
	
	    /* Ensure that the index is in bounds */
	
	    if ( index < 0 || index >= elemCount ) {
	        if ( interp != NULL ) {
	            Tcl_SetObjResult( interp,
	                              Tcl_NewStringObj( "list index out of range",
	                                                -1 ) );
	            return TCL_ERROR;


	        }
	    }
	
	    /* Add a reference to the new list element */
	
	    Tcl_IncrRefCount( valuePtr );
	
	    /* Remove a reference from the old list element */
	
	    Tcl_DecrRefCount( elemPtrs[ index ] );
	
	    /* Stash the new object in the list */
	
	    elemPtrs[ index ] = valuePtr;
	
	    /* Invalidate and free any old string representation */
	
	    Tcl_InvalidateStringRep( listPtr );
	
	    return TCL_OK;
	    

	}

Even without bytecode compilation, the performance improvement of
array-based applications that can be achieved by the _lset_ command
is substantial.  The following table shows run times in microseconds
\(on a 550 MHz Pentium III laptop, running a modified Tcl 8.4 on
Windows NT 4.0, Service Pack \#6\) of the three implementations of
_shuffle_ that appear in this TIP.

	                    RUN TIMES IN MICROSECONDS
	
	                                Version
	                     shuffle1       shuffle1a       shuffle1b
	                     (Naive)      (K combinator)  (lset command)
	 List length
	        1                 26               32              27            
	       10                108              152             101
	      100               1627             1462             936
	     1000             117831            14789            9574
	    10000       Test stopped           152853           96912

Similar \(30-50%\) improvements are observed on many of the array
related benchmarks that have been proposed.  Bytecode compilation is
expected to produce even greater improvements.

Another area where _lset_ can achieve a major performance gain is in
memory usage.  The author of this TIP has benchmarked competing
implementations of heapsort, one using Tcl arrays, and the other using
_lset_ to manipulate lists as linear arrays.  When sorting 80000
elements, the Tcl-array-based implementation used 12.7 megabytes of
memory; the list-based implementation was faster and used only 5.6
megabytes.  The explanation is simple: each entry in the hash table
requires an allocated block of twenty bytes of memory, plus the space
required for the hash key.  The hash key is a string, and requires at
least six bytes.  When both of these objects are aligned and padded
with the overheads imposed by _ckalloc_, they require about 80 bytes of
memory on the Windows NT platform.  The memory cost of an element of a
Tcl list, by comparison, is four bytes to hold the pointer to the
object.

# Discussion

There are several objections that can be foreseen to this proposal.

   * _Why implement the command in the Core and not as an extension?_

	   > In a word, _performance._  At the present state of Tcl
     development, only Core commands can be bytecoded.  The cost of
     the hash table lookups in the _Tcl\_ObjGetVar2_ and
     _Tcl\_ObjSetVar2_ calls is significant, and can be eliminated
     from many common usages by the bytecode compiler.  Since this
     command is likely to appear in inner loops, it is important to
     squeeze every bit of possible performance out of it.

   * _Why a new command in the global namespace?_

	   > The author of this TIP feels that having a single added command
     that is parallel to the existing list commands is not polluting
     the namespace excessively.  It would be a shame if this proposal
     founders upon the Naming of Names.

   * _Why a new command, rather than including this functionality in
     the proposed functionality of an extensible command for list
     manipulation?_

	   > The author of this TIP has yet to see a formal proposal of any
     extensible list manipulation command; the closest thing appears
     to be Andreas Kupries's _listx_ package
     <http://www.oche.de/~akupries/tcltk.html> .  Given the size and
     complexity of any such modification, it is unlikely that it will
     be available in the Core in time for an 8.4 release.  The
     performance improvements achievable by the _lset_ command are
     needed urgently.

   * _Isn't this [[29]](29.md) warmed over?_

	   > Several objectors to [[29]](29.md) indicated that they were willing to
     consider list element assignment implemented as a new command.

   * _Doesn't this proposal depend on multiple _index_ arguments to
     _lindex_ \([[22]](22.md)\)?

	   > This proposal can stand alone.  If multiple _index_ arguments
     to _lindex_ are also accepted, the resulting symmetry is
     pleasing.  Having multiple _index_ args to _lset_ is much
     more important, because it is horribly difficult to implement
     equivalent functionality in pure Tcl without introducing
     excessive calls to _Tcl\_DuplicateObj_.  In fact, the reference
     implementation of _lset_ presented in this TIP was motivated by
     the fact that its author gave up on the task and resorted to C.

# Implementation Notes

Having two versions of the syntax for the _lset_ command is perhaps
unattractive, but neither can be left out effectively.

The syntax where the indices are packaged as a single list allows a
_cursor_ into complex list structure to be maintained in a single
variable.  The list element that the cursor designates can be altered
with a single call to the _lset_ command, without needing to resort
to _eval_ \(a command that is both expensive and dangerous\) to expand
the indices inline.

The syntax where each index is a first-class object is motivated by
the performance of array-based algorithms.  Programmers who are using
lists as arrays know exactly how many subscripts they have, and in
fact are generally iterating through them.  A typical sort of usage
might be the naïve matrix multiplication shown below.

	 # Construct a matrix with 'rows' rows and 'columns' columns
	 # having an initial value of 'initCellValue' in each cell.
	 
	 proc matrix { rows columns { initCellValue {} } } {
	     set oneRow {}
	     for { set i 0 } { $i < $columns } { incr i } {
	         lappend oneRow $initCellValue

	     }
	     set matrix {}
	     for { set i 0 } { $i < $rows } { incr i } {
	         lappend matrix $oneRow

	     }
	     return $matrix

	 }
	 
	 # Multiply two matrices
	 
	 proc matmult { x y } {
	 
	     set m [llength $x];                 # Number of rows of left matrix
	     set n [llength [lindex $x 0]];      # Number of columns of left matrix
	 
	     if { $n != [llength $y] } {
	         return -code error "rank error: left operand has $n columns\
	                             while right operand has [llength $y] rows"

	     }
	 
	     set k [llength [lindex $y 0]];      # Number of columns of right matrix
	 
	     # Construct a matrix to hold the product
	 
	     set product [matrix $m $k]
	 
	     for { set i 0 } { $i < $m } { incr i } {
	         for { set j 0 } { $j < $k } { incr j } {
	             lset product $i $j 0.0
	             for { set r 0 } { $r < $n } { incr r } {
	                 set term [expr { [lindex $x $i $r] * [lindex $y $r $j] }]
	                 lset product $i $j [expr { [lindex $product $i $j] + $term }]



	             }
	         }
	     }
	 
	     return $product

	 }

Note how we have an [lset] operation in the innermost loop, executed
\(m\*n\*k\) times.

If in this instance, we have to write:

	                 set indices [list $i $j]
	                 lset product $indices \
	                     [expr { [lindex $product $indices] + $term }]

in place of the [lset] shown above, we add the cost of forming the
list of indices to the cost of the inner loop.  This cost is not to be
sneezed at -- it's two expensive calls to _ckalloc._  \(The cost can
be avoided, at some cost in readability, by maintaning a variable
containing the index list, and altering its elements with other uses
of [lset].\)

Richard Suchenwirth suggested the compromise that appears in this
proposal.  This scheme will perilous to performance if implemented
naively.  If the implementation of [lset] simply calls
_Tcl\_ListObjGetElements_, look what happens to the inner loop of our
_shuffle1b_ procedure:

	      for { set i 0 } { $i < $n } { incr i } {
	          set j [expr {int(rand()*$n)}]
	          set temp [lindex $list $j]
	          lset list $j [lindex $list $i]
	          lset list $i $temp

	      }

   * Initially, \{set i 0\} sets i to the constant "0"; it is a string.

   * Evaluating the conditional \{$i < $n\} will shimmer i to an integer;
     now it's an integer.  \(We had to do a call to strtol here.\)

   * The [lindex $list $i] call now has to consider $i as a list of
     indices, and shimmers it to the list.  This discards the internal
     rep, parses the string rep into a list, and then reconverts its
     first element to an integer.

   * OK, now the 'lset' is happy, and no further shimmering occurs...

   * ... until we get to the \{incr i\}.  Now we go back to the string rep
     once again, shimmer it to an integer \(yet another call to strtol\),
     and invalidate the string rep because we've incremented the integer.

   * Now we get back into the [lindex] once again, and need a list
     rep.  This time, we have to format the integer as a string, parse
     it as a list, take the object representing element 0, and reparse
     that as an integer.

This sequence has converted the integer to and from a string, and
performed four calls to _ckalloc_, but resulted in the same integer
that we started with!

It is possible for a sufficiently smart compromise implementation
to avoid all this shimmering.  In the case where _objc==4_, the
_lset_ command must:

 1. Test whether _objv[[2]](2.md)_ designates an object whose internal
    representation holds an integer.  If so, simply use it as an index.

 2. Test whether _objv[[2]](2.md)_ designates an object whose internal
    representation holds a list.  If so, perform the recursive
    extraction of indexed elements from sublists described above.

 3. Form the string representation of _objv[[2]](2.md)_ and test whether
    it is _end_ or _end-_ followed by an integer.  If so, use it
    as an index.

 4. Attempt to coerce _objv[[2]](2.md)_ to an integer; if successful, use
    the result as an integer.

 5. Attempt to coerce _objv[[2]](2.md)_ to a list; if successful, use
    the result as an index list.

 6. Report a malformed _index_ argument; the _indexList_ parameter
    is not a well-formed list.

This logic handles all the cases of singleton lists transparently; it
is effectively a simple-minded type inference that optimizes away
needless conversions.  With it in place, none of the _lset_ examples
shown in this TIP will suffer from type shimmering.

In the event that the related [[22]](22.md) is approved, the logic for parsing
an index list will likely be combined with that used in the _lindex_
command.

Bytecoding variadic commands like _lset_ presents some interesting
technical challenges; a discussion in progress on the Tcl'ers Wiki
<http://wiki.tcl.tk/1604>  is recording the design
decisions being made for bytecoding _lset_ so that they can be
applied to similar commands in the future.

# See Also

[[22]](22.md), [[29]](29.md).

# Change History

This TIP has undergone several revisions by the original author.
The most significant was made on 20 May 2001, where the syntax was
revised to allow for either several indices inline on the command line
or a list of indices.

# Copyright

This document has been placed in the public domain.

Name change from tip/330.tip to tip/330.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

TIP:		330
Title:		Eliminate interp->result from the Public Headers
Version:	$Revision: 1.5 $
Author:		Kevin B. Kenny <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	22-Sep-2008
Post-History:
Tcl-Version:	8.6


~ Abstract

This TIP proposes to eliminate the long-deprecated ''interp''->''result''
field from the public headers.

~ Proposal

The include file ''tcl.h'' is to be modified so that the ''result'' field of
the ''Tcl_Interp'' data structure will be renamed to ''unused1'' unless a
preprocessor symbol, '''USE_INTERP_RESULT''' is defined.

Note that this change leaves the ''result'' field in the internal ''Interp''
data structure untouched, and all the code that manipulates it will still be
there. Stubs compatiblity is thus preserved for extensions that compile
against an 8.5 or earlier code base, and full source-level compatibility is
available with the appropriate preprocessor definition.

~ Rationale

The ''result'' field in this structure has been deprecated for a decade now,
and yet extensions that use it still turn up. Extension writers need to be put
on sterner notice that it ''will'' disappear as soon as Tcl 9.0 development is
open.

~ Copyright

Copyright � 2008 by Kevin B. Kenny.

This document may be distributed subject to the terms and conditions set forth
in the Open Publication License, version 1.0
[http://www.opencontent.org/openpub/].

<
|
<
|
|
|
|
|
|
|
>

|

|


|

|
|
|

|





|

|

|


|

|



|
>

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

# TIP 330: Eliminate interp->result from the Public Headers

	Author:		Kevin B. Kenny <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	22-Sep-2008
	Post-History:
	Tcl-Version:	8.6
-----

# Abstract

This TIP proposes to eliminate the long-deprecated _interp_->_result_
field from the public headers.

# Proposal

The include file _tcl.h_ is to be modified so that the _result_ field of
the _Tcl\_Interp_ data structure will be renamed to _unused1_ unless a
preprocessor symbol, **USE\_INTERP\_RESULT** is defined.

Note that this change leaves the _result_ field in the internal _Interp_
data structure untouched, and all the code that manipulates it will still be
there. Stubs compatiblity is thus preserved for extensions that compile
against an 8.5 or earlier code base, and full source-level compatibility is
available with the appropriate preprocessor definition.

# Rationale

The _result_ field in this structure has been deprecated for a decade now,
and yet extensions that use it still turn up. Extension writers need to be put
on sterner notice that it _will_ disappear as soon as Tcl 9.0 development is
open.

# Copyright

Copyright © 2008 by Kevin B. Kenny.

This document may be distributed subject to the terms and conditions set forth
in the Open Publication License, version 1.0
<http://www.opencontent.org/openpub/> .

Name change from tip/331.tip to tip/331.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

TIP:		331
Title:		Allow [lset] to Extend Lists
Version:	$Revision: 1.5 $
Author:		Kevin B. Kenny <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	22-Sep-2008
Post-History:
Tcl-Version:	8.6


~ Abstract

This TIP proposes to modify the '''lset''' command to allow it to extend
lists.

~ Proposal

The '''lset''' command shall be modified to allow the index ''end+1'' (or any
equivalent index designating the element one beyond the last element of the
list). For the simple usage:

|    lset list end+1 foo

the effect is the same as if the script had evaluated the command:

|    lappend list foo

For the usage:

|    lset list $n end+1 foo

the effect is much the same as if the script had evaluated:

|    set temp [lindex $list $n]
|    lappend temp foo
|    lset list $n $temp

(except, of course that no ''temp'' variable is created)

The usage:

|    lset list end+1 0 foo

or, equivalently,

|    lset list end+1 end+1 foo

is equivalent to

|    lappend list [list foo]

~ Rationale

Clearly, there are equivalent constructs to all of these usages. Nevertheless,
it is convenient not to have to worry about whether a given index is in
bounds, particularly when iterating through a vector or matrix. With the
proposed change, many of the standard algorithms in linear algebra will just
work, without either having to preinitialize a list to a given size or to have
a test to determine whether to use '''lappend''' or '''lset''' to store a
given element.

~ Alternatives

Explicitly out of scope is the treatment of indices greater than or equal to
''end+2''. Setting non-contiguous elements would raise false expectations of
sparse lists, '''NULL''' elements, and so on.

~ Copyright

Copyright � 2008 by Kevin B. Kenny.

This document may be distributed subject to the terms and conditions set forth
in the Open Publication License, version 1.0
[http://www.opencontent.org/openpub/].

<
|
<
|
|
|
|
|
|
|
>

|

|


|

|

|

|



|



|



|
|
|

|



|



|



|

|






|


|


|
|

|

|



|
>

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

# TIP 331: Allow [lset] to Extend Lists

	Author:		Kevin B. Kenny <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	22-Sep-2008
	Post-History:
	Tcl-Version:	8.6
-----

# Abstract

This TIP proposes to modify the **lset** command to allow it to extend
lists.

# Proposal

The **lset** command shall be modified to allow the index _end\+1_ \(or any
equivalent index designating the element one beyond the last element of the
list\). For the simple usage:

	    lset list end+1 foo

the effect is the same as if the script had evaluated the command:

	    lappend list foo

For the usage:

	    lset list $n end+1 foo

the effect is much the same as if the script had evaluated:

	    set temp [lindex $list $n]
	    lappend temp foo
	    lset list $n $temp

\(except, of course that no _temp_ variable is created\)

The usage:

	    lset list end+1 0 foo

or, equivalently,

	    lset list end+1 end+1 foo

is equivalent to

	    lappend list [list foo]

# Rationale

Clearly, there are equivalent constructs to all of these usages. Nevertheless,
it is convenient not to have to worry about whether a given index is in
bounds, particularly when iterating through a vector or matrix. With the
proposed change, many of the standard algorithms in linear algebra will just
work, without either having to preinitialize a list to a given size or to have
a test to determine whether to use **lappend** or **lset** to store a
given element.

# Alternatives

Explicitly out of scope is the treatment of indices greater than or equal to
_end\+2_. Setting non-contiguous elements would raise false expectations of
sparse lists, **NULL** elements, and so on.

# Copyright

Copyright © 2008 by Kevin B. Kenny.

This document may be distributed subject to the terms and conditions set forth
in the Open Publication License, version 1.0
<http://www.opencontent.org/openpub/> .

Name change from tip/332.tip to tip/332.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

TIP:            332
Title:          Half-Close for Bidirectional Channels
Version:        $Revision: 1.6 $
Author:         Alexandre Ferrieux <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        25-Sep-2008
Post-History:   
Keywords:       Tcl,channel,close,socket,shutdown
Obsoletes:      301
Tcl-Version:    8.6


~ Abstract

This TIP proposes to extend the '''close'''/'''chan close''' commands to let
them perform an unidirectional "half-close" on bidirectional channels.

~ Background

Bidirectional channels (sockets and command pipelines) allow Tcl to make an
efficient use of a "filter process", by exchanging data back and forth over an
abstract "single" channel.

However, this single channel abstraction comes with a too coarse-grained
'''close''' primitive. Indeed, it closes both directions simultaneously, while
it is often desirable to close "gracefully" the half-connection ''to'' the
filter process, leaving the return path open. The effect of such a half-close
is that the filter receives a bona fide EOF alone, without a nearly
simultaneous SIGPIPE on its write end if it happens to be writing at that
time. Moreover, if the filter is itself comprised of a pipeline of processes,
some of which doing buffered I/O, then this graceful EOF may be the only way
of flushing the chain and receiving back precious data.

This technique is supported by all modern OSes: for pipes there are actually
two separate file descriptors/handles, and it suffices to close() the write
side; for sockets, a single fd is used, but a specific syscall, shutdown(),
brings back the ability to half-close. Hence it is fairly natural for a
universal "OS glove" like Tcl to expose this universal feature.

~ Proposed Change

This TIP proposes to extend the '''close''' and twin brother '''chan close'''
commands to take an optional extra "direction" argument, indicating a
half-close on the substream going in that direction:

 > '''close''' ''channel'' ?'''read'''|'''write'''?

When the extra direction argument (which may be abbreviated) is given, first
the OS-level half-close is performed: this means a shutdown() on a socket, and
a close() of one end of a pipe for a command pipeline. Then, the Tcl-level
channel data structure is either kept or freed depending on whether the other
direction is still open:

|	set f [open |command r+]
|	...
|	close $f w ;# $f still exists
|	...
|	close $f r ;# now $f is gone

Also, a single-argument '''close''' on an already half-closed bi-channel is
defined to just "finish the job", which allows to write blind cleanup
procedures easily:

|	if {[catch {
|	  set f [open |command r+]
|	  ...
|	  close $f w
|	  ...
|	} err]} {
|	  ...
|	  close $f ;# close what's left
|	}


In the case of a command pipeline, the child-reaping duty falls upon the
shoulders of the last close or half-close, so that an error condition at this
stage (like "Child exited abnormally") doesn't leak system resources.

Last, a half-close on an already closed half raises an error:

|	set [open |command r+]
|	close $f w
|	close $f w
|	==> channel "file3" wasn't opened for writing

And the same applies to wrong-sided unidirectional channels:

|	set [open filename r]
|	close $f w
|	==> channel "file3" wasn't opened for writing

~ Rationale

The concept has gone full circle. From an initial half-close proposal very
close to the current one, an ambitious '''chan split''' generalization was
born in the surrounding enthusiasm, and specified in [301]. Then, [304]'s
'''chan pipe''' was accepted, which addressed most of the "splitting" demand
(asymmetric fconfigures on both ends of a command pipeline can be done by
redirecting to a standalone pipe). Moreover, in hindsight it appears that the
implementation of [301] had very long-ranging effects on various channel
implementations, which are more numerous today than before (TLS, reflection
API).

As a consequence, [301] is being withdrawn, and the current TIP goes back to
its initial, lower profile: just provide the half-close.

~ C Interface

Luckily, the polymorphic channel API in Tcl has been fitted with a half-close function for nearly 10 years (!): the Tcl_ChannelType structure has had a ''close2proc'' member since 1998 in order to avoid deadlocks when closing a command pipeline. As a consequence, the implementation of half-close can be done with a constant channel ABI, avoiding any compatibility issue for extensions.

Still, the ''close2proc'' member does not have public status. To promote symmetry between the script-level and public C APIs, this TIP proposes to add an entry in the main stub table with the following signature:

   > int '''Tcl_CloseEx'''(Tcl_Interp *''interp'', Tcl_Channel ''chan'', int ''flags'')

The behavior being defined as mirrorring the script-level semantics described bove, where ''flags'' is either 0 (meaning bidirectional close) or one of TCL_CLOSE_READ and TCL_CLOSE_WRITE (meaning half-close).

~ Reference Implementation

See Patch 219159 [https://sourceforge.net/tracker/index.php?func=detail&aid=219159&group_id=10894&atid=310894].

After a discussion with Andreas Kupries, the plan is to half-close-enable only raw (unstacked) channels for the time being, raising an explicit error when trying a half-close on a non-bottom channel. This leaves time to carefully design the necessary API extension of the generic stacking and reflection layers, while preparing a fully compatible change (error cases becoming valid).

On the channel-type-dependent side, only sockets and pipelines will be half-close-enabled for now: these are assumed to represent the most pressing demand.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|

|




|
|








|
|



|

|



|

|
|
|



|
|
|
|
|

|



|
|
|
|
|
|
|
|
<
>



|



|
|
|
|



|
|
|

|


|
|
|
|
|
|
|
|

|


|

|

|

|

|

|

|

|



|


>

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

# TIP 332: Half-Close for Bidirectional Channels

	Author:         Alexandre Ferrieux <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        25-Sep-2008
	Post-History:   
	Keywords:       Tcl,channel,close,socket,shutdown
	Obsoletes:      301
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes to extend the **close**/**chan close** commands to let
them perform an unidirectional "half-close" on bidirectional channels.

# Background

Bidirectional channels \(sockets and command pipelines\) allow Tcl to make an
efficient use of a "filter process", by exchanging data back and forth over an
abstract "single" channel.

However, this single channel abstraction comes with a too coarse-grained
**close** primitive. Indeed, it closes both directions simultaneously, while
it is often desirable to close "gracefully" the half-connection _to_ the
filter process, leaving the return path open. The effect of such a half-close
is that the filter receives a bona fide EOF alone, without a nearly
simultaneous SIGPIPE on its write end if it happens to be writing at that
time. Moreover, if the filter is itself comprised of a pipeline of processes,
some of which doing buffered I/O, then this graceful EOF may be the only way
of flushing the chain and receiving back precious data.

This technique is supported by all modern OSes: for pipes there are actually
two separate file descriptors/handles, and it suffices to close\(\) the write
side; for sockets, a single fd is used, but a specific syscall, shutdown\(\),
brings back the ability to half-close. Hence it is fairly natural for a
universal "OS glove" like Tcl to expose this universal feature.

# Proposed Change

This TIP proposes to extend the **close** and twin brother **chan close**
commands to take an optional extra "direction" argument, indicating a
half-close on the substream going in that direction:

 > **close** _channel_ ?**read**\|**write**?

When the extra direction argument \(which may be abbreviated\) is given, first
the OS-level half-close is performed: this means a shutdown\(\) on a socket, and
a close\(\) of one end of a pipe for a command pipeline. Then, the Tcl-level
channel data structure is either kept or freed depending on whether the other
direction is still open:

		set f [open |command r+]
		...
		close $f w ;# $f still exists
		...
		close $f r ;# now $f is gone

Also, a single-argument **close** on an already half-closed bi-channel is
defined to just "finish the job", which allows to write blind cleanup
procedures easily:

		if {[catch {
		  set f [open |command r+]
		  ...
		  close $f w
		  ...
		} err]} {
		  ...
		  close $f ;# close what's left

		}

In the case of a command pipeline, the child-reaping duty falls upon the
shoulders of the last close or half-close, so that an error condition at this
stage \(like "Child exited abnormally"\) doesn't leak system resources.

Last, a half-close on an already closed half raises an error:

		set [open |command r+]
		close $f w
		close $f w
		==> channel "file3" wasn't opened for writing

And the same applies to wrong-sided unidirectional channels:

		set [open filename r]
		close $f w
		==> channel "file3" wasn't opened for writing

# Rationale

The concept has gone full circle. From an initial half-close proposal very
close to the current one, an ambitious **chan split** generalization was
born in the surrounding enthusiasm, and specified in [[301]](301.md). Then, [[304]](304.md)'s
**chan pipe** was accepted, which addressed most of the "splitting" demand
\(asymmetric fconfigures on both ends of a command pipeline can be done by
redirecting to a standalone pipe\). Moreover, in hindsight it appears that the
implementation of [[301]](301.md) had very long-ranging effects on various channel
implementations, which are more numerous today than before \(TLS, reflection
API\).

As a consequence, [[301]](301.md) is being withdrawn, and the current TIP goes back to
its initial, lower profile: just provide the half-close.

# C Interface

Luckily, the polymorphic channel API in Tcl has been fitted with a half-close function for nearly 10 years \(!\): the Tcl\_ChannelType structure has had a _close2proc_ member since 1998 in order to avoid deadlocks when closing a command pipeline. As a consequence, the implementation of half-close can be done with a constant channel ABI, avoiding any compatibility issue for extensions.

Still, the _close2proc_ member does not have public status. To promote symmetry between the script-level and public C APIs, this TIP proposes to add an entry in the main stub table with the following signature:

   > int **Tcl\_CloseEx**\(Tcl\_Interp \*_interp_, Tcl\_Channel _chan_, int _flags_\)

The behavior being defined as mirrorring the script-level semantics described bove, where _flags_ is either 0 \(meaning bidirectional close\) or one of TCL\_CLOSE\_READ and TCL\_CLOSE\_WRITE \(meaning half-close\).

# Reference Implementation

See Patch 219159 <https://sourceforge.net/tracker/index.php?func=detail&aid=219159&group_id=10894&atid=310894> .

After a discussion with Andreas Kupries, the plan is to half-close-enable only raw \(unstacked\) channels for the time being, raising an explicit error when trying a half-close on a non-bottom channel. This leaves time to carefully design the necessary API extension of the generic stacking and reflection layers, while preparing a fully compatible change \(error cases becoming valid\).

On the channel-type-dependent side, only sockets and pipelines will be half-close-enabled for now: these are assumed to represent the most pressing demand.

# Copyright

This document has been placed in the public domain.

Name change from tip/333.tip to tip/333.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

TIP:            333
Title:          New Variable and Namespace Resolving Interface
Version:        $Revision: 1.4 $
Author:         Arnulf Wiedemann <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        13-Oct-2008
Post-History:   
Keywords:       Tcl,resolution
Tcl-Version:    8.7


~ Abstract

This is a TIP to allow easy command and variable resolving for itcl-ng, but is
not restricted to itcl-ng. It should be possible for an application to drive
the rules for command and variable lookup using the interface described
below. This TIP should allow to get rid of namespace and interpreter resolvers
for itcl-ng.

~ Rationale

The current implementation for command and variable resolution using namespace
and interpreter resolvers has a lot of problems for the Tcl core
implementation. Second problem is the additonal performance penality for using
the resolvers (much more code is needed in the application). The suggested
interface allows to hide Tcl core details concerning handling of variables and
commands from the outside. If the interface would be made public, it would be
also possible to avoid use of tclInt.h in that area and to only use stubs
interfaces, which means itcl-ng versions would be independent of Tcl versions.
Other applications (e.g. snit) could also use this interface for fast lookup
of variables and commands.

~ C-API Specification

At the moment there is only a need for a C-API for the suggested functionality

~~ For Commands (methods/procs)

 > typedef int (*'''TclCheckClassProtectionProc''')(Tcl_Interp *''interp'',
   Tcl_Namespace *''nsPtr'', const char *''varName'', ClientData
   ''clientData'');

 > typedef void (*'''Tcl_ClassCommandDeleteProc''')(ClientData
   ''clientData'');

 > typedef void (*'''Tcl_ObjectCommandDeleteProc''')(ClientData
   ''clientData'');

 > ClientData '''Tcl_RegisterClassMethod'''(Tcl_Interp *''interp'',
   Tcl_Namespace *''nsPtr'', const char *''cmdName'', ClientData
   ''clientData'');

 > Tcl_Command '''Tcl_RegisterObjectMethod'''(TclInterp *''interp'',
   ClientData ''objectPtr'', const char *''cmdName'', Tcl_Command ''cmdPtr'',
   ClientData ''clientData'');

 > void '''Tcl_UnregisterClassCommand'''(Tcl_Interp *''interp'', Tcl_Namespace
   *''nsPtr'', const char *''cmdName'', Tcl_ClassCommandDeleteProc
   ''delProc'');

 > void '''Tcl_UnregisterObjectCommand'''(Tcl_Interp *''interp'', ClientData
   ''objectPtr'', const char *''cmdName'', Tcl_ObjectCommandDeleteProc
   ''delProc'');

 > int '''Tcl_SetCallFrameObject'''(Tcl_Interp *''interp'', ClientData
   ''objectPtr'');

 > int '''Tcl_SetNamespaceCommandProtectionCallback'''(Tcl_Interp *''interp'',
   Tcl_Namespace *''nsPtr'', TclCheckNamespaceProtection ''cnpProc'');

~~ For Variables (variables/commons)

 > typedef int (*'''TclCheckClassProtection''')(Tcl_Interp *''interp'',
   Tcl_Namespace *''nsPtr'', const char *''varName'', ClientData
   ''clientData'');

 > typedef void (*'''Tcl_ObjectVariableDeleteProc''')(ClientData
   ''clientData'');

 > typedef void (*'''Tcl_ClassVariableDeleteProc''')(ClientData
   ''clientData'');

 > ClientData '''Tcl_RegisterClassVariable'''(Tcl_Interp *''interp'',
   Tcl_Namespace *''nsPtr'', const char *''varName'', ClientData
   ''clientData'');

 > Tcl_Var '''Tcl_RegisterObjectVariable'''(TclInterp *''interp'', ClientData
   ''objectPtr'', const char *''varName'', ClientData ''clientData'', Tcl_Var
   ''varPtr'');

 > void '''Tcl_UnregisterClassVariable'''(Tcl_Interp *''interp'',
   Tcl_Namespace *''nsPtr'', const char *''varName'',
   Tcl_ClassVariableDeleteProc ''delProc'');

 > void '''Tcl_UnregisterObjectVariable'''(Tcl_Interp *''interp'', ClientData
   ''objectPtr'', const char *''varName'', Tcl_ObjectVariableDeleteProc
   ''delProc'');

 > int '''Tcl_SetCallFrameObject'''(Tcl_Interp *''interp'', ClientData
   ''objectPtr'');

 > int '''Tcl_SetNamespaceVariableProtectionCallback'''(Tcl_Interp
   *''interp'', Tcl_Namespace *''nsPtr'', TclCheckNamespaceProtection
   ''cnpProc'');

~ Detailed Description

For details on how itcl-ng is using variables scopes and command scopes look
here: http://wiki.tcl.tk/21676

I am only describing details for variables, as variables are more complex and
commands are handled very similar to variables in itcl-ng concerning lookup.
There is the need for collecting all variables from an itcl-ng class hierarchy
for every class in the hierarchy together with the class (which is a
namespace). Then for each such collection there is the need to specify which
variables are used phisically based on a per object basis, because every
object has an own set of variables for the class hierarchy tied to the object.
There is the need to switch these variable collections during runtime for
every itcl-ng method (a method is similar to a tcl proc) which is called.
Every method is called in the class (namespace) where it is defined. Therefor
it is necessary to have a registration mechanism for variables on a class and
object base. During execution when calling a method the appropriate set of
object variables for the currently active object has to be available on a per
CallFrame basis (Tcl_SetCallFrameObject).

The protection check function shall be called when a class variable is found
to check the protection level by the caller according to the protection rules
for the application. The clientData structure has to be filled by the
application with the appropriate data when registering a variable.

The suggested rules for lookup should be: on all places where the namespace
resolvers are called at the moment to additionally (instead of) do the lookup
for the new interfaces and if there is nothing found continue with normal
lookup.

The *Unregister* functions are for cleaning up variable information when no
longer needed. The application has to do the calls and the deleteProc is used
for freeing the contents of the clientData containers used when registering
the variables. If no registered variable for a class or object is left, also
the data structures in Tcl core used for registering and lookup should be
freed.

For commands substitute variable by command in the last few sections.

The names for the interface functions are just a suggestion, maybe someone
finds better names.

~ Reference Implementation

A reference implementaion has been done for itcl-ng using the namespace
resolvers and in the resolver functions using the described interfaces. It
runs aganist the test suite without problems.

~ Details about the Reference Implementation

I have used a straight forward approach, which was easy to implement.

All lookup info is at the moment in a structure available with Tcl_SetAssocData/Tcl_GetAssocData

Tcl_RegisterClassVariable fills a Tcl_HashTable with the namespace as the key (not necessary in Tcl core there the info should be tied to the Namespace structure). The value is a Tcl_HashTable for the variable infos. In that hash table there are entries with varName as a key and clientData as the value.

Tcl_RegisterObjectVariable fills a Tcl_HashTable with the objectClientData as key and value is a Tcl_HashTable. The key for the hash table is clientData tied to a varName from Tcl_RegisterClassVariable and if varPtr != NULL then it is the value for the hash table otherwise a new variable is created and used for the varPtr. The variable is created at the moment in a special per object namespace but better should be stored in a per object TclVarHashTable.

Lookup in the namespace resolvers fetches the lookup data structure, looks with namespace and varName for clientData, and if found calls Tcl_CheckClassProtection and if TCL_OK is returned gets the itcl object and looks for the varPtr with objectClientData and clientData and if successful returns varPtr.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|







|




|




|


|



|

|
|
|

|
|

|
|

|
|
|

|
|
|

|
|
|

|
|
|

|
|

|
|

|

|
|
|

|
|

|
|

|
|
|

|
|
|

|
|
|

|
|
|

|
|

|
|
|

|


|




|
|



|
|



|







|



|











|





|



|

|

|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

# TIP 333: New Variable and Namespace Resolving Interface

	Author:         Arnulf Wiedemann <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        13-Oct-2008
	Post-History:   
	Keywords:       Tcl,resolution
	Tcl-Version:    8.7
-----

# Abstract

This is a TIP to allow easy command and variable resolving for itcl-ng, but is
not restricted to itcl-ng. It should be possible for an application to drive
the rules for command and variable lookup using the interface described
below. This TIP should allow to get rid of namespace and interpreter resolvers
for itcl-ng.

# Rationale

The current implementation for command and variable resolution using namespace
and interpreter resolvers has a lot of problems for the Tcl core
implementation. Second problem is the additonal performance penality for using
the resolvers \(much more code is needed in the application\). The suggested
interface allows to hide Tcl core details concerning handling of variables and
commands from the outside. If the interface would be made public, it would be
also possible to avoid use of tclInt.h in that area and to only use stubs
interfaces, which means itcl-ng versions would be independent of Tcl versions.
Other applications \(e.g. snit\) could also use this interface for fast lookup
of variables and commands.

# C-API Specification

At the moment there is only a need for a C-API for the suggested functionality

## For Commands \(methods/procs\)

 > typedef int \(\***TclCheckClassProtectionProc**\)\(Tcl\_Interp \*_interp_,
   Tcl\_Namespace \*_nsPtr_, const char \*_varName_, ClientData
   _clientData_\);

 > typedef void \(\***Tcl\_ClassCommandDeleteProc**\)\(ClientData
   _clientData_\);

 > typedef void \(\***Tcl\_ObjectCommandDeleteProc**\)\(ClientData
   _clientData_\);

 > ClientData **Tcl\_RegisterClassMethod**\(Tcl\_Interp \*_interp_,
   Tcl\_Namespace \*_nsPtr_, const char \*_cmdName_, ClientData
   _clientData_\);

 > Tcl\_Command **Tcl\_RegisterObjectMethod**\(TclInterp \*_interp_,
   ClientData _objectPtr_, const char \*_cmdName_, Tcl\_Command _cmdPtr_,
   ClientData _clientData_\);

 > void **Tcl\_UnregisterClassCommand**\(Tcl\_Interp \*_interp_, Tcl\_Namespace
   *_nsPtr_, const char \*_cmdName_, Tcl\_ClassCommandDeleteProc
   _delProc_\);

	 > void **Tcl\_UnregisterObjectCommand**\(Tcl\_Interp \*_interp_, ClientData
   _objectPtr_, const char \*_cmdName_, Tcl\_ObjectCommandDeleteProc
   _delProc_\);

	 > int **Tcl\_SetCallFrameObject**\(Tcl\_Interp \*_interp_, ClientData
   _objectPtr_\);

	 > int **Tcl\_SetNamespaceCommandProtectionCallback**\(Tcl\_Interp \*_interp_,
   Tcl\_Namespace \*_nsPtr_, TclCheckNamespaceProtection _cnpProc_\);

## For Variables \(variables/commons\)

 > typedef int \(\***TclCheckClassProtection**\)\(Tcl\_Interp \*_interp_,
   Tcl\_Namespace \*_nsPtr_, const char \*_varName_, ClientData
   _clientData_\);

 > typedef void \(\***Tcl\_ObjectVariableDeleteProc**\)\(ClientData
   _clientData_\);

 > typedef void \(\***Tcl\_ClassVariableDeleteProc**\)\(ClientData
   _clientData_\);

 > ClientData **Tcl\_RegisterClassVariable**\(Tcl\_Interp \*_interp_,
   Tcl\_Namespace \*_nsPtr_, const char \*_varName_, ClientData
   _clientData_\);

 > Tcl\_Var **Tcl\_RegisterObjectVariable**\(TclInterp \*_interp_, ClientData
   _objectPtr_, const char \*_varName_, ClientData _clientData_, Tcl\_Var
   _varPtr_\);

 > void **Tcl\_UnregisterClassVariable**\(Tcl\_Interp \*_interp_,
   Tcl\_Namespace \*_nsPtr_, const char \*_varName_,
   Tcl\_ClassVariableDeleteProc _delProc_\);

 > void **Tcl\_UnregisterObjectVariable**\(Tcl\_Interp \*_interp_, ClientData
   _objectPtr_, const char \*_varName_, Tcl\_ObjectVariableDeleteProc
   _delProc_\);

 > int **Tcl\_SetCallFrameObject**\(Tcl\_Interp \*_interp_, ClientData
   _objectPtr_\);

 > int **Tcl\_SetNamespaceVariableProtectionCallback**\(Tcl\_Interp
   *_interp_, Tcl\_Namespace \*_nsPtr_, TclCheckNamespaceProtection
   _cnpProc_\);

# Detailed Description

For details on how itcl-ng is using variables scopes and command scopes look
here: <http://wiki.tcl.tk/21676>

I am only describing details for variables, as variables are more complex and
commands are handled very similar to variables in itcl-ng concerning lookup.
There is the need for collecting all variables from an itcl-ng class hierarchy
for every class in the hierarchy together with the class \(which is a
namespace\). Then for each such collection there is the need to specify which
variables are used phisically based on a per object basis, because every
object has an own set of variables for the class hierarchy tied to the object.
There is the need to switch these variable collections during runtime for
every itcl-ng method \(a method is similar to a tcl proc\) which is called.
Every method is called in the class \(namespace\) where it is defined. Therefor
it is necessary to have a registration mechanism for variables on a class and
object base. During execution when calling a method the appropriate set of
object variables for the currently active object has to be available on a per
CallFrame basis \(Tcl\_SetCallFrameObject\).

The protection check function shall be called when a class variable is found
to check the protection level by the caller according to the protection rules
for the application. The clientData structure has to be filled by the
application with the appropriate data when registering a variable.

The suggested rules for lookup should be: on all places where the namespace
resolvers are called at the moment to additionally \(instead of\) do the lookup
for the new interfaces and if there is nothing found continue with normal
lookup.

The \*Unregister\* functions are for cleaning up variable information when no
longer needed. The application has to do the calls and the deleteProc is used
for freeing the contents of the clientData containers used when registering
the variables. If no registered variable for a class or object is left, also
the data structures in Tcl core used for registering and lookup should be
freed.

For commands substitute variable by command in the last few sections.

The names for the interface functions are just a suggestion, maybe someone
finds better names.

# Reference Implementation

A reference implementaion has been done for itcl-ng using the namespace
resolvers and in the resolver functions using the described interfaces. It
runs aganist the test suite without problems.

# Details about the Reference Implementation

I have used a straight forward approach, which was easy to implement.

All lookup info is at the moment in a structure available with Tcl\_SetAssocData/Tcl\_GetAssocData

Tcl\_RegisterClassVariable fills a Tcl\_HashTable with the namespace as the key \(not necessary in Tcl core there the info should be tied to the Namespace structure\). The value is a Tcl\_HashTable for the variable infos. In that hash table there are entries with varName as a key and clientData as the value.

Tcl\_RegisterObjectVariable fills a Tcl\_HashTable with the objectClientData as key and value is a Tcl\_HashTable. The key for the hash table is clientData tied to a varName from Tcl\_RegisterClassVariable and if varPtr != NULL then it is the value for the hash table otherwise a new variable is created and used for the varPtr. The variable is created at the moment in a special per object namespace but better should be stored in a per object TclVarHashTable.

Lookup in the namespace resolvers fetches the lookup data structure, looks with namespace and varName for clientData, and if found calls Tcl\_CheckClassProtection and if TCL\_OK is returned gets the itcl object and looks for the varPtr with objectClientData and clientData and if successful returns varPtr.

# Copyright

This document has been placed in the public domain.

Name change from tip/334.tip to tip/334.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

TIP:		334
Title:		Make 'lrepeat' Accept Zero as a Count
Version:	$Revision: 1.2 $
Author:		Michael Thomas Greer <[email protected]>
State:		Withdrawn
Type:		Project
Tcl-Version:	8.6
Vote:		Pending
Created:	13-Oct-2008
Post-History:	
Keywords:	empty list


~ Abstract

Following on from [323], the '''lrepeat''' command should also act gracefully
when a repeat count of zero is used, as an empty list is still a valid list.

~ Rationale

A list of zero items is a valid, empty list. In my own experience (I cannot
speak for others'), generating a list of ''N'' identical elements is more
often an algorithmic expression than a literal shorthand, and often enough an
empty list is the correct result. All other core list commands properly handle
empty lists; but '''lrepeat''' complains when given a count of zero
repetitions, requiring additional code to handle this (doubly) exceptional
condition.

~ Proposal

The '''lrepeat''' command should be changed so that when it's first,
''count'', argument is zero, it returns an empty list.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|
|


|
|


|

|
|

|


>

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

# TIP 334: Make 'lrepeat' Accept Zero as a Count

	Author:		Michael Thomas Greer <[email protected]>
	State:		Withdrawn
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Pending
	Created:	13-Oct-2008
	Post-History:	
	Keywords:	empty list
-----

# Abstract

Following on from [[323]](323.md), the **lrepeat** command should also act gracefully
when a repeat count of zero is used, as an empty list is still a valid list.

# Rationale

A list of zero items is a valid, empty list. In my own experience \(I cannot
speak for others'\), generating a list of _N_ identical elements is more
often an algorithmic expression than a literal shorthand, and often enough an
empty list is the correct result. All other core list commands properly handle
empty lists; but **lrepeat** complains when given a count of zero
repetitions, requiring additional code to handle this \(doubly\) exceptional
condition.

# Proposal

The **lrepeat** command should be changed so that when it's first,
_count_, argument is zero, it returns an empty list.

# Copyright

This document has been placed in the public domain.

Name change from tip/335.tip to tip/335.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

TIP:		335
Title:		An API for Detecting Active Interpreters
Version:	$Revision: 1.8 $
Author:		Joe Mistachkin <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	13-Oct-2008
Keywords:	numLevels,embedding,terminate,async,thread,safe,gc
Tcl-Version:	8.6
Post-History:	


~ Abstract

This TIP introduces the ability to quickly and safely decide whether a Tcl
script is evaluating in an interpreter, allowing an external system to
determine whether it is safe to delete that interpreter.

~ Rationale

For applications written in garbage-collected languages, such as C#, it is not
always desirable to rely upon the '''Tcl_Preserve''' / '''Tcl_Release'''
mechanism to protect an against deletion of an interpreter while it is in use.
For details of how this is used, see [http://wiki.tcl.tk/6580]
[http://eagle.to/] and Joe Mistachkin's talk at Tcl 2008.

Additionally, an application may want to proactively forbid attempts to delete
an interpreter while it is in use. Unfortunately, there is currently no
publicly exposed method to determine if a given Tcl interpreter is in use
(i.e. one or more calls to '''Tcl_Eval''' are active). This TIP proposes to
correct that deficiency.

~ Specification

This TIP introduces a single function to Tcl's public API:

 > int '''Tcl_InterpActive'''(Tcl_Interp *''interp'')

The '''Tcl_InterpActive''' function returns non-zero if the interpreter is in
use, and zero if it is idle (i.e. not evaluating any script).

~ Reference Implementation

|/*
| *----------------------------------------------------------------------
| *

| * Tcl_InterpActive --
| *

| *	Returns non-zero if the specified interpreter is in use.
| *

| * Results:
| *	See above.
| *

| * Side effects:
| *	None.
| *

| *----------------------------------------------------------------------
| */
|
|int
|Tcl_InterpActive(Tcl_Interp *interp)
|{

|    return (((Interp *) interp)->numLevels > 0);
|}


~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|

|
|

|
|




|


|



|

|
|

|

|
|
<
>
|
<
>
|
<
>
|
|
<
>
|
|
<
>
|
|
|
|
|
<
>
|
<
|
>
|


>

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

# TIP 335: An API for Detecting Active Interpreters

	Author:		Joe Mistachkin <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	13-Oct-2008
	Keywords:	numLevels,embedding,terminate,async,thread,safe,gc
	Tcl-Version:	8.6
	Post-History:	
-----

# Abstract

This TIP introduces the ability to quickly and safely decide whether a Tcl
script is evaluating in an interpreter, allowing an external system to
determine whether it is safe to delete that interpreter.

# Rationale

For applications written in garbage-collected languages, such as C\#, it is not
always desirable to rely upon the **Tcl\_Preserve** / **Tcl\_Release**
mechanism to protect an against deletion of an interpreter while it is in use.
For details of how this is used, see <http://wiki.tcl.tk/6580> 
<http://eagle.to/>  and Joe Mistachkin's talk at Tcl 2008.

Additionally, an application may want to proactively forbid attempts to delete
an interpreter while it is in use. Unfortunately, there is currently no
publicly exposed method to determine if a given Tcl interpreter is in use
\(i.e. one or more calls to **Tcl\_Eval** are active\). This TIP proposes to
correct that deficiency.

# Specification

This TIP introduces a single function to Tcl's public API:

 > int **Tcl\_InterpActive**\(Tcl\_Interp \*_interp_\)

The **Tcl\_InterpActive** function returns non-zero if the interpreter is in
use, and zero if it is idle \(i.e. not evaluating any script\).

# Reference Implementation

	/*
	 *----------------------------------------------------------------------

	 *
	 * Tcl_InterpActive --

	 *
	 *	Returns non-zero if the specified interpreter is in use.

	 *
	 * Results:
	 *	See above.

	 *
	 * Side effects:
	 *	None.

	 *
	 *----------------------------------------------------------------------
	 */
	
	int
	Tcl_InterpActive(Tcl_Interp *interp)

	{
	    return (((Interp *) interp)->numLevels > 0);

	}

# Copyright

This document has been placed in the public domain.

Name change from tip/336.tip to tip/336.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

TIP:		336
Title:		Supported Access To interp->errorline
Version:	$Revision: 1.4 $
Author:		Don Porter <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	21-Oct-2008
Post-History:	
Tcl-Version:	8.6


~ Abstract

This TIP proposes a supported public interface to set and get the value of the
''errorLine'' field of the ''Tcl_Interp'' data structure.

~ Background

A more forceful barrier to direct access to the ''result'' and ''freeProc''
fields of the ''Tcl_Interp'' data structure has just been accepted [330]. This
revision leaves only the ''errorLine'' field still normally publicly visible.
The visibility of this field prevents the realization of ''Tcl_Interp'' as a
fully opaque data structure.

The ''result'' and ''freeProc'' fields have long had the recommended
alternatives of '''Tcl_GetStringResult''' and '''Tcl_SetResult''' which make
direct access unnecessary. The ''errorLine'' field has long gone without such
alternatives. Starting with Tcl 8.5, some alternatives do exist. The value of
the ''errorLine'' field can be set by passing an appropriate dictionary to
'''Tcl_SetReturnOptions''' and the value can be retrieved from the dictionary
returned by passing '''TCL_ERROR''' to '''Tcl_GetReturnOption''' [227]. The
housekeeping burden of these alternatives is significant, so there's little
attraction for replacing direct access to the ''errorLine'' field with them.

Specialized routines already exist for managing the fully private fields
''errorInfo'' and ''errorCode'' in the opaque part of the ''Interp'' data
structure, '''Tcl_SetErrorCode''', '''Tcl_AddErrorInfo''', etc. The management
of these values is needed frequently enough to make simplified alternatives
like this worthwhile.

~ Proposal

Create the following new public routines to get and set the ''errorLine''
field:

 > int '''Tcl_GetErrorLine'''(Tcl_Interp *''interp'')

 > void '''Tcl_SetErrorLine'''(Tcl_Interp *''interp'', int ''value'')

These will be implemented as (equivalent to):

|int Tcl_GetErrorLine(Tcl_Interp *interp) {
|    return ((Interp *) interp)->errorLine;
|}

|
|void Tcl_SetErrorLine(Tcl_Interp *interp, int value) {
|    ((Interp *) interp)->errorLine = value;
|}


In addition, following the example of [330], disable the default public access
to the ''errorLine'' field, permitting the restoration of access only when the
'''USE_INTERP_ERRORLINE''' directive is defined.

~ Compatibility

This change is a source incompatibility with C code directly accessing the
''errorLine'' field. The quick fix to restore compatibility is to define
'''USE_INTERP_ERRORLINE'''. The next step for migrating old code would be to
adopt the new routines, and offer macros to duplicate the effect of the new
routines when older Tcl headers are in use.

~ Rationale

This is the last stepping stone to prepare the way for ''Tcl_Interp'' to
become a fully opaque data structure. The rationale for the immediate
disabling of public access is to (over?)learn the lesson of [330]. No matter
how sternly you warn about deprecation, nothing happens until you turn it off,
so let's move immediately to turning it off, with the burden on the users to
restore what they need.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|

|

|
|
|
|


|
|
|

|
|
|

|


|
|



|

|


|

|

|

|
|
<
>
|
|
|
<
|
>
|
|
|

|


|
|



|

|

|




|


>

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

# TIP 336: Supported Access To interp->errorline

	Author:		Don Porter <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	21-Oct-2008
	Post-History:	
	Tcl-Version:	8.6
-----

# Abstract

This TIP proposes a supported public interface to set and get the value of the
_errorLine_ field of the _Tcl\_Interp_ data structure.

# Background

A more forceful barrier to direct access to the _result_ and _freeProc_
fields of the _Tcl\_Interp_ data structure has just been accepted [[330]](330.md). This
revision leaves only the _errorLine_ field still normally publicly visible.
The visibility of this field prevents the realization of _Tcl\_Interp_ as a
fully opaque data structure.

The _result_ and _freeProc_ fields have long had the recommended
alternatives of **Tcl\_GetStringResult** and **Tcl\_SetResult** which make
direct access unnecessary. The _errorLine_ field has long gone without such
alternatives. Starting with Tcl 8.5, some alternatives do exist. The value of
the _errorLine_ field can be set by passing an appropriate dictionary to
**Tcl\_SetReturnOptions** and the value can be retrieved from the dictionary
returned by passing **TCL\_ERROR** to **Tcl\_GetReturnOption** [[227]](227.md). The
housekeeping burden of these alternatives is significant, so there's little
attraction for replacing direct access to the _errorLine_ field with them.

Specialized routines already exist for managing the fully private fields
_errorInfo_ and _errorCode_ in the opaque part of the _Interp_ data
structure, **Tcl\_SetErrorCode**, **Tcl\_AddErrorInfo**, etc. The management
of these values is needed frequently enough to make simplified alternatives
like this worthwhile.

# Proposal

Create the following new public routines to get and set the _errorLine_
field:

 > int **Tcl\_GetErrorLine**\(Tcl\_Interp \*_interp_\)

 > void **Tcl\_SetErrorLine**\(Tcl\_Interp \*_interp_, int _value_\)

These will be implemented as \(equivalent to\):

	int Tcl_GetErrorLine(Tcl_Interp *interp) {
	    return ((Interp *) interp)->errorLine;

	}
	
	void Tcl_SetErrorLine(Tcl_Interp *interp, int value) {
	    ((Interp *) interp)->errorLine = value;

	}

In addition, following the example of [[330]](330.md), disable the default public access
to the _errorLine_ field, permitting the restoration of access only when the
**USE\_INTERP\_ERRORLINE** directive is defined.

# Compatibility

This change is a source incompatibility with C code directly accessing the
_errorLine_ field. The quick fix to restore compatibility is to define
**USE\_INTERP\_ERRORLINE**. The next step for migrating old code would be to
adopt the new routines, and offer macros to duplicate the effect of the new
routines when older Tcl headers are in use.

# Rationale

This is the last stepping stone to prepare the way for _Tcl\_Interp_ to
become a fully opaque data structure. The rationale for the immediate
disabling of public access is to \(over?\)learn the lesson of [[330]](330.md). No matter
how sternly you warn about deprecation, nothing happens until you turn it off,
so let's move immediately to turning it off, with the burden on the users to
restore what they need.

# Copyright

This document has been placed in the public domain.

Name change from tip/337.tip to tip/337.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

TIP:		337
Title:		Make TclBackgroundException() Public
Version:	$Revision: 1.6 $
Author:		Don Porter <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	21-Oct-2008
Post-History:	
Tcl-Version:	8.6


~ Abstract

This TIP proposes to make the ''TclBackgroundException'' routine available in
the public interface so that extensions may notify Tcl about all return codes
that occur during background operations.

~ Background

When background operations in Tcl result in a non-'''TCL_OK''' return code, it
has been recommended practice to call ''Tcl_BackgroundError()'' so that Tcl
can arrange for background error handlers to react to the exceptional
situation. The prototype of that routine is:

 > void '''Tcl_BackgroundError'''(Tcl_Interp *''interp'')

In Tcl 8.5, the new '''interp bgerror''' command permits registration of
handlers that receive the full return options dictionary as an argument [221].
This means that such handlers can respond differently to different exceptions.
At the same time a new internal routine '''TclBackgroundException''' with
prototype:

 > void '''TclBackgroundException'''(Tcl_Interp *''interp'', int ''code'')

and the implementation of '''Tcl_BackgroundError''' became:

|void Tcl_BackgroundError(Tcl_Interp *interp) {
|    TclBackgroundException(interp, TCL_ERROR);
|}


The new '''TclBackgroundException''' routine is a more general routine
suitable for announcing any exceptional code returned by background
operations, not limited to '''TCL_ERROR''' like '''Tcl_BackgroundError''' has
been. The new '''TclBackgroundException''' routine is used throughout the
internal portions of Tcl so that full exception information gets reliably
passed through to background exception handlers, when the background
processing is governed by things which are built in to Tcl, such as
'''after''' and '''chan event'''.

The oversight of [221] was not proposing to make '''TclBackgroundException'''
public at the same time, so that extensions which govern background
operations, notably Tk, have access to the same full expressive power.

~ Proposal

Rename the internal routine '''TclBackgroundException''' to
'''Tcl_BackgroundException''' and place it in the public stubs table.

Apply Tk Patch 1789752
[https://sourceforge.net/support/tracker.php?aid=1789752]
to make use of the new facility.

~ Compatibility

No compatibility concerns from a new public routine.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|



|

|
|



|

|
|

|


|

|

|
|
<
|
>
|

|
|



|

|



|

|
|


|


|



|


>

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

# TIP 337: Make TclBackgroundException() Public

	Author:		Don Porter <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	21-Oct-2008
	Post-History:	
	Tcl-Version:	8.6
-----

# Abstract

This TIP proposes to make the _TclBackgroundException_ routine available in
the public interface so that extensions may notify Tcl about all return codes
that occur during background operations.

# Background

When background operations in Tcl result in a non-**TCL\_OK** return code, it
has been recommended practice to call _Tcl\_BackgroundError\(\)_ so that Tcl
can arrange for background error handlers to react to the exceptional
situation. The prototype of that routine is:

 > void **Tcl\_BackgroundError**\(Tcl\_Interp \*_interp_\)

In Tcl 8.5, the new **interp bgerror** command permits registration of
handlers that receive the full return options dictionary as an argument [[221]](221.md).
This means that such handlers can respond differently to different exceptions.
At the same time a new internal routine **TclBackgroundException** with
prototype:

 > void **TclBackgroundException**\(Tcl\_Interp \*_interp_, int _code_\)

and the implementation of **Tcl\_BackgroundError** became:

	void Tcl_BackgroundError(Tcl_Interp *interp) {
	    TclBackgroundException(interp, TCL_ERROR);

	}

The new **TclBackgroundException** routine is a more general routine
suitable for announcing any exceptional code returned by background
operations, not limited to **TCL\_ERROR** like **Tcl\_BackgroundError** has
been. The new **TclBackgroundException** routine is used throughout the
internal portions of Tcl so that full exception information gets reliably
passed through to background exception handlers, when the background
processing is governed by things which are built in to Tcl, such as
**after** and **chan event**.

The oversight of [[221]](221.md) was not proposing to make **TclBackgroundException**
public at the same time, so that extensions which govern background
operations, notably Tk, have access to the same full expressive power.

# Proposal

Rename the internal routine **TclBackgroundException** to
**Tcl\_BackgroundException** and place it in the public stubs table.

Apply Tk Patch 1789752
<https://sourceforge.net/support/tracker.php?aid=1789752> 
to make use of the new facility.

# Compatibility

No compatibility concerns from a new public routine.

# Copyright

This document has been placed in the public domain.

Name change from tip/338.tip to tip/338.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

TIP:		338
Title:		Embedder Access to Startup Scripts of *_Main()
Version:	$Revision: 1.4 $
Author:		Don Porter <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	22-Oct-2008
Post-History:
Tcl-Version:	8.6
Keywords:	Tcl, Tk, tclsh, wish


~ Abstract

This TIP proposes to make public the routines that get and set the startup
script file that ''Tcl_Main'' or ''Tk_Main'' evaluate in their non-interactive
modes.

~ Background

When support for the '''-encoding''' option was added to tclsh and wish [137],
two new internal routines were added to Tcl:

 > Tcl_Obj *'''Tcl_GetStartupScript'''(const char **''encodingNamePtr'')

 > void '''Tcl_SetStartupScript'''(Tcl_Obj *''pathPtr'', const char
   *''encodingName'')

These routines (or other weaker alternative internal routines) are used by
both wish and Tclkit by way of the internal stubs table to manipulate the
startup script for ''Tcl_Main'' or ''Tk_Main'' to evaluate.

~ Rationale

The naming of these routines indicate they were always intended to be(come)
public.

These are the last "private" Tcl routines used by Tk and wish. After
implementation of this TIP, Tk can drop use of tclInt.h.

~ Proposal

Make these routines public.

~ Compatibility

There will need to be some care taken for existing users of these routines via
the private stubs table. The ability to compile against Tcl 8.6 headers, yet
run against a pre-8.6 stubs table will likely be lost.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|


|

|


|

|
|

|

|

|

|





|



|





|


>

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

# TIP 338: Embedder Access to Startup Scripts of *_Main()

	Author:		Don Porter <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	22-Oct-2008
	Post-History:
	Tcl-Version:	8.6
	Keywords:	Tcl, Tk, tclsh, wish
-----

# Abstract

This TIP proposes to make public the routines that get and set the startup
script file that _Tcl\_Main_ or _Tk\_Main_ evaluate in their non-interactive
modes.

# Background

When support for the **-encoding** option was added to tclsh and wish [[137]](137.md),
two new internal routines were added to Tcl:

 > Tcl\_Obj \***Tcl\_GetStartupScript**\(const char \*\*_encodingNamePtr_\)

 > void **Tcl\_SetStartupScript**\(Tcl\_Obj \*_pathPtr_, const char
   *_encodingName_\)

These routines \(or other weaker alternative internal routines\) are used by
both wish and Tclkit by way of the internal stubs table to manipulate the
startup script for _Tcl\_Main_ or _Tk\_Main_ to evaluate.

# Rationale

The naming of these routines indicate they were always intended to be\(come\)
public.

These are the last "private" Tcl routines used by Tk and wish. After
implementation of this TIP, Tk can drop use of tclInt.h.

# Proposal

Make these routines public.

# Compatibility

There will need to be some care taken for existing users of these routines via
the private stubs table. The ability to compile against Tcl 8.6 headers, yet
run against a pre-8.6 stubs table will likely be lost.

# Copyright

This document has been placed in the public domain.

Name change from tip/339.tip to tip/339.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252

TIP:            339
Title:          Case-Insensitive Package Names
Version:        $Revision: 1.8 $
Author:         Andreas Kupries <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        14-Nov-2008
Post-History:   
Tcl-Version:    8.6


~ Abstract

This document proposes to change the package management facilities of the Tcl
core to handle package names in a case-insensitive manner, switching back to
case-sensitive operation if and only if explicitly requested by the user. The
case of package names is preserved in the storage however.

~ Rationale

The package management facilities of Tcl are an area where the user of
packages is currently burdened with more ... than is convenient or easy. A big
problem is that Tcl compares package names case-sensitively. This means that
''Expect'' and ''expect'' are two different things to Tcl. In the real world
however having two packages using the same name but different capitalization
is extremely rare.

Yet the user of Tcl package facilities has to remember whatever ecclectic
capitalization the package creator has chosen.

Changing this, i.e. having Tcl's package management go to case-insensitive
comparison, will lift this burden and make things easier, as it is not
necessary anymore to get the capitalization right. Most people will likely
simply start to write all package names lower-case after this change.

~ Specification

~~ Script Level

The only command affected by the proposed change is '''package'''. More
specifically, its sub-commands ''ifneeded'', ''present'', ''require'', and
''versions''.

In detail

 * '''package require''' ''name'' ...

 > This sub-command is changed to accept an additional option ''-strict''.

 > If this option is present the sub-command performs an old-style, i.e.
   case-sensitive search for the package ''name''.

 > Otherwise the command is changed to disregard case during the search for
   ''name''. In that case it is possible that multiple packages are found
   which have the same name, just with different capitalizations. To resolve
   this conflict the command will load the package in the matching set which
   was added first to its memory database via '''package ifneeded'''.

 > If that resolves to the wrong package the user has to use ''-strict'' and
   specify the exact name of the package required, capitalization and all.
   Given our rationale for the TIP this should be required seldomly.

 * '''package present''' ?-exact? ''name'' ?''version''?

 > This sub-command is changed to accept an additional option ''-strict''.

 > If this option is present the sub-command performs an old-style, i.e.
   case-sensitive search for the package ''name''.

 > Otherwise the command is changed to disregard case during the search for
   ''name''. In that case it is possible that multiple packages are found
   which have the same name, just with different capitalizations. To resolve
   this conflict the command will return the version of the package in the
   matching set it found first among the loaded packages.

 > If that resolves to the wrong package the user has to use ''-strict'' and
   specify the exact name of the package to look for, capitalization and all.
   Given our rationale for the TIP this should be required seldomly.

 * '''package versions''' ''name''

 > This sub-command is changed to accept an additional option ''-strict''.

 > If this option is present the sub-command performs an old-style, i.e.
   case-sensitive search for the package ''name''.

 > Otherwise the command is changed to disregard case during the search for
   ''name''. In that case it is possible that multiple packages are found
   which have the same name, just with different capitalizations. To resolve
   this conflict the command will return the version of the package in the
   matching set which was added first to its memory database via '''package
   ifneeded'''.

 > If that resolves to the wrong package the user has to use ''-strict'' and
   specify the exact name of the package to query, capitalization and all.
   Given our rationale for the TIP this should be required seldomly.

 * '''package forget''' ''name'' ...

 > This sub-command is changed to accept an additional option ''-strict''.

 > If this option is present the sub-command performs an old-style, i.e.
   case-sensitive search for the package ''name'' to forget.

 > Otherwise the command is changed to disregard case during the search for
   ''name''. In that case it is possible that multiple packages are found
   which have the same name, just with different capitalizations. Instead of
   resolving the conflict by forgetting only the first package found among the
   loaded this command will forget '''all''' of the packages matching the
   name.

 > If that does more than intended the user has to use ''-strict'' and specify
   the exact name(s) of the package to forget, capitalization and all. Given
   our rationale for the TIP this should be required seldomly.

 * '''package provide''' ''name'' ''version''

 > This form of the command is left unchanged.

 * '''package provide''' ''name''

 > This form of the command is like '''package present''', except for the
   different handling of a package not in memory. It is therefore changed in
   the same manner, i.e:

 > This form of the sub-command is changed to accept an additional option
   ''-strict''.

 > If this option is present this form of the sub-command performs an
   old-style, i.e. case-sensitive search for the package ''name'' before
   returning its version, or the empty string if nothing was found.

 > Otherwise this form of the sub-command is changed to disregard case during
   the search for ''name''. In that case it is possible that multiple packages
   are found which have the same name, just with different capitalizations. To
   resolve this conflict the command will return the version of the package in
   the matching set it found first among the loaded packages.

 > If that resolves to the wrong package the user has to use ''-strict'' and
   specify the exact name of the package to look for, capitalization and all.
   Given our rationale for the TIP this should be required seldomly.

 * '''package ifneeded''' ''name'' ''version'' ''script''

 > This form of the command is left unchanged. It keeps storing the package
   name as given, preserving capitalization, and ''package provide'' searches
   case-sensitively. This means that the name used by '''provide''' has to
   match the name used by the '''ifneeded''', just like the version numbers
   have to match. While we are working on easing the load on the user of a
   package with regard to letter case we do assume that the developer of a
   package does know how it is spelled, capitalization and all, therefore a
   strict, case-sensitive search is best to detect such avoidable mismatches.

 * '''package ifneeded''' ''name'' ''version''

 > This form of the command is similar to '''package present''' or '''package
   provide'''. It is therefore changed in the same manner, i.e:

 > This form of the sub-command is changed to accept an additional option
   ''-strict''.

 > If this option is present this form of the sub-command performs an old-style, i.e.
   case-sensitive search for the package ''name'' before returning the script, or
   the empty string if nothing was found.

 > Otherwise this form of the sub-command is changed to disregard case during the
   search for ''name''. In that case it is possible that multiple packages are
   found which have the same name, just with different capitalizations, and the
   same version. To resolve this conflict the command will return the script of the
   package in the matching set it found first among the loaded packages.

 > If that resolves to the wrong package the user has to use ''-strict'' and specify
   the exact name of the package to look for, capitalization and all. Given our
   rationale for the TIP this should be required seldomly.

~~ C API

At the C-level the only functions to consider are

 * Tcl_PkgPresent

 * Tcl_PkgPresentEx

 * Tcl_PkgRequire

 * Tcl_PkgRequireEx

 * Tcl_PkgRequireProc

The first four of these currently have an integer (boolean) argument
''exact''. This argument is changed to an integer (bitset) ''flags'', with the
original exact value residing in bit 0. The strictness of the package name
comparison is encoded in bit 1. For easy access to the flags we define

| #define TCL_PKG_EXACT  1  /* Exact version required */
| #define TCL_PKG_STRICT 2  /* Use strict (case-sensitive) package name
|                            * comparison */

This change relies on the assumption that all (most) existing users of these
functions use the constants 0 and 1 for ''exact'', making them fully backward
compatible.

The last function, ''Tcl_PkgRequireProc'', has no arguments we can modify in
this manner. Its behaviour is changed to perform case-insensitive searches, as
specified above for the associated subcommands of '''package''', and a new
function is added for access to the old behaviour, i.e. case-sensitive
searches. This new function is

 * Tcl_PkgRequireProcEx

It has the same signature as its pre-TIP counterpart, except that a ''flags''
argument is added after the clientData. This argument recognizes
''TCL_PKG_STRICT'' as defined above and uses it to switch between
case-insensitive and strict search. The old ''Tcl_PkgRequireProc'' is
reimplemented in terms of ''Tcl_PkgRequireProcEx''.

~~ Unknown handlers

The contract between the package management facilities in the Tcl core and the
handler commands registered with ''package unknown'' is amended. The handler has
to perform case-insensitive search for the package whose name it is invoked with.

~~ Discussions

The contract for the package unknown handler is amended because not doing so would
force the package management facilities in the Tcl core to search for a package by
iterating over all possible combinations of upper/lower case in the package name.
For a name containing N alphabetic characters (i.e. not counting ':'s, and digits)
this means to loop 2**N times. This exponentional explosion and consequent running
time is not acceptable (The longest name for a package currently found in
ActiveState's public TEApot repository is 25 alpabetic characters, forcing over
30 million searches before the core can give up).

Further, of the two known standard package unknown handlers the handler for regular
packages need not be modified at all as it always register every possible package
it finds. Only the unknown handler for Tcl Modules has to be modified to perform
case insensitive filesystem searches, and only for Unix. On Windows the builtin
'''glob''' command already perform such.

~ Reference Implementation

An implementation patch is available at SourceForge
[http://sourceforge.net/support/tracker.php?aid=2316115].

~ Copyright

This document has been placed in the public domain.

Please note that any correspondence to the author concerning this TIP is
considered in the public domain unless otherwise specifically requested by the
individual(s) authoring said correspondence. This is to allow information
about the TIP to be placed in a public forum for discussion.

<
|
<
|
|
|
|
|
|
|
>

|






|




|











|

|

|
|
|



|

|

|
|

|
|


|

|



|

|

|
|

|
|




|



|

|

|
|

|
|


|
|

|



|

|

|
|

|
|


|


|
|


|

|

|

|



|
|

|
|


|
|




|



|

|
|
|
|





|

|
|

|
|

|
|


|
|




|



|



|

|

|

|

|

|
|



|
|
|

|
|


|

|



|

|

|
|
|

|


|


|




|
|
|

|





|

|


|

|





|

>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252

# TIP 339: Case-Insensitive Package Names

	Author:         Andreas Kupries <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        14-Nov-2008
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

This document proposes to change the package management facilities of the Tcl
core to handle package names in a case-insensitive manner, switching back to
case-sensitive operation if and only if explicitly requested by the user. The
case of package names is preserved in the storage however.

# Rationale

The package management facilities of Tcl are an area where the user of
packages is currently burdened with more ... than is convenient or easy. A big
problem is that Tcl compares package names case-sensitively. This means that
_Expect_ and _expect_ are two different things to Tcl. In the real world
however having two packages using the same name but different capitalization
is extremely rare.

Yet the user of Tcl package facilities has to remember whatever ecclectic
capitalization the package creator has chosen.

Changing this, i.e. having Tcl's package management go to case-insensitive
comparison, will lift this burden and make things easier, as it is not
necessary anymore to get the capitalization right. Most people will likely
simply start to write all package names lower-case after this change.

# Specification

## Script Level

The only command affected by the proposed change is **package**. More
specifically, its sub-commands _ifneeded_, _present_, _require_, and
_versions_.

In detail

 * **package require** _name_ ...

	 > This sub-command is changed to accept an additional option _-strict_.

	 > If this option is present the sub-command performs an old-style, i.e.
   case-sensitive search for the package _name_.

	 > Otherwise the command is changed to disregard case during the search for
   _name_. In that case it is possible that multiple packages are found
   which have the same name, just with different capitalizations. To resolve
   this conflict the command will load the package in the matching set which
   was added first to its memory database via **package ifneeded**.

	 > If that resolves to the wrong package the user has to use _-strict_ and
   specify the exact name of the package required, capitalization and all.
   Given our rationale for the TIP this should be required seldomly.

 * **package present** ?-exact? _name_ ?_version_?

	 > This sub-command is changed to accept an additional option _-strict_.

	 > If this option is present the sub-command performs an old-style, i.e.
   case-sensitive search for the package _name_.

	 > Otherwise the command is changed to disregard case during the search for
   _name_. In that case it is possible that multiple packages are found
   which have the same name, just with different capitalizations. To resolve
   this conflict the command will return the version of the package in the
   matching set it found first among the loaded packages.

	 > If that resolves to the wrong package the user has to use _-strict_ and
   specify the exact name of the package to look for, capitalization and all.
   Given our rationale for the TIP this should be required seldomly.

 * **package versions** _name_

	 > This sub-command is changed to accept an additional option _-strict_.

	 > If this option is present the sub-command performs an old-style, i.e.
   case-sensitive search for the package _name_.

	 > Otherwise the command is changed to disregard case during the search for
   _name_. In that case it is possible that multiple packages are found
   which have the same name, just with different capitalizations. To resolve
   this conflict the command will return the version of the package in the
   matching set which was added first to its memory database via **package
   ifneeded**.

	 > If that resolves to the wrong package the user has to use _-strict_ and
   specify the exact name of the package to query, capitalization and all.
   Given our rationale for the TIP this should be required seldomly.

 * **package forget** _name_ ...

	 > This sub-command is changed to accept an additional option _-strict_.

	 > If this option is present the sub-command performs an old-style, i.e.
   case-sensitive search for the package _name_ to forget.

	 > Otherwise the command is changed to disregard case during the search for
   _name_. In that case it is possible that multiple packages are found
   which have the same name, just with different capitalizations. Instead of
   resolving the conflict by forgetting only the first package found among the
   loaded this command will forget **all** of the packages matching the
   name.

	 > If that does more than intended the user has to use _-strict_ and specify
   the exact name\(s\) of the package to forget, capitalization and all. Given
   our rationale for the TIP this should be required seldomly.

 * **package provide** _name_ _version_

	 > This form of the command is left unchanged.

 * **package provide** _name_

	 > This form of the command is like **package present**, except for the
   different handling of a package not in memory. It is therefore changed in
   the same manner, i.e:

	 > This form of the sub-command is changed to accept an additional option
   _-strict_.

	 > If this option is present this form of the sub-command performs an
   old-style, i.e. case-sensitive search for the package _name_ before
   returning its version, or the empty string if nothing was found.

	 > Otherwise this form of the sub-command is changed to disregard case during
   the search for _name_. In that case it is possible that multiple packages
   are found which have the same name, just with different capitalizations. To
   resolve this conflict the command will return the version of the package in
   the matching set it found first among the loaded packages.

	 > If that resolves to the wrong package the user has to use _-strict_ and
   specify the exact name of the package to look for, capitalization and all.
   Given our rationale for the TIP this should be required seldomly.

 * **package ifneeded** _name_ _version_ _script_

	 > This form of the command is left unchanged. It keeps storing the package
   name as given, preserving capitalization, and _package provide_ searches
   case-sensitively. This means that the name used by **provide** has to
   match the name used by the **ifneeded**, just like the version numbers
   have to match. While we are working on easing the load on the user of a
   package with regard to letter case we do assume that the developer of a
   package does know how it is spelled, capitalization and all, therefore a
   strict, case-sensitive search is best to detect such avoidable mismatches.

 * **package ifneeded** _name_ _version_

	 > This form of the command is similar to **package present** or **package
   provide**. It is therefore changed in the same manner, i.e:

	 > This form of the sub-command is changed to accept an additional option
   _-strict_.

	 > If this option is present this form of the sub-command performs an old-style, i.e.
   case-sensitive search for the package _name_ before returning the script, or
   the empty string if nothing was found.

	 > Otherwise this form of the sub-command is changed to disregard case during the
   search for _name_. In that case it is possible that multiple packages are
   found which have the same name, just with different capitalizations, and the
   same version. To resolve this conflict the command will return the script of the
   package in the matching set it found first among the loaded packages.

	 > If that resolves to the wrong package the user has to use _-strict_ and specify
   the exact name of the package to look for, capitalization and all. Given our
   rationale for the TIP this should be required seldomly.

## C API

At the C-level the only functions to consider are

 * Tcl\_PkgPresent

 * Tcl\_PkgPresentEx

 * Tcl\_PkgRequire

 * Tcl\_PkgRequireEx

 * Tcl\_PkgRequireProc

The first four of these currently have an integer \(boolean\) argument
_exact_. This argument is changed to an integer \(bitset\) _flags_, with the
original exact value residing in bit 0. The strictness of the package name
comparison is encoded in bit 1. For easy access to the flags we define

	 #define TCL_PKG_EXACT  1  /* Exact version required */
	 #define TCL_PKG_STRICT 2  /* Use strict (case-sensitive) package name
	                            * comparison */

This change relies on the assumption that all \(most\) existing users of these
functions use the constants 0 and 1 for _exact_, making them fully backward
compatible.

The last function, _Tcl\_PkgRequireProc_, has no arguments we can modify in
this manner. Its behaviour is changed to perform case-insensitive searches, as
specified above for the associated subcommands of **package**, and a new
function is added for access to the old behaviour, i.e. case-sensitive
searches. This new function is

 * Tcl\_PkgRequireProcEx

It has the same signature as its pre-TIP counterpart, except that a _flags_
argument is added after the clientData. This argument recognizes
_TCL\_PKG\_STRICT_ as defined above and uses it to switch between
case-insensitive and strict search. The old _Tcl\_PkgRequireProc_ is
reimplemented in terms of _Tcl\_PkgRequireProcEx_.

## Unknown handlers

The contract between the package management facilities in the Tcl core and the
handler commands registered with _package unknown_ is amended. The handler has
to perform case-insensitive search for the package whose name it is invoked with.

## Discussions

The contract for the package unknown handler is amended because not doing so would
force the package management facilities in the Tcl core to search for a package by
iterating over all possible combinations of upper/lower case in the package name.
For a name containing N alphabetic characters \(i.e. not counting ':'s, and digits\)
this means to loop 2\*\*N times. This exponentional explosion and consequent running
time is not acceptable \(The longest name for a package currently found in
ActiveState's public TEApot repository is 25 alpabetic characters, forcing over
30 million searches before the core can give up\).

Further, of the two known standard package unknown handlers the handler for regular
packages need not be modified at all as it always register every possible package
it finds. Only the unknown handler for Tcl Modules has to be modified to perform
case insensitive filesystem searches, and only for Unix. On Windows the builtin
**glob** command already perform such.

# Reference Implementation

An implementation patch is available at SourceForge
<http://sourceforge.net/support/tracker.php?aid=2316115> .

# Copyright

This document has been placed in the public domain.

Please note that any correspondence to the author concerning this TIP is
considered in the public domain unless otherwise specifically requested by the
individual\(s\) authoring said correspondence. This is to allow information
about the TIP to be placed in a public forum for discussion.

Name change from tip/34.tip to tip/34.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
TIP:            34
Title:          Modernize TEA Build System
Version:        $Revision: 2.7 $
Author:         Mo DeJong <[email protected]>
Author:         Andreas Kupries <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Done
Created:        03-May-2001
Post-History:   
Tcl-Version:    8.5


~ Abstract

A number of things in the original TEA specification and documentation
have fallen out of date.  Numerous complaints about the difficulty of
creating a TEA compliant package have appeared on news:comp.lang.tcl.
Other complaints about the ease of building Tcl and Tk using the
autoconf based build system have also surfaced.  Addressing these
concerns is made even more difficult by the fact that two independent
build systems currently exist, one for UNIX, and one for Windows.
Maintaining multiple build systems is a frustratingly slow process
that wastes time better spent on other issues.  In addition, the Tcl
build scripts do not support cross compilation which makes the
maintenance process even slower since one can't test simple build
system changes for a given platform without access to that platform.
This document describes how these concerns can be addressed.

~ Documentation

As new software is released, existing documentation becomes obsolete.
Some of the existing TEA documentation is now so badly out of date
that suggested software releases are no longer available.  For
example, the TEA based build for Windows requires Cygwin, yet there is
a lack of clear instructions that describe how to install Cygwin.  The
solution to this problem is simple, the TEA documentation and
implementation must be updated.

~ Platform Detection

Most open source packages make use of a pair of scripts called
''config.guess'' and ''config.sub'' to detect a platform specific
configuration string.  For example, running ''config.guess'' on an x86
Linux box might print:

|% ./config.guess
|i686-pc-linux-gnu

This value can be accessed from the configure.in script by adding a
call to the ''AC_CANONICAL_HOST()'' macro.  One would then detect a
specific platform by doing a switch on the value of the $host
variable.  Tcl currently detects the build platform by examining the
results of running ''`uname -s`-`uname -r`''.  Tcl should use the
''config.guess'' and ''config.sub'' method of platform detection.
This may not seem like a big change at first but it has quite a few
ramifications.

This change cannot be made incrementally, so there is a real danger of
breaking the build for configurations that currently work.  For this
reason, it would be a good idea to wait until a 8.4 release branch has
been created before adding such a change to the CVS HEAD.  The cross
compiling section will describe some of the other maintenance benefits
that can be realized by using ''config.sub'' and ''config.guess''.

~ Cross Compiling

Tcl's build system has never supported cross compiling.  The use of
uname instead of ''config.guess'' during platform detection is largely
to blame for this.  A configure script that makes use of the
''AC_CANONICAL_HOST()'' macro keeps track of two separate
configuration variables, ''build'' and ''host''.  The ''build''
variable holds the configuration string for the platform running the
''./configure'' script.  The ''host'' variable holds the configuration
string for the platform the generated binaries will be run on.  For
example, if one were to build a Windows binary under Linux the
''build'' variable could be set to ''i686-pc-linux-gnu'' and the
''host'' variable could be set to ''i386-pc-mingw32msvc''.

Using the host variable instead of the output of ''uname'' has another
important benefit.  The build system maintainer can often test out
changes to the build system logic without having access to the system
in question.  This is important since a surprising number of "broken
builds" are the result of stupid logic or syntax errors in the sh code
for a particular platform.  For example, one could test out the
Windows build using a cross compiler prefixed by ''i386-mingw32msvc''
like so:

|% ./configure --host=i386-mingw32msvc
|% make

The above commands will run the Windows configure script in bash and
then generate Win32 .dll and .exe files.  One can even create cross
compilers for multiple systems.  Binaries for Solaris, IRIX, or others
can be created under Linux or even Windows.  The attentive reader will
note that even compiling a Win32 application under Cygwin is
technically a cross compile since the generated executable would be
run with the Win32 runtime instead of the Cygwin runtime.  To properly
support cross compiling and make it easy for the end user, an upgrade
to autoconf is also required.

~ Autoconf 2.50 Update

The autoconf 2.13 release is now several years old.  The most recent
stable release of autoconf is 2.50.  A huge number of problems have
been fixed in the autoconf 2.50 release, the most important of which
is cross compiling support.  Cross compiling with autoconf 2.13 is
possible but far harder than it needs to be.  The long and sordid
history of this particular feature in autoconf will not be addressed
in this document.  It is safe to say that the autoconf 2.50 release is
the first release to make cross compiling easy for the end user.  The
existing build system works with the autoconf 2.50 release on a number
of systems, but it is possible that the build on some system would be
broken by this upgrade.  For this reason, the autoconf 2.50 upgrade
should happen after an 8.4 branch has been created.

~ Use a Config Header

Autoconf supports two ways to set platform specific flags set via the
''AC_DEFINE()'' macro.  Tcl currently makes use of the default option.
Each call to ''AC_DEFINE()'' adds a ''-DVAR=1'' value that is passed
into the compiler.  These ''-D'' flags are also included in the
generated ''tclConfig.sh'' file so that extensions will use the same
set of defines.  The second option is to generate a .h file that will
be #included into any needed header or source file.  This file could be
called ''tclconfig.h''.  Instead of passing ''-DVAR=1'' on the command
line, the generated .h file might look like:

|# define VAR 1

There is no functional difference between these two options.  The
benefit of using ''tclconfig.h'' will likely only be realized by the
maintainers or people hacking on the core and extensions.  By taking
the -D flags out of the ''Makefile'', we make it easier to hack around
in the generated .h file without having to worry about also changing
the flags in the generated ''tclConfig.sh'' file.  It can be quite a
pain to change an option in Tcl's ''Makefile'', then again in the
''tclConfig.sh'' file, and then rerun the configure script in each
extension.  This pain can be avoided by adding a call to
''AM_CONFIG_HEADER(tclconfig.h)'' to the top of Tcl's ''configure.in''
script.  One possible ramification of this change may be the need to
install ''tclconfig.h'' in the event items in ''tclInt.h'' depend on
#defines in ''tclconfig.h''.

~ Misplaced AC_SUBST Calls

The ''configure.in'' file for both Tcl and Tk invokes the
''AC_SUBST()'' macro for each variable that is to be substituted into
the ''Makefile''.  This makes sense for variables defined in the
''configure.in'' file, but it makes no sense for those variables
defined in ''tcl.m4''.  Invoking ''AC_SUBST()'' in ''configure.in''
for a variable defined in ''tcl.m4'' means that the maintainer will
need to keep track of the variable in Tcl's ''configure.in'' as well
as the ''configure.in'' of any extension that uses the given variable.
This simply makes no sense.  Each macro defined in ''tcl.m4'' should
call ''AC_SUBST()'' for any variables it wishes to substitute into
generated files.

~ One Rule to Build Them All

Perhaps the most frustrating thing about maintaining Tcl's build
system is the fact that each and every modification needs to be made
and tested in at least 4 configurations.  This is because Tcl and Tk
have two separate build systems, one for Unix and one for Windows.
Each and every change needs to be tested on Unix for both Tcl and Tk
and then again on Windows for both Tcl and Tk.  It is an incredible
waste of time.

A single build system with properly abstracted macros can be used to
build both a Unix and Windows version of Tcl.  Changes would still
need to be tested on each platform, but dealing with only one source
base would save a significant amount of the maintainer's time.

A related problem is experienced by extension authors.  It can be
quite difficult to write a build system for an extension that works
with both the Unix and Windows version of Tcl.  Here is a telling
quote from Todd Helfter, the maintainer of the Oratcl extension.

 > ''"TEA specifies that there should be only one set of configure
   files.  Why should extension writers have to comply with a standard
   that Tcl nor Tk does not?"''

For starters, some of the variables defined in the Unix version of
''tclConfig.sh'' do not exist in the Windows version.  Most of the
obvious problems in this area have already been corrected in the 8.4
release, but some difficult ones remain.  For example, how would an
extension author figure out how to name a generated library file in a
cross platform way?  One would assume that a couple of variables could
be concatenated together, but in practice this is not so easy.  A
quick look at the ''configure.in'' scripts will turn up examples like
this:

(Unix version)

|if test "${SHARED_BUILD}" = "1" ; then
|  eval "TCL_LIB_FILE=libtcl${TCL_SHARED_LIB_SUFFIX}"
|else
|  eval "TCL_LIB_FILE=libtcl${TCL_UNSHARED_LIB_SUFFIX}"
|fi

(Windows version)

|eval "TCL_LIB_FILE=${LIBPREFIX}tcl$VER${LIBSUFFIX}"

The attentive reader will note that these are completely different!
To understand the Unix version, one has to go exploring to find out
how ''TCL_[UN]SHARED_LIB_SUFFIX'' gets set.  To understand the Windows
version, one needs to look into the origins of ''LIBPREFIX'' and
''LIBSUFFIX''.  It is really quite a bother and it gets even worse
once you introduce additional compilers (like mingw) into the mix.
The casual coder would poke around for a bit then give up.

The solution to this problem is to merge the two build systems and
provide some properly abstracted macros that work on multiple
platforms.  These macros will need to be available to Tcl/Tk as well
as extension authors.  Here is a short example of a couple of macros
that were developed while porting Tcl/Tk and Itcl to the Cygnus
environment.  These macros can be found in the current CVS HEAD of
gdb/Insight.

|TCL_TOOL_STATIC_LIB_LONGNAME(VAR, LIBNAME, SUFFIX)
|TCL_TOOL_SHARED_LIB_LONGNAME(VAR, LIBNAME, SUFFIX)

Using these macros, one could code the Unix and Windows versions to
use the same logic.

|if test "${SHARED_BUILD}" = "1" ; then
|  TCL_TOOL_SHARED_LIB_LONGNAME(TCL_LIB_FILE, tcl, ${TCL_SHARED_LIB_SUFFIX})
|else
|  TCL_TOOL_STATIC_LIB_LONGNAME(TCL_LIB_FILE, tcl, ${TCL_UNSHARED_LIB_SUFFIX})
|fi

Behind the scenes, the unix version might set
''TCL_LIB_FILE=libtcl83.so'' while the Windows version might set
''TCL_LIB_FILE=tcl83.dll''.  Once both build systems use the same
code, we can abstract them out into a new ''tcl.m4'' file that is
shared between the Unix and Windows versions.  An extension that has
only one build system can also make use of these macros.  The concept
is not a difficult one, the problem is that the implementation takes a
very long time to get right.

~ VC++ vs. GCC Library Names

The previous section touched on issues related to library naming and
how they differ between Unix and Windows.  This section will focus
only on Windows and discuss some of the differences that make it
difficult to support both the VC++ and gcc compilers.  Two variables
that are quite difficult to support properly are ''TCL_LIB_SPEC'' and
''TCL_BUILD_LIB_SPEC''.  The gcc compiler supports command line
arguments like ''-L${dir} -l${lib}'' but VC++ does not.  VC++ users
must pass the fully qualified name of a .lib file or set an
environment variable.  To deal with this situation, the following
macros were developed.

|TCL_TOOL_LIB_SHORTNAME(VAR, LIBNAME, VERSION)
|TCL_TOOL_LIB_SPEC(VAR, DIR, LIBARG)

A single ''configure.in'' file for Tcl or an extension could make use
of these macros as follows:

|TCL_TOOL_LIB_SHORTNAME(TCL_LIB_FLAG, tcl, ${TCL_VERSION})
|TCL_TOOL_LIB_SPEC(TCL_BUILD_LIB_SPEC, `pwd`, ${TCL_LIB_FLAG})
|TCL_TOOL_LIB_SPEC(TCL_LIB_SPEC, ${exec_prefix}/lib, ${TCL_LIB_FLAG})

When configured with VC++, the macros would set:

|TCL_BUILD_LIB_SPEC="/build/tcl83.lib"
|TCL_LIB_SPEC="/install/tcl83.lib"

When configured with gcc, the macros would set:

|TCL_BUILD_LIB_SPEC="-L/build -ltcl83"
|TCL_LIB_SPEC="-L/install -ltcl83"

These macros are a good first step.  They provide abstraction for
library naming issues and work in both shared and static builds.  This
set of macros has been tested with Tcl, Tk, and Itcl and should be
ready for incorporation into other extensions.  One only needs to look
at Tcl bug 219330 to find an example of a core extension that only
builds with VC++ under Windows.  An extension writer should not need
to solve compiler problems such as this.  The Tcl core needs to
provide abstracted macros that can be used in extensions.

~ Cygwin vs. Mingw

The Windows version of Tcl traditionally supported building with VC++
only.  During the Tcl 8.3 development process, gcc support was added.
Trouble is, the default version of gcc delivered with Cygwin had and
continues to have some problems compiling the Windows Tcl code.

Cygwin is a Unix/POSIX compatibility layer built on top of the Win32
API.  The Cygwin version of gcc is designed to help people compile C
programs that make use of POSIX APIs.  The Cygwin version of gcc was
not designed to support compiling Win32 native applications.  Some
support for Win32 applications was added later via the ''-mno-cygwin''
command line switch, but it is far from perfect.

The Mingw project was created to produce a version of gcc that
supports building native Win32 applications.  This version of gcc is a
native Windows application, it does not depend on the Cygwin dll and
it does not link generated applications to the Cygwin dll.  In fact,
it is simply not possible to create an executable that accidently
requires the Cygwin dll when compiling with the Mingw version of gcc.
This can be a problem with the Cygwin version of gcc, especially when
C++ is involved.

Tcl currently builds with the Mingw version of gcc.  Tcl does not
build with the Cygwin version of gcc even though the ''-mno-cygwin''
is used.  Tcl also does not build using the Cygwin version of gcc in
POSIX mode without the ''-mno-cygwin'' flag.  In addition, the
individual working on Cygwin compatibility for Tcl will not be
pursuing it in the future.  For all of these reasons, support for
Cygwin gcc should be dropped in favor of Mingw gcc.  Documentation
should be updated to instruct people to install the Mingw version of
gcc instead of the Cygwin version.  It is even possible to have both
Cygwin gcc and Mingw gcc installed on the same system, the user just
needs to make sure the correct one is on the PATH before compiling
Tcl.  A check should also be placed in the configure.in script to keep
people from accidently compiling with the Cygwin version of gcc since
it does not work and will only lead to useless bug reports.

~ A New tclconfig Module

A number of Tcl extensions copy Tcl's ''tcl.m4'' file into the
extension's CVS module.  For example, Itcl distributes a locally
modified version of ''tcl.m4'' that supports building on Windows and
Unix with a single ''configure.in'' script.  It is very difficult to
keep up maintenance when this sort of approach is used.  For one
thing, the maintainer has to constantly copy the ''tcl.m4'' into
extensions.  Each and every commit to a ''tcl.m4'' file in the ''tcl''
CVS module needs to be followed by a commit to the same file in the
''tk'' module.  If an extension has made local modifications to the
''tcl.m4'' file, a new one can't just me copied over.  The extension
maintainer would need to merge the changes in my hand or make use of
some fancy CVS maintainer branch features that are not commonly used.
The result of all this trouble is a predictable lag in keeping an
extension's build system up to date.

Perhaps the best solution to this problem is to create a new module in
the Tcl CVS named ''tclconfig''.  This module would contain all the
macro files and supporting scripts that were available to Tcl and any
extensions.  Anyone who has worked on tclpro will notice that this is
equivalent to the ''config'' module that currently exists in the
''tclpro'' CVS.  The idea is the same, but the new module needs to
live in the ''tcl'' CVS repo not the ''tclpro'' CVS repo.  When a user
checks the ''tcl'' module out of the CVS a ''tclconfig'' directory
will also be created.  The ''tcl/unix/aclocal.m4'' script would then
be changed from:

|builtin(include,tcl.m4)

To:

|builtin(include,../../tclconfig/tcl.m4)

This approach will provide a single destination for all configure
related changes.  It will end the need to copy ''tcl.m4'' files into
each extension and will help extension authors resist the urge to make
local modifications to the ''tcl.m4'' script.  If an extension author
wants to change ''tcl.m4'' they will need to submit a patch via the
normal channels.  Nothing will force extension authors to use this new
approach, but it will be available to them when they are ready to
upgrade.  This change should not be integrated until Tcl 8.5.

~ Extension Defaults

A Tcl extension should default to the same configuration options that
Tcl was compiled with.  For example, if ''--prefix=/usr/local/tcl84''
is passed to Tcl's configure script, it should not also need to be
passed to Tk's configure script [[Tcl bug 428627]].  Tk should use the
compiler that Tcl was configured with by default.  In fact, each of
the following options could fit into this category:

 * --prefix

 * --exec-prefix

 * --host

 * --enable-threads

 * --enable-64bit

 * --enable-symbols

 * --enable-shared

Each one of these options will need to be saved in ''tclConfig.sh''.

~ Build vs. Install Configuration

The ''tclConfig.sh'' script should provide information that allows an
extension to be built with either an installed or uninstalled version
of Tcl.  The current ''tclConfig.sh'' largely fails to provide this
functionality to extensions.  Both build variables and install
variables are included in the ''tclConfig.sh'' file, but there is
nothing to indicate to the script that loads ''tclConfig.sh'' whether
or not a given ''tclConfig.sh'' has actually been installed.

An extension author has a couple of choices about how to deal with
this situation.  One could simply recreate needed flags like
''TCL_LIB_SPEC'' and ''TCL_STUB_LIB_SPEC'' and ignore the definitions
in the ''tclConfig.sh'' file.  Tk uses this approach.

One could also just pick from the build or install variables.  If the
extension author chose to use ''TCL_LIB_SPEC'' instead of
''TCL_BUILD_LIB_SPEC'' then the extension would only build with a
version of Tcl that was already installed.  Itcl uses this approach.

Both of these approaches are seriously flawed.  Tcl needs to provide a
means to load a ''tclConfig.sh'' file without having to worry about
build vs. install flags.  The ''SC_LOAD_TCLCONFIG'' macro can be
modified in such a way as to define
''TCL_LIB_SPEC=$TCL_BUILD_LIB_SPEC'' when loading ''tclConfig.sh''
from the build directory.  When ''tclConfig.sh'' is loaded from the
install directory one could safely set
''TCL_BUILD_LIB_SPEC=$TCL_LIB_SPEC''.

The above change would address the most obvious problem in
''tclConfig.sh'', but others remain.  Tcl bugs 219260 and 421835
provide some examples of variables in ''tclConfig.sh'' that may work
at build time but not install time and vice versa.  One possible long
term solution could be to create a ''tclBuildConfig.sh'' as well as a
''tclConfig.sh'' script.  The ''tclBuildConfig.sh'' could be loaded by
the ''SC_LOAD_TCLCONFIG'' macro when ''--with-tcl'' indicated a build
directory.  The ''tclConfig.sh'' script would not contain any build
variables and would be the only configuration file to get installed.

~ Chicken or the Egg

A number of targets in the current Tcl build process depend on having
a working version of Tcl on the users ''PATH''.  It is not entirely
clear if this was intentional.  Either way, it creates real problems
for users.  Tcl bugs 420501 and 464874 demonstrates how a user might
get a build error indicating that tclsh cannot be found before tclsh
is even built.  This problem should be straightforward to fix.  Tcl
patch 465874 describes on possible approach.  The fact that this
problem exists in the first place is indicative of a larger issue.

The Tcl build process should minimize external dependencies.  This
seems like a simple thing to seek agreement on, but people are
constantly advocating changes that fly in the face of this goal.  Tcl
bug 219259 describes one such misguided effort.  Older releases of
Itcl mistakenly assumed a version of tclsh would exist on the system
and tried to install files using a Tcl script named
''installFile.tcl''.  [59] seeks to embed Tcl build information into
tclsh so that Tcl extensions could build themselves using Tcl scripts.
Each of these approaches make different assumptions about how Tcl will
bootstrap itself.

The current bootstrap approach depends on tclsh in some circumstances
and not in others.  This tends to work most of the time.  Trouble is,
if the user does something to change the time-stamps of certain files,
<
|
<
|
|
|
|
|
|
|
|
>

|















|









|


|
|


|
|


|


|
|








|

|


|

|
|

|


|
|

|





|


|
|











|














|


|
|
|
|

|
|


|


|

|

|
|
|

|

|
|

|

|
|
|
|
|
|
|
|
|
|


|



















|

|


|





|


|

|
|
|
|
|

|

|



|
|
|
|










|
|




|
|
|
|
|


|
|
|





|




|
|
|
|




|
|

|


|
|
|

|

|
|



|
|






|



|

|








|









|


|

|











|

|

|
|

|
|

|
|






|


|
|
|
|
|


|



|


|

|
|




|


|

|

















|

|

|

|

|
|
|



|
|


|
|



|
|

|
|

|


|
|

|
|
|
|


|


|













|








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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451

# TIP 34: Modernize TEA Build System

	Author:         Mo DeJong <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Done
	Created:        03-May-2001
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

A number of things in the original TEA specification and documentation
have fallen out of date.  Numerous complaints about the difficulty of
creating a TEA compliant package have appeared on news:comp.lang.tcl.
Other complaints about the ease of building Tcl and Tk using the
autoconf based build system have also surfaced.  Addressing these
concerns is made even more difficult by the fact that two independent
build systems currently exist, one for UNIX, and one for Windows.
Maintaining multiple build systems is a frustratingly slow process
that wastes time better spent on other issues.  In addition, the Tcl
build scripts do not support cross compilation which makes the
maintenance process even slower since one can't test simple build
system changes for a given platform without access to that platform.
This document describes how these concerns can be addressed.

# Documentation

As new software is released, existing documentation becomes obsolete.
Some of the existing TEA documentation is now so badly out of date
that suggested software releases are no longer available.  For
example, the TEA based build for Windows requires Cygwin, yet there is
a lack of clear instructions that describe how to install Cygwin.  The
solution to this problem is simple, the TEA documentation and
implementation must be updated.

# Platform Detection

Most open source packages make use of a pair of scripts called
_config.guess_ and _config.sub_ to detect a platform specific
configuration string.  For example, running _config.guess_ on an x86
Linux box might print:

	% ./config.guess
	i686-pc-linux-gnu

This value can be accessed from the configure.in script by adding a
call to the _AC\_CANONICAL\_HOST\(\)_ macro.  One would then detect a
specific platform by doing a switch on the value of the $host
variable.  Tcl currently detects the build platform by examining the
results of running _\`uname -s\`-\`uname -r\`_.  Tcl should use the
_config.guess_ and _config.sub_ method of platform detection.
This may not seem like a big change at first but it has quite a few
ramifications.

This change cannot be made incrementally, so there is a real danger of
breaking the build for configurations that currently work.  For this
reason, it would be a good idea to wait until a 8.4 release branch has
been created before adding such a change to the CVS HEAD.  The cross
compiling section will describe some of the other maintenance benefits
that can be realized by using _config.sub_ and _config.guess_.

# Cross Compiling

Tcl's build system has never supported cross compiling.  The use of
uname instead of _config.guess_ during platform detection is largely
to blame for this.  A configure script that makes use of the
_AC\_CANONICAL\_HOST\(\)_ macro keeps track of two separate
configuration variables, _build_ and _host_.  The _build_
variable holds the configuration string for the platform running the
_./configure_ script.  The _host_ variable holds the configuration
string for the platform the generated binaries will be run on.  For
example, if one were to build a Windows binary under Linux the
_build_ variable could be set to _i686-pc-linux-gnu_ and the
_host_ variable could be set to _i386-pc-mingw32msvc_.

Using the host variable instead of the output of _uname_ has another
important benefit.  The build system maintainer can often test out
changes to the build system logic without having access to the system
in question.  This is important since a surprising number of "broken
builds" are the result of stupid logic or syntax errors in the sh code
for a particular platform.  For example, one could test out the
Windows build using a cross compiler prefixed by _i386-mingw32msvc_
like so:

	% ./configure --host=i386-mingw32msvc
	% make

The above commands will run the Windows configure script in bash and
then generate Win32 .dll and .exe files.  One can even create cross
compilers for multiple systems.  Binaries for Solaris, IRIX, or others
can be created under Linux or even Windows.  The attentive reader will
note that even compiling a Win32 application under Cygwin is
technically a cross compile since the generated executable would be
run with the Win32 runtime instead of the Cygwin runtime.  To properly
support cross compiling and make it easy for the end user, an upgrade
to autoconf is also required.

# Autoconf 2.50 Update

The autoconf 2.13 release is now several years old.  The most recent
stable release of autoconf is 2.50.  A huge number of problems have
been fixed in the autoconf 2.50 release, the most important of which
is cross compiling support.  Cross compiling with autoconf 2.13 is
possible but far harder than it needs to be.  The long and sordid
history of this particular feature in autoconf will not be addressed
in this document.  It is safe to say that the autoconf 2.50 release is
the first release to make cross compiling easy for the end user.  The
existing build system works with the autoconf 2.50 release on a number
of systems, but it is possible that the build on some system would be
broken by this upgrade.  For this reason, the autoconf 2.50 upgrade
should happen after an 8.4 branch has been created.

# Use a Config Header

Autoconf supports two ways to set platform specific flags set via the
_AC\_DEFINE\(\)_ macro.  Tcl currently makes use of the default option.
Each call to _AC\_DEFINE\(\)_ adds a _-DVAR=1_ value that is passed
into the compiler.  These _-D_ flags are also included in the
generated _tclConfig.sh_ file so that extensions will use the same
set of defines.  The second option is to generate a .h file that will
be \#included into any needed header or source file.  This file could be
called _tclconfig.h_.  Instead of passing _-DVAR=1_ on the command
line, the generated .h file might look like:

	# define VAR 1

There is no functional difference between these two options.  The
benefit of using _tclconfig.h_ will likely only be realized by the
maintainers or people hacking on the core and extensions.  By taking
the -D flags out of the _Makefile_, we make it easier to hack around
in the generated .h file without having to worry about also changing
the flags in the generated _tclConfig.sh_ file.  It can be quite a
pain to change an option in Tcl's _Makefile_, then again in the
_tclConfig.sh_ file, and then rerun the configure script in each
extension.  This pain can be avoided by adding a call to
_AM\_CONFIG\_HEADER\(tclconfig.h\)_ to the top of Tcl's _configure.in_
script.  One possible ramification of this change may be the need to
install _tclconfig.h_ in the event items in _tclInt.h_ depend on
\#defines in _tclconfig.h_.

# Misplaced AC\_SUBST Calls

The _configure.in_ file for both Tcl and Tk invokes the
_AC\_SUBST\(\)_ macro for each variable that is to be substituted into
the _Makefile_.  This makes sense for variables defined in the
_configure.in_ file, but it makes no sense for those variables
defined in _tcl.m4_.  Invoking _AC\_SUBST\(\)_ in _configure.in_
for a variable defined in _tcl.m4_ means that the maintainer will
need to keep track of the variable in Tcl's _configure.in_ as well
as the _configure.in_ of any extension that uses the given variable.
This simply makes no sense.  Each macro defined in _tcl.m4_ should
call _AC\_SUBST\(\)_ for any variables it wishes to substitute into
generated files.

# One Rule to Build Them All

Perhaps the most frustrating thing about maintaining Tcl's build
system is the fact that each and every modification needs to be made
and tested in at least 4 configurations.  This is because Tcl and Tk
have two separate build systems, one for Unix and one for Windows.
Each and every change needs to be tested on Unix for both Tcl and Tk
and then again on Windows for both Tcl and Tk.  It is an incredible
waste of time.

A single build system with properly abstracted macros can be used to
build both a Unix and Windows version of Tcl.  Changes would still
need to be tested on each platform, but dealing with only one source
base would save a significant amount of the maintainer's time.

A related problem is experienced by extension authors.  It can be
quite difficult to write a build system for an extension that works
with both the Unix and Windows version of Tcl.  Here is a telling
quote from Todd Helfter, the maintainer of the Oratcl extension.

 > _"TEA specifies that there should be only one set of configure
   files.  Why should extension writers have to comply with a standard
   that Tcl nor Tk does not?"_

For starters, some of the variables defined in the Unix version of
_tclConfig.sh_ do not exist in the Windows version.  Most of the
obvious problems in this area have already been corrected in the 8.4
release, but some difficult ones remain.  For example, how would an
extension author figure out how to name a generated library file in a
cross platform way?  One would assume that a couple of variables could
be concatenated together, but in practice this is not so easy.  A
quick look at the _configure.in_ scripts will turn up examples like
this:

\(Unix version\)

	if test "${SHARED_BUILD}" = "1" ; then
	  eval "TCL_LIB_FILE=libtcl${TCL_SHARED_LIB_SUFFIX}"
	else
	  eval "TCL_LIB_FILE=libtcl${TCL_UNSHARED_LIB_SUFFIX}"
	fi

\(Windows version\)

	eval "TCL_LIB_FILE=${LIBPREFIX}tcl$VER${LIBSUFFIX}"

The attentive reader will note that these are completely different!
To understand the Unix version, one has to go exploring to find out
how _TCL\_[UN]SHARED\_LIB\_SUFFIX_ gets set.  To understand the Windows
version, one needs to look into the origins of _LIBPREFIX_ and
_LIBSUFFIX_.  It is really quite a bother and it gets even worse
once you introduce additional compilers \(like mingw\) into the mix.
The casual coder would poke around for a bit then give up.

The solution to this problem is to merge the two build systems and
provide some properly abstracted macros that work on multiple
platforms.  These macros will need to be available to Tcl/Tk as well
as extension authors.  Here is a short example of a couple of macros
that were developed while porting Tcl/Tk and Itcl to the Cygnus
environment.  These macros can be found in the current CVS HEAD of
gdb/Insight.

	TCL_TOOL_STATIC_LIB_LONGNAME(VAR, LIBNAME, SUFFIX)
	TCL_TOOL_SHARED_LIB_LONGNAME(VAR, LIBNAME, SUFFIX)

Using these macros, one could code the Unix and Windows versions to
use the same logic.

	if test "${SHARED_BUILD}" = "1" ; then
	  TCL_TOOL_SHARED_LIB_LONGNAME(TCL_LIB_FILE, tcl, ${TCL_SHARED_LIB_SUFFIX})
	else
	  TCL_TOOL_STATIC_LIB_LONGNAME(TCL_LIB_FILE, tcl, ${TCL_UNSHARED_LIB_SUFFIX})
	fi

Behind the scenes, the unix version might set
_TCL\_LIB\_FILE=libtcl83.so_ while the Windows version might set
_TCL\_LIB\_FILE=tcl83.dll_.  Once both build systems use the same
code, we can abstract them out into a new _tcl.m4_ file that is
shared between the Unix and Windows versions.  An extension that has
only one build system can also make use of these macros.  The concept
is not a difficult one, the problem is that the implementation takes a
very long time to get right.

# VC\+\+ vs. GCC Library Names

The previous section touched on issues related to library naming and
how they differ between Unix and Windows.  This section will focus
only on Windows and discuss some of the differences that make it
difficult to support both the VC\+\+ and gcc compilers.  Two variables
that are quite difficult to support properly are _TCL\_LIB\_SPEC_ and
_TCL\_BUILD\_LIB\_SPEC_.  The gcc compiler supports command line
arguments like _-L$\{dir\} -l$\{lib\}_ but VC\+\+ does not.  VC\+\+ users
must pass the fully qualified name of a .lib file or set an
environment variable.  To deal with this situation, the following
macros were developed.

	TCL_TOOL_LIB_SHORTNAME(VAR, LIBNAME, VERSION)
	TCL_TOOL_LIB_SPEC(VAR, DIR, LIBARG)

A single _configure.in_ file for Tcl or an extension could make use
of these macros as follows:

	TCL_TOOL_LIB_SHORTNAME(TCL_LIB_FLAG, tcl, ${TCL_VERSION})
	TCL_TOOL_LIB_SPEC(TCL_BUILD_LIB_SPEC, `pwd`, ${TCL_LIB_FLAG})
	TCL_TOOL_LIB_SPEC(TCL_LIB_SPEC, ${exec_prefix}/lib, ${TCL_LIB_FLAG})

When configured with VC\+\+, the macros would set:

	TCL_BUILD_LIB_SPEC="/build/tcl83.lib"
	TCL_LIB_SPEC="/install/tcl83.lib"

When configured with gcc, the macros would set:

	TCL_BUILD_LIB_SPEC="-L/build -ltcl83"
	TCL_LIB_SPEC="-L/install -ltcl83"

These macros are a good first step.  They provide abstraction for
library naming issues and work in both shared and static builds.  This
set of macros has been tested with Tcl, Tk, and Itcl and should be
ready for incorporation into other extensions.  One only needs to look
at Tcl bug 219330 to find an example of a core extension that only
builds with VC\+\+ under Windows.  An extension writer should not need
to solve compiler problems such as this.  The Tcl core needs to
provide abstracted macros that can be used in extensions.

# Cygwin vs. Mingw

The Windows version of Tcl traditionally supported building with VC\+\+
only.  During the Tcl 8.3 development process, gcc support was added.
Trouble is, the default version of gcc delivered with Cygwin had and
continues to have some problems compiling the Windows Tcl code.

Cygwin is a Unix/POSIX compatibility layer built on top of the Win32
API.  The Cygwin version of gcc is designed to help people compile C
programs that make use of POSIX APIs.  The Cygwin version of gcc was
not designed to support compiling Win32 native applications.  Some
support for Win32 applications was added later via the _-mno-cygwin_
command line switch, but it is far from perfect.

The Mingw project was created to produce a version of gcc that
supports building native Win32 applications.  This version of gcc is a
native Windows application, it does not depend on the Cygwin dll and
it does not link generated applications to the Cygwin dll.  In fact,
it is simply not possible to create an executable that accidently
requires the Cygwin dll when compiling with the Mingw version of gcc.
This can be a problem with the Cygwin version of gcc, especially when
C\+\+ is involved.

Tcl currently builds with the Mingw version of gcc.  Tcl does not
build with the Cygwin version of gcc even though the _-mno-cygwin_
is used.  Tcl also does not build using the Cygwin version of gcc in
POSIX mode without the _-mno-cygwin_ flag.  In addition, the
individual working on Cygwin compatibility for Tcl will not be
pursuing it in the future.  For all of these reasons, support for
Cygwin gcc should be dropped in favor of Mingw gcc.  Documentation
should be updated to instruct people to install the Mingw version of
gcc instead of the Cygwin version.  It is even possible to have both
Cygwin gcc and Mingw gcc installed on the same system, the user just
needs to make sure the correct one is on the PATH before compiling
Tcl.  A check should also be placed in the configure.in script to keep
people from accidently compiling with the Cygwin version of gcc since
it does not work and will only lead to useless bug reports.

# A New tclconfig Module

A number of Tcl extensions copy Tcl's _tcl.m4_ file into the
extension's CVS module.  For example, Itcl distributes a locally
modified version of _tcl.m4_ that supports building on Windows and
Unix with a single _configure.in_ script.  It is very difficult to
keep up maintenance when this sort of approach is used.  For one
thing, the maintainer has to constantly copy the _tcl.m4_ into
extensions.  Each and every commit to a _tcl.m4_ file in the _tcl_
CVS module needs to be followed by a commit to the same file in the
_tk_ module.  If an extension has made local modifications to the
_tcl.m4_ file, a new one can't just me copied over.  The extension
maintainer would need to merge the changes in my hand or make use of
some fancy CVS maintainer branch features that are not commonly used.
The result of all this trouble is a predictable lag in keeping an
extension's build system up to date.

Perhaps the best solution to this problem is to create a new module in
the Tcl CVS named _tclconfig_.  This module would contain all the
macro files and supporting scripts that were available to Tcl and any
extensions.  Anyone who has worked on tclpro will notice that this is
equivalent to the _config_ module that currently exists in the
_tclpro_ CVS.  The idea is the same, but the new module needs to
live in the _tcl_ CVS repo not the _tclpro_ CVS repo.  When a user
checks the _tcl_ module out of the CVS a _tclconfig_ directory
will also be created.  The _tcl/unix/aclocal.m4_ script would then
be changed from:

	builtin(include,tcl.m4)

To:

	builtin(include,../../tclconfig/tcl.m4)

This approach will provide a single destination for all configure
related changes.  It will end the need to copy _tcl.m4_ files into
each extension and will help extension authors resist the urge to make
local modifications to the _tcl.m4_ script.  If an extension author
wants to change _tcl.m4_ they will need to submit a patch via the
normal channels.  Nothing will force extension authors to use this new
approach, but it will be available to them when they are ready to
upgrade.  This change should not be integrated until Tcl 8.5.

# Extension Defaults

A Tcl extension should default to the same configuration options that
Tcl was compiled with.  For example, if _--prefix=/usr/local/tcl84_
is passed to Tcl's configure script, it should not also need to be
passed to Tk's configure script [Tcl bug 428627].  Tk should use the
compiler that Tcl was configured with by default.  In fact, each of
the following options could fit into this category:

 * --prefix

 * --exec-prefix

 * --host

 * --enable-threads

 * --enable-64bit

 * --enable-symbols

 * --enable-shared

Each one of these options will need to be saved in _tclConfig.sh_.

# Build vs. Install Configuration

The _tclConfig.sh_ script should provide information that allows an
extension to be built with either an installed or uninstalled version
of Tcl.  The current _tclConfig.sh_ largely fails to provide this
functionality to extensions.  Both build variables and install
variables are included in the _tclConfig.sh_ file, but there is
nothing to indicate to the script that loads _tclConfig.sh_ whether
or not a given _tclConfig.sh_ has actually been installed.

An extension author has a couple of choices about how to deal with
this situation.  One could simply recreate needed flags like
_TCL\_LIB\_SPEC_ and _TCL\_STUB\_LIB\_SPEC_ and ignore the definitions
in the _tclConfig.sh_ file.  Tk uses this approach.

One could also just pick from the build or install variables.  If the
extension author chose to use _TCL\_LIB\_SPEC_ instead of
_TCL\_BUILD\_LIB\_SPEC_ then the extension would only build with a
version of Tcl that was already installed.  Itcl uses this approach.

Both of these approaches are seriously flawed.  Tcl needs to provide a
means to load a _tclConfig.sh_ file without having to worry about
build vs. install flags.  The _SC\_LOAD\_TCLCONFIG_ macro can be
modified in such a way as to define
_TCL\_LIB\_SPEC=$TCL\_BUILD\_LIB\_SPEC_ when loading _tclConfig.sh_
from the build directory.  When _tclConfig.sh_ is loaded from the
install directory one could safely set
_TCL\_BUILD\_LIB\_SPEC=$TCL\_LIB\_SPEC_.

The above change would address the most obvious problem in
_tclConfig.sh_, but others remain.  Tcl bugs 219260 and 421835
provide some examples of variables in _tclConfig.sh_ that may work
at build time but not install time and vice versa.  One possible long
term solution could be to create a _tclBuildConfig.sh_ as well as a
_tclConfig.sh_ script.  The _tclBuildConfig.sh_ could be loaded by
the _SC\_LOAD\_TCLCONFIG_ macro when _--with-tcl_ indicated a build
directory.  The _tclConfig.sh_ script would not contain any build
variables and would be the only configuration file to get installed.

# Chicken or the Egg

A number of targets in the current Tcl build process depend on having
a working version of Tcl on the users _PATH_.  It is not entirely
clear if this was intentional.  Either way, it creates real problems
for users.  Tcl bugs 420501 and 464874 demonstrates how a user might
get a build error indicating that tclsh cannot be found before tclsh
is even built.  This problem should be straightforward to fix.  Tcl
patch 465874 describes on possible approach.  The fact that this
problem exists in the first place is indicative of a larger issue.

The Tcl build process should minimize external dependencies.  This
seems like a simple thing to seek agreement on, but people are
constantly advocating changes that fly in the face of this goal.  Tcl
bug 219259 describes one such misguided effort.  Older releases of
Itcl mistakenly assumed a version of tclsh would exist on the system
and tried to install files using a Tcl script named
_installFile.tcl_.  [[59]](59.md) seeks to embed Tcl build information into
tclsh so that Tcl extensions could build themselves using Tcl scripts.
Each of these approaches make different assumptions about how Tcl will
bootstrap itself.

The current bootstrap approach depends on tclsh in some circumstances
and not in others.  This tends to work most of the time.  Trouble is,
if the user does something to change the time-stamps of certain files,
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531

the generated version of tclsh would need to run on the host system.
If the normal build process is always going to depend on tclsh, a
private build version of tclsh will need to be bootstrapped.
Realistically, this may be too much work to implement.  It seems the
only workable approach is to make sure none of the targets in the
normal build process depend on an external tclsh.

~ Death to TCL_DBGX

The most thoroughly evil part of the entire Tcl build process is the
''TCL_DBGX'' variable used in ''configure.in'', ''Makefile.in'', and
''tclConfig.sh''.  The following quote from Brent Welch say it all:

 > ''"The TCL_DBGX manifestation is one of the worst /bin/sh quoting
   hell situations I have encountered."''

Presumably, the ''TCL_DBGX'' variable was introduced to support
building of debug vs. non-debug versions of Tcl and installing them
into the same directory.  That may have been a noble goal, but in
practice this indirection makes many parts of the build system
extremely difficult to modify.  This scheme also fails to deal with
other identifying suffixes like 's' for a static build or 't' for a
threaded build.  A number of queries as to the usefulness of
''TCL_DBGX'' have appeared on news:comp.lang.tcl but none produced
satisfactory results.  The ''TCL_DBGX'' variable should be removed and
never spoken of again.

~ Configure Flags

The ''--enable-symbols'' should be renamed to ''--enable-debug''.
Quite a few other software projects use the ''--enable-debug'' flag.
A Google search turned up no other projects that make use of the
''--enable-symbols'' flag.  This change would have documentation
impact, but it would be minimal.  The old flag could be retained for
compatibility if a significant number of folks were concerned.

The Tcl 8.4 release removes the ''--enable-gcc'' flag.  This flag
introduced a number of problems that are much better solved by simply
setting the ''CC'' environment variable before running configure.
This change has already been incorporated into the CVS and is only
mentioned here for the sake of completeness.

~ Risks

Implementing this TIP is by no means an easy task.  Build system
changes are by far the most dangerous since a broken configuration
will not be noticed until someone actually tries to build on the given
system.  One can only ask for forgiveness before hand.  Large scale
build system changes will no doubt break something.  For this reason,
many of the suggested changes should be incorporated into the Tcl 8.5
release.

~ Alternatives

One alternative is to continue to use the existing system.  While
things would get no worse, they would also get no better.  Another
alternative is to replace the existing TEA based build system with a
build system written in Tcl.  This TIP does explore some of the build
issues a Tcl based system will face, but tries to focus on improving
the existing system instead of replacing TEA.

~ See Also

SourceForge bugs: 219259, 219260, 219330, 420501, 421835, 428627,
464874

SourceForge patch: 465874

~ Copyright

This document has been placed in the public domain.








|


|
|

|
|

|






|
|


|

|
|

|



|

|



|









|








|






|


>
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
the generated version of tclsh would need to run on the host system.
If the normal build process is always going to depend on tclsh, a
private build version of tclsh will need to be bootstrapped.
Realistically, this may be too much work to implement.  It seems the
only workable approach is to make sure none of the targets in the
normal build process depend on an external tclsh.

# Death to TCL\_DBGX

The most thoroughly evil part of the entire Tcl build process is the
_TCL\_DBGX_ variable used in _configure.in_, _Makefile.in_, and
_tclConfig.sh_.  The following quote from Brent Welch say it all:

 > _"The TCL\_DBGX manifestation is one of the worst /bin/sh quoting
   hell situations I have encountered."_

Presumably, the _TCL\_DBGX_ variable was introduced to support
building of debug vs. non-debug versions of Tcl and installing them
into the same directory.  That may have been a noble goal, but in
practice this indirection makes many parts of the build system
extremely difficult to modify.  This scheme also fails to deal with
other identifying suffixes like 's' for a static build or 't' for a
threaded build.  A number of queries as to the usefulness of
_TCL\_DBGX_ have appeared on news:comp.lang.tcl but none produced
satisfactory results.  The _TCL\_DBGX_ variable should be removed and
never spoken of again.

# Configure Flags

The _--enable-symbols_ should be renamed to _--enable-debug_.
Quite a few other software projects use the _--enable-debug_ flag.
A Google search turned up no other projects that make use of the
_--enable-symbols_ flag.  This change would have documentation
impact, but it would be minimal.  The old flag could be retained for
compatibility if a significant number of folks were concerned.

The Tcl 8.4 release removes the _--enable-gcc_ flag.  This flag
introduced a number of problems that are much better solved by simply
setting the _CC_ environment variable before running configure.
This change has already been incorporated into the CVS and is only
mentioned here for the sake of completeness.

# Risks

Implementing this TIP is by no means an easy task.  Build system
changes are by far the most dangerous since a broken configuration
will not be noticed until someone actually tries to build on the given
system.  One can only ask for forgiveness before hand.  Large scale
build system changes will no doubt break something.  For this reason,
many of the suggested changes should be incorporated into the Tcl 8.5
release.

# Alternatives

One alternative is to continue to use the existing system.  While
things would get no worse, they would also get no better.  Another
alternative is to replace the existing TEA based build system with a
build system written in Tcl.  This TIP does explore some of the build
issues a Tcl based system will face, but tries to focus on improving
the existing system instead of replacing TEA.

# See Also

SourceForge bugs: 219259, 219260, 219330, 420501, 421835, 428627,
464874

SourceForge patch: 465874

# Copyright

This document has been placed in the public domain.

Name change from tip/340.tip to tip/340.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

TIP:            340
Title:          Const Qualification of Tcl_SetResult's Argument
Version:        $Revision: 1.8 $
Author:         Jan Nijtmans <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        14-Nov-2008
Post-History:   
Keywords:       Tcl_SetResult
Tcl-Version:    8.7


~ Abstract

As a follow-up of [27], in Tcl 8.6 and Tk 8.6 much work has been done to clean
up the remaining places where pointers were not ''const'' qualified. The
question is, how can we prevent that in the future similar "mistakes" are
made. The gcc compiler warning ''-Wwrite-strings'' helps in that, therefore
this TIP proposes to add that to the CFLAGS_WARNING flag in Tcl and Tk when
using gcc. But for this flag to be introduced, all warnings will have to be
eliminated. In the HEAD, this is done already, except for one function:
'''Tcl_SetResult'''. This function is explicitely mentioned in [27] not to be
modified, because it cannot be handled without unsafe casting. This TIP
proposes to deprecate '''Tcl_SetResult''' in full, and provide a new macro
'''Tcl_SetStringResult''' in its place.

~ Rationale

The gcc manual mentions for the flag -Wwrite-strings:

 > When compiling C, give string constants the type ''const char[length]'' so
   that copying the address of one into a non-''const char *'' pointer will
   get a warning .... These warnings will help you find at compile time code
   that can try to write into a string constant, but only if you have been
   very careful about using const in declarations and prototypes. Otherwise,
   it will just be a nuisance; this is why we did not make -Wall request these
   warnings.

Now that all Tcl and Tk API's are modified to be very careful about using
const, this opens the way to add ''-Wwrite-strings'' to CFLAGS_WARNING when
building with gcc. Other extensions can start to do the same, if they want to
find out about this type of potential problem.

When considering the elimination of the warning when using '''Tcl_SetResult'',
I originally see two alternatives:

 * Change the implementation such that '''Tcl_SetResult'''(''i, s, f'') does
   the same as '''Tcl_SetObjResult'''(''i'', '''Tcl_NewStringObj'''(''s'',
   -1)), ignoring the last parameter.

 > This can be done without an unsafe type cast, but it has the disadvantage
   that after a (modified) '''Tcl_SetResult''' call the result is no longer
   available in interp->result. Older extensions might expect that, those will
   be silently broken. A the moment, serveral tests fail when doing this,
   because in various places of the Tcl core there are hack which still
   support older extensions which still use interp->result directly. It's a
   little short before Tcl 8.6 to do it now, but it should certainly be
   considered for the future.

 * The solution that originally was proposed in this TIP was to leave the
   '''Tcl_SetResult''' implementation as it is, only add a single type cast to
   prevent a gcc warning.

 > This violates the [27] conditions, but is in fact not more dangerous than
   the current situation. It is only dangerous, when the Tcl_SetResult call
   has another value than TCL_STATIC or TCL_VOLATILE as last argument

 * The final proposal is a new macro '''Tcl_SetStringResult''' that takes over
   the function of '''Tcl_SetResult'''. The function '''Tcl_SetResult''' will
   be deprecated in full.

There has been a discussion stating that changing the '''Tcl_SetResult'''
signature is wrong, because '''Tcl_SetResult''' cannot be made const-correct.

Most '''Tcl_SetResult''' calls use TCL_STATIC or TCL_VOLATILE as last
argument. In this case, the second argument is expected to be a const. The
macro '''Tcl_SetStringResult''' takes care of that, since it is implemented in
terms of '''Tcl_SetObjResult''' and '''Tcl_NewStringObj'''.

Very few '''Tcl_SetResult''' calls have some other value as last argument,
most likely TCL_DYNAMIC. This TIP proposes to deprecate '''Tcl_SetResult'''
for all values of freeProc. If the value is TCL_STATIC or TCL_VOLATILE, there
is a new macro '''Tcl_SetStringResult''' which can be used in stead. For other
values the call can be replaced with '''Tcl_SetStringResult''' as well, but
then the caller is responsible to free the memory after the
'''Tcl_SetStringResult''' call.

It turns out that Tcl had only 4 deprecated (as defined by this TIP)
'''Tcl_SetResult''' calls, one of them was wrong [[Bug 2308236]], two of them
were in tclTest.c meant to test the '''Tcl_SetResult''' function itself. Tk
had only 5 such calls. All those calls have been modified now. Tcl and Tk now
only calls '''Tcl_SetResult''' with either TCL_STATIC or TCL_VOLATILE

This proposal does not have the "forward compatibility" problem, that
extensions using '''Tcl_SetStringResult''' compiled. it is even possible for
extensions to use '''Tcl_SetStringResult''' with Tcl 8.5 and before:

| #ifndef
| #   define Tcl_SetStringResult(i,s) \
|     Tcl_SetObjResult(i, Tcl_NewStringObj(s, -1))
| #endif

~ Reference Implementation

A new patch will be available in issue #2315890
[http://sourceforge.net/support/tracker.php/?aid=2315890].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|

|
|


|

|
|

|



|
|







|



|


|
|
|

|
|








|


|
|
|

|
|


|
|

|

|
|

|
|
|
|
|

|

|
|
|

|


|
|

|
|
|
|

|

|
|

|


>

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

# TIP 340: Const Qualification of Tcl_SetResult's Argument

	Author:         Jan Nijtmans <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        14-Nov-2008
	Post-History:   
	Keywords:       Tcl_SetResult
	Tcl-Version:    8.7
-----

# Abstract

As a follow-up of [[27]](27.md), in Tcl 8.6 and Tk 8.6 much work has been done to clean
up the remaining places where pointers were not _const_ qualified. The
question is, how can we prevent that in the future similar "mistakes" are
made. The gcc compiler warning _-Wwrite-strings_ helps in that, therefore
this TIP proposes to add that to the CFLAGS\_WARNING flag in Tcl and Tk when
using gcc. But for this flag to be introduced, all warnings will have to be
eliminated. In the HEAD, this is done already, except for one function:
**Tcl\_SetResult**. This function is explicitely mentioned in [[27]](27.md) not to be
modified, because it cannot be handled without unsafe casting. This TIP
proposes to deprecate **Tcl\_SetResult** in full, and provide a new macro
**Tcl\_SetStringResult** in its place.

# Rationale

The gcc manual mentions for the flag -Wwrite-strings:

 > When compiling C, give string constants the type _const char[length]_ so
   that copying the address of one into a non-_const char \*_ pointer will
   get a warning .... These warnings will help you find at compile time code
   that can try to write into a string constant, but only if you have been
   very careful about using const in declarations and prototypes. Otherwise,
   it will just be a nuisance; this is why we did not make -Wall request these
   warnings.

Now that all Tcl and Tk API's are modified to be very careful about using
const, this opens the way to add _-Wwrite-strings_ to CFLAGS\_WARNING when
building with gcc. Other extensions can start to do the same, if they want to
find out about this type of potential problem.

When considering the elimination of the warning when using **Tcl\_SetResult_,
I originally see two alternatives:

 * Change the implementation such that **Tcl\_SetResult**\(_i, s, f_\) does
   the same as **Tcl\_SetObjResult**\(_i_, **Tcl\_NewStringObj**\(_s_,
   -1\)\), ignoring the last parameter.

	 > This can be done without an unsafe type cast, but it has the disadvantage
   that after a \(modified\) **Tcl\_SetResult** call the result is no longer
   available in interp->result. Older extensions might expect that, those will
   be silently broken. A the moment, serveral tests fail when doing this,
   because in various places of the Tcl core there are hack which still
   support older extensions which still use interp->result directly. It's a
   little short before Tcl 8.6 to do it now, but it should certainly be
   considered for the future.

 * The solution that originally was proposed in this TIP was to leave the
   **Tcl\_SetResult** implementation as it is, only add a single type cast to
   prevent a gcc warning.

	 > This violates the [[27]](27.md) conditions, but is in fact not more dangerous than
   the current situation. It is only dangerous, when the Tcl\_SetResult call
   has another value than TCL\_STATIC or TCL\_VOLATILE as last argument

 * The final proposal is a new macro **Tcl\_SetStringResult** that takes over
   the function of **Tcl\_SetResult**. The function **Tcl\_SetResult** will
   be deprecated in full.

There has been a discussion stating that changing the **Tcl\_SetResult**
signature is wrong, because **Tcl\_SetResult** cannot be made const-correct.

Most **Tcl\_SetResult** calls use TCL\_STATIC or TCL\_VOLATILE as last
argument. In this case, the second argument is expected to be a const. The
macro **Tcl\_SetStringResult** takes care of that, since it is implemented in
terms of **Tcl\_SetObjResult** and **Tcl\_NewStringObj**.

Very few **Tcl\_SetResult** calls have some other value as last argument,
most likely TCL\_DYNAMIC. This TIP proposes to deprecate **Tcl\_SetResult**
for all values of freeProc. If the value is TCL\_STATIC or TCL\_VOLATILE, there
is a new macro **Tcl\_SetStringResult** which can be used in stead. For other
values the call can be replaced with **Tcl\_SetStringResult** as well, but
then the caller is responsible to free the memory after the
**Tcl\_SetStringResult** call.

It turns out that Tcl had only 4 deprecated \(as defined by this TIP\)
**Tcl\_SetResult** calls, one of them was wrong [Bug 2308236], two of them
were in tclTest.c meant to test the **Tcl\_SetResult** function itself. Tk
had only 5 such calls. All those calls have been modified now. Tcl and Tk now
only calls **Tcl\_SetResult** with either TCL\_STATIC or TCL\_VOLATILE

This proposal does not have the "forward compatibility" problem, that
extensions using **Tcl\_SetStringResult** compiled. it is even possible for
extensions to use **Tcl\_SetStringResult** with Tcl 8.5 and before:

	 #ifndef
	 #   define Tcl_SetStringResult(i,s) \
	     Tcl_SetObjResult(i, Tcl_NewStringObj(s, -1))
	 #endif

# Reference Implementation

A new patch will be available in issue \#2315890
<http://sourceforge.net/support/tracker.php/?aid=2315890> .

# Copyright

This document has been placed in the public domain.

Name change from tip/341.tip to tip/341.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

TIP:		341
Title:		Multiple 'dict filter' Patterns
Version:	$Revision: 1.5 $
Author:		Lars Hellstr�m <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Tcl-Version:	8.6
Created:	27-Nov-2008
Keywords:	Tcl, set intersection
Post-History:	


~ Abstract

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

~ Specification

The two '''dict filter''' command forms

 > '''dict filter''' ''dictionary'' '''key''' ''pattern''

 > '''dict filter''' ''dictionary'' '''value''' ''pattern''

are generalised to

 > '''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 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.

~ 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 SF path #2370575.
[https://sourceforge.net/support/tracker.php?aid=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. 

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|

|

|



|

|




|

|
|
|





|
|

|
|
|
|
|
|
|

|


|



|
|

|

|
|
<
|
>
|
|





|

|
|
|
|

|




|




|

|

|

|
|
|
|

|








|


|



|
|

|
|

|

|


>

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

# TIP 341: Multiple 'dict filter' Patterns

	Author:		Lars Hellström <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Tcl-Version:	8.6
	Created:	27-Nov-2008
	Keywords:	Tcl, set intersection
	Post-History:	
-----

# Abstract

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

# Specification

The two **dict filter** command forms

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

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

are generalised to

 > **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 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.

# 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 SF path \#2370575.
<https://sourceforge.net/support/tracker.php?aid=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. 

Name change from tip/342.tip to tip/342.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
136
137
138
139
140
141

TIP:		342
Title:		Dict Get With Default
Version:	$Revision: 1.3 $
Author:		Lars Hellstr�m <[email protected]>
State:		Draft
Type:		Project
Vote:		Pending
Tcl-Version:	8.7
Created:	27-Nov-2008
Keywords:	dictionary, default value
Post-History:	


~ 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''

(I consider the name of this subcommand very much open for discussion) which
modulo error messages behaves like

| proc dict_getwithdefault {D args} {
|     if {[dict exists $D {*}[lrange $args 0 end-1]]} then {
|         dict get $D {*}[lrange $args 0 end-1]
|     } else {
|         lindex $args end
|     }
| }



i.e., it returns the value from the ''dictionary'' corresponding to the
sequence of ''key''s if it exists, or the default ''value'' otherwise. As with
'''dict exists''', it is OK (and will cause the default ''value'' to be
returned) if one of the ''key''s is missing from its dictionary, but an error
is thrown if this path of keys cannot be traversed because the value
associated with the previous key is not a dictionary.

~ Rationale

It is clear that getting a value from a dictionary if it exists and using a
default otherwise is a common operation, but it is also clear that this can be
carried out with a combination of existing Tcl commands. Hence the issue is
whether a new subcommand for this improves efficiency and convenience of this
operation enough to justify the possible bloat it brings.

~~ Alternative Methods

One approach that has been suggested for providing default values is to
combine '''dict get''' with '''dict merge''', like so:

|  dict get [dict merge {-apa bar} $D] -apa

This approach is however appropriate mainly in situations where several keys
are given fixed defaults simultaneously. Compared to '''dict
getwithdefault''', it has the following disadvantages:

   * It cannot be used for keys in nested dictionaries.

   * 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
implementation is very easy whereas the alternatives are not so easy.

Concretely, the necessary DictGetWithDefaultCmd is a trivial modification of
DictExistsCmd, to take one extra argument after the ''key''s and change the
final

|  Tcl_SetObjResult(interp, Tcl_NewBooleanObj(valuePtr != NULL));

to

|  Tcl_SetObjResult(interp, valuePtr != NULL ? valuePtr : objv[objc-1]);

It is nowhere near as easy to do this in a well-behaved extension, since
DictExistsCmd relies on TclTraceDictPath to do most of the work, and the
latter is AFAICT at best available in the internal stubs table.

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. 

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|

|

|


|
|
|
|
|
<
<
|
>
>
|
|
|
|



|







|


|

|


|
|




|



|



|


|
|


|
|

|
|
|

|
|

|

|

|
|

|


|

|

|



|

|

|




|


|



|










|

|
|

|


>

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
136
137
138
139
140
141

# TIP 342: Dict Get With Default

	Author:		Lars Hellström <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		Pending
	Tcl-Version:	8.7
	Created:	27-Nov-2008
	Keywords:	dictionary, default value
	Post-History:	
-----

# 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_

\(I consider the name of this subcommand very much open for discussion\) which
modulo error messages behaves like

	 proc dict_getwithdefault {D args} {
	     if {[dict exists $D {*}[lrange $args 0 end-1]]} then {
	         dict get $D {*}[lrange $args 0 end-1]
	     } else {
	         lindex $args end


	     }
	 }

i.e., it returns the value from the _dictionary_ corresponding to the
sequence of _key_s if it exists, or the default _value_ otherwise. As with
**dict exists**, it is OK \(and will cause the default _value_ to be
returned\) if one of the _key_s is missing from its dictionary, but an error
is thrown if this path of keys cannot be traversed because the value
associated with the previous key is not a dictionary.

# Rationale

It is clear that getting a value from a dictionary if it exists and using a
default otherwise is a common operation, but it is also clear that this can be
carried out with a combination of existing Tcl commands. Hence the issue is
whether a new subcommand for this improves efficiency and convenience of this
operation enough to justify the possible bloat it brings.

## Alternative Methods

One approach that has been suggested for providing default values is to
combine **dict get** with **dict merge**, like so:

	  dict get [dict merge {-apa bar} $D] -apa

This approach is however appropriate mainly in situations where several keys
are given fixed defaults simultaneously. Compared to **dict
getwithdefault**, it has the following disadvantages:

   * It cannot be used for keys in nested dictionaries.

   * 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
implementation is very easy whereas the alternatives are not so easy.

Concretely, the necessary DictGetWithDefaultCmd is a trivial modification of
DictExistsCmd, to take one extra argument after the _key_s and change the
final

	  Tcl_SetObjResult(interp, Tcl_NewBooleanObj(valuePtr != NULL));

to

	  Tcl_SetObjResult(interp, valuePtr != NULL ? valuePtr : objv[objc-1]);

It is nowhere near as easy to do this in a well-behaved extension, since
DictExistsCmd relies on TclTraceDictPath to do most of the work, and the
latter is AFAICT at best available in the internal stubs table.

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. 

Name change from tip/343.tip to tip/343.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

TIP:		343
Title:		A Binary Specifier for [format/scan]
Version:	$Revision: 1.3 $
Author:		Alexandre Ferrieux <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	03-Dec-2008
Post-History:	
Keywords:	Tcl,binary
Tcl-Version:	8.6


~ Abstract

This TIP proposes to add a %b specifier to the '''format''' and '''scan'''
commands for working with integers in base-2 representation.

~ Background

The '''format''' and '''scan''' commands already have decimal, hexadecimal,
and octal support, but people wanting binary today resort to a hack, namely
going hexadecimal first and then '''string map'''ping the hex digits to their
four-bits binary representations. We also already have the "0b" notation as
input for '''expr'''. This lack is inelegant.

~ Proposed Change

This TIP proposes to reuse the existing binary representation machinery to
expose a new '''%b''' specifier:

|	format %b 5
|	=> 101
|	scan 000101 %b x;set x
|	=> 5

The good properties of the existing code make the addition really painless, in
that it automagically combines with the size (l,ll), width (digits), and
prefix (#) modifiers:

|	format %#06b 5
|	=> 0b0101
|	format %llb [expr {(2**72-1)/7}]
|	1001001001001001001001001001001001001001001001001001001001001001001001

~ Rationale

That is really low-hanging fruit. All the pieces are in place, it's just a
matter of exposition. The binary representation is a nice pedagogic tool, and
having it handy (rather than with a hack) is a bonus.

~ Reference Implementation

See Patch 2368084 [https://sourceforge.net/support/tracker.php?aid=2368084].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|

|

|

|


|

|
|
|
|


|
|

|
|
|
|

|



|

|

|

|


>

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

# TIP 343: A Binary Specifier for [format/scan]

	Author:		Alexandre Ferrieux <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	03-Dec-2008
	Post-History:	
	Keywords:	Tcl,binary
	Tcl-Version:	8.6
-----

# Abstract

This TIP proposes to add a %b specifier to the **format** and **scan**
commands for working with integers in base-2 representation.

# Background

The **format** and **scan** commands already have decimal, hexadecimal,
and octal support, but people wanting binary today resort to a hack, namely
going hexadecimal first and then **string map**ping the hex digits to their
four-bits binary representations. We also already have the "0b" notation as
input for **expr**. This lack is inelegant.

# Proposed Change

This TIP proposes to reuse the existing binary representation machinery to
expose a new **%b** specifier:

		format %b 5
		=> 101
		scan 000101 %b x;set x
		=> 5

The good properties of the existing code make the addition really painless, in
that it automagically combines with the size \(l,ll\), width \(digits\), and
prefix \(\#\) modifiers:

		format %#06b 5
		=> 0b0101
		format %llb [expr {(2**72-1)/7}]
		1001001001001001001001001001001001001001001001001001001001001001001001

# Rationale

That is really low-hanging fruit. All the pieces are in place, it's just a
matter of exposition. The binary representation is a nice pedagogic tool, and
having it handy \(rather than with a hack\) is a bonus.

# Reference Implementation

See Patch 2368084 <https://sourceforge.net/support/tracker.php?aid=2368084> .

# Copyright

This document has been placed in the public domain.

Name change from tip/344.tip to tip/344.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

TIP:		344
Title:		Bring TCP_NODELAY and SO_KEEPALIVE to socket options
Version:	$Revision: 1.2 $
Author:		Alexandre Ferrieux <[email protected]>
State:		Draft
Type:		Project
Vote:		Pending
Created:	31-Dec-2008
Post-History:	
Tcl-Version:	8.7


~ Abstract

Just expose to script level, via '''fconfigure''', the two most important
setsockopt() use cases: TCP_NODELAY (disabling the Nagle agorithm) and
SO_KEEPALIVE (sending automatic keepalives).

~ Background & Rationale

Currently, there is no way to set nodefault values to a Tcl socket's
underlying socket options TCP_NODELAY and SO_KEEPALIVE. That is frustrating
because all TCP stacks support setsockopt().

Of these two options, the most important I guess is TCP_NODELAY. Indeed, the
Nagle algorithm being on by default may introduce unwanted latencies in some
specific cases. This TIP does not try to argument about the prevalence of
these cases; the ubiquity of setsockopt(TCP_NODELAY) suffices to justify
exposing it to script level.

~ Proposed Change

This TIP proposes to add two boolean [fconfigure] options to sockets:
'''-nodelay''' (or '''-nonagle''', or '''-nagle''', take your pick) and
'''-keepalive'''.

~ Reference Implementation

Pretty trivial; will be provided shortly after validation. The code has even
been in place for a long time, though only in the Windows-specific part, and
commented/ifdef'ed out...
 
~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|
|

|


|
|

|


|


|


|
|

|





|


>

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

# TIP 344: Bring TCP_NODELAY and SO_KEEPALIVE to socket options

	Author:		Alexandre Ferrieux <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		Pending
	Created:	31-Dec-2008
	Post-History:	
	Tcl-Version:	8.7
-----

# Abstract

Just expose to script level, via **fconfigure**, the two most important
setsockopt\(\) use cases: TCP\_NODELAY \(disabling the Nagle agorithm\) and
SO\_KEEPALIVE \(sending automatic keepalives\).

# Background & Rationale

Currently, there is no way to set nodefault values to a Tcl socket's
underlying socket options TCP\_NODELAY and SO\_KEEPALIVE. That is frustrating
because all TCP stacks support setsockopt\(\).

Of these two options, the most important I guess is TCP\_NODELAY. Indeed, the
Nagle algorithm being on by default may introduce unwanted latencies in some
specific cases. This TIP does not try to argument about the prevalence of
these cases; the ubiquity of setsockopt\(TCP\_NODELAY\) suffices to justify
exposing it to script level.

# Proposed Change

This TIP proposes to add two boolean [fconfigure] options to sockets:
**-nodelay** \(or **-nonagle**, or **-nagle**, take your pick\) and
**-keepalive**.

# Reference Implementation

Pretty trivial; will be provided shortly after validation. The code has even
been in place for a long time, though only in the Windows-specific part, and
commented/ifdef'ed out...
 
# Copyright

This document has been placed in the public domain.

Name change from tip/345.tip to tip/345.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

TIP:            345
Title:          Kill the 'identity' Encoding
Version:        $Revision: 1.2 $
Author:         Alexandre Ferrieux <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        05-Feb-2009
Post-History:   
Keywords:       Tcl,encoding,invalid UTF-8
Tcl-Version:    8.7


~ Abstract

This TIP proposes to remove the 'identity' encoding which is the Pandora's Box
of invalid UTF-8 string representations.

~ Background

The contract of string representations in Tcl states that the ''bytes'' field
(the '''strep''') of a Tcl_Obj must be a valid UTF-8 byte sequence. Violating
it leads at best to inconsistent and shimmer-sensitive string comparisons.
Fortunately, nearly all of the Tcl code takes careful steps to enforce it.
With one exception: the 'identity' encoding. Indeed, this encoding allows any
byte sequence to be copied verbatim into the strep of a value, as a
side-effect of a strep computation on a ByteArray with ['''encoding
system''']=="identity", or through ['''encoding convertfrom identity'''].
Hence an invalid UTF-8 sequence can easily make it to the strep and start
wreaking havoc.

~ Proposed Change

This TIP proposes to simply close that single window to the dark side.

~ Rationale

The risk of compatibility breakage is inordinately mild in that case, since it
has only ever been documented in tcltest.

~ Reference Example

See Bug 2564363 [https://sourceforge.net/support/tracker.php?aid=2564363]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|

|
|




|
|



|



|




|

|

|


>

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

# TIP 345: Kill the 'identity' Encoding

	Author:         Alexandre Ferrieux <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        05-Feb-2009
	Post-History:   
	Keywords:       Tcl,encoding,invalid UTF-8
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to remove the 'identity' encoding which is the Pandora's Box
of invalid UTF-8 string representations.

# Background

The contract of string representations in Tcl states that the _bytes_ field
\(the **strep**\) of a Tcl\_Obj must be a valid UTF-8 byte sequence. Violating
it leads at best to inconsistent and shimmer-sensitive string comparisons.
Fortunately, nearly all of the Tcl code takes careful steps to enforce it.
With one exception: the 'identity' encoding. Indeed, this encoding allows any
byte sequence to be copied verbatim into the strep of a value, as a
side-effect of a strep computation on a ByteArray with [**encoding
system**]=="identity", or through [**encoding convertfrom identity**].
Hence an invalid UTF-8 sequence can easily make it to the strep and start
wreaking havoc.

# Proposed Change

This TIP proposes to simply close that single window to the dark side.

# Rationale

The risk of compatibility breakage is inordinately mild in that case, since it
has only ever been documented in tcltest.

# Reference Example

See Bug 2564363 <https://sourceforge.net/support/tracker.php?aid=2564363> 

# Copyright

This document has been placed in the public domain.

Name change from tip/346.tip to tip/346.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

TIP:            346
Title:          Error on Failed String Encodings
Version:        $Revision: 1.2 $
Author:         Alexandre Ferrieux <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        02-Feb-2009
Post-History:   
Keywords:       Tcl,encoding,convertto,strict,Unicode,String,ByteArray
Tcl-Version:    8.7


~ Abstract

This TIP proposes to raise an error when an encoding-based conversion
loses information.

~ Background

Encoding-based conversions occur e.g. when writing a string to a
channel. In doing so, Unicode characters are converted to sequences of bytes
according to the channel's encoding. Similarly, a conversion can occur
on request of the ByteArray internal representation of an object, the target
encoding being ISO8859-1. In both cases, for some
combinations of Unicode char and target encoding, the mapping is lossy
(non-injective). For example, the "e acute" character, and many of its
cousins, is mapped to a "?" in the 'ascii' target encoding. Also, Unicode chars above \u00FF get 'projected' onto their low byte in the ISO8859-1 ByteArray conversion.

This loss of information, in the first case, introduces unnoticed i18n
mishandlings. In the second case, it makes it unreliable to do pure-ByteArray
operations on objects unless they have no string representation. This induces
unwanted and hard-to-debug performance hits on bytearray manipulations when
people add debugging '''puts'''.

~ Proposed Change

This TIP proposes to make this loss conspicuous.

For the first use case, the idea is to introduce a '''-strict''' option to
'''encoding convertto''', that would raise an explicit error when non-mappable
characters are met. Lossy conversions during channel I/O would also fail if a '''-strictencoding true''' [fconfigure option] is set.
  For the second case, we simply want the conversion to
fail, like does the Listification of an ill-formed list. In both cases, the
change consists of letting the proper internal conversion routine like '''SetByteArrayFromAny''' return TCL_ERROR.

~ Rationale

The second case does imply a Potential Incompatibility, since currently SBFA is documented to always return TCL_OK. However, it is felt
that virtually all cases that are sensitive to this, are actually half-working
in a completely hidden manner. Hence the global effect is a healthy one.

~ Reference Example

See Bug 1665628 [https://sourceforge.net/support/tracker.php?aid=1665628].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|







|
|





|

|



|
|
|


|

|

|



|

|

|


>

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

# TIP 346: Error on Failed String Encodings

	Author:         Alexandre Ferrieux <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        02-Feb-2009
	Post-History:   
	Keywords:       Tcl,encoding,convertto,strict,Unicode,String,ByteArray
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to raise an error when an encoding-based conversion
loses information.

# Background

Encoding-based conversions occur e.g. when writing a string to a
channel. In doing so, Unicode characters are converted to sequences of bytes
according to the channel's encoding. Similarly, a conversion can occur
on request of the ByteArray internal representation of an object, the target
encoding being ISO8859-1. In both cases, for some
combinations of Unicode char and target encoding, the mapping is lossy
\(non-injective\). For example, the "e acute" character, and many of its
cousins, is mapped to a "?" in the 'ascii' target encoding. Also, Unicode chars above \\u00FF get 'projected' onto their low byte in the ISO8859-1 ByteArray conversion.

This loss of information, in the first case, introduces unnoticed i18n
mishandlings. In the second case, it makes it unreliable to do pure-ByteArray
operations on objects unless they have no string representation. This induces
unwanted and hard-to-debug performance hits on bytearray manipulations when
people add debugging **puts**.

# Proposed Change

This TIP proposes to make this loss conspicuous.

For the first use case, the idea is to introduce a **-strict** option to
**encoding convertto**, that would raise an explicit error when non-mappable
characters are met. Lossy conversions during channel I/O would also fail if a **-strictencoding true** [fconfigure option] is set.
  For the second case, we simply want the conversion to
fail, like does the Listification of an ill-formed list. In both cases, the
change consists of letting the proper internal conversion routine like **SetByteArrayFromAny** return TCL\_ERROR.

# Rationale

The second case does imply a Potential Incompatibility, since currently SBFA is documented to always return TCL\_OK. However, it is felt
that virtually all cases that are sensitive to this, are actually half-working
in a completely hidden manner. Hence the global effect is a healthy one.

# Reference Example

See Bug 1665628 <https://sourceforge.net/support/tracker.php?aid=1665628> .

# Copyright

This document has been placed in the public domain.

Name change from tip/347.tip to tip/347.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

TIP:            347
Title:          Align 'string is ...' to Type-Conversion Functions in 'expr'
Version:        $Revision: 1.8 $
Author:         Jos Decoster <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        09-Feb-2009
Post-History:   
Discussions-To: news:comp.lang.tcl
Keywords:       Tcl
Tcl-Version:    8.7
Obsoleted-By:	395


~ Abstract

The '''string''' command supports tests for a number of Tcl's basic types, for
example, integers, doubles, and booleans. 
The '''tcl::mathfunc''' mathematical functions provides sevaral functions to
limit the number of bits used in integer numbers. 
This TIP proposes to align both groups of functions for '''int''', '''long''',
'''wide''' and '''entier'''.

~ Rationale

The '''string''' command includes tests for the common Tcl types: '''string is
boolean''', '''string is double''' and '''string is integer'''. Some of the
integer ranges used in Tcl internals are missing from the list, making it
difficult for an input validation procedure to determine whether, in fact, a
string contains a valid integer number to be used for that specific Tcl
command. 

Ranges already present are:

 * '''integer'''

 * '''wideinteger'''

Missing ranges are:

 * '''long'''

 * '''entier'''

The '''::tcl::mathfunc''' mathematical functions provides sevaral functions to
limit the number of bits used in integer numbers. Some of the integer ranges
used in Tcl internals are missing from the list, and other check an unexpected
range. 

Functions already present are:

 * '''wide'''

 * '''entier'''

Functions already present but with unexpected behavior are:

 * '''int''' actually does a '''long''' conversion

Missing functions are:

 * '''long'''

Providing a '''string is''' function for every integer range used in Tcl
internals will make it possible to check every argument in input validation
procedures before calling a Tcl command. Providing '''::tcl::mathfunc''' for
every integer range used in Tcl internals will make it possible to create values
in a valid range before calling a Tcl command.

Having the same integer range names in the '''string is''' functions and in the
'''::tcl::mathfunc''' when they act on the same integer ranges would make the
commands easier to recognise.

~ Specification

This document proposes:

 * augmenting the '''string is''' command with a '''string is long''' that
functions the same as '''string is integer''' in every respect except for the
fact that it accepts any string containing a substring that is valid as a long
integer (that is, acceptable to ''Tcl_GetLongFromObj'') possibly surrounded by
whitespace.

 * augmenting the '''string is''' command with a '''string is entier''' that
functions the same as '''string is integer''' in every respect except for the
fact that it accepts any string containing a substring that is valid as a bignum
integer (that is, acceptable to ''Tcl_GetBignumFromObj'') possibly surrounded by
whitespace.

 * modifying the '''::tcl::mathfunc::int''' to convert to an integer (that is,
acceptable to ''Tcl_GetIntFromObj'').

 * adding the '''::tcl::mathfunc::long''' to convert to a long integer (that is,
acceptable to ''Tcl_GetLongFromObj'').

 * keeping the '''string is integer''' command as it can be abbreviated to
   '''string is int''' to align with '''::tcl::mathfunc::int'''.

 * keeping the '''string is wideinteger''' command as it can be abbreviated to
   '''string is wide''' to align with '''::tcl::mathfunc::wide'''.

~ Compatibility

On platforms where a '''long'' variable has a different range than an '''int'''
variable, renaming the '''::tcl::mathfunc::int''' to '''::tcl::mathfunc::long'''
will let code like:

 | set a [expr {int($b)}]

behave differently for '''long''' values outside the '''int''' range.

~ Alternatives

The '''bignum''' was rejected in favor of '''entier''' because '''entier''' is
already used in '''::tcl::mathfunc::entier'''.

~ Reference Implementation

Patches that implement the above, provide test cases for it, and update
documentation to include it are available at SourceForge as Tcl Patch
#2581150[http://sourceforge.net/tracker2/?func=detail&aid=2581150&group_id=10894&atid=310894].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|

|

|
|

|

|
|







|

|



|

|

|






|

|



|



|

|

|



|
|


|



|
|

|


|
|

|


|
|

|
|

|
|

|
|

|

|
|


|

|

|

|
|

|



|

|


>

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

# TIP 347: Align 'string is ...' to Type-Conversion Functions in 'expr'

	Author:         Jos Decoster <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        09-Feb-2009
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Keywords:       Tcl
	Tcl-Version:    8.7
	Obsoleted-By:	395
-----

# Abstract

The **string** command supports tests for a number of Tcl's basic types, for
example, integers, doubles, and booleans. 
The **tcl::mathfunc** mathematical functions provides sevaral functions to
limit the number of bits used in integer numbers. 
This TIP proposes to align both groups of functions for **int**, **long**,
**wide** and **entier**.

# Rationale

The **string** command includes tests for the common Tcl types: **string is
boolean**, **string is double** and **string is integer**. Some of the
integer ranges used in Tcl internals are missing from the list, making it
difficult for an input validation procedure to determine whether, in fact, a
string contains a valid integer number to be used for that specific Tcl
command. 

Ranges already present are:

 * **integer**

 * **wideinteger**

Missing ranges are:

 * **long**

 * **entier**

The **::tcl::mathfunc** mathematical functions provides sevaral functions to
limit the number of bits used in integer numbers. Some of the integer ranges
used in Tcl internals are missing from the list, and other check an unexpected
range. 

Functions already present are:

 * **wide**

 * **entier**

Functions already present but with unexpected behavior are:

 * **int** actually does a **long** conversion

Missing functions are:

 * **long**

Providing a **string is** function for every integer range used in Tcl
internals will make it possible to check every argument in input validation
procedures before calling a Tcl command. Providing **::tcl::mathfunc** for
every integer range used in Tcl internals will make it possible to create values
in a valid range before calling a Tcl command.

Having the same integer range names in the **string is** functions and in the
**::tcl::mathfunc** when they act on the same integer ranges would make the
commands easier to recognise.

# Specification

This document proposes:

 * augmenting the **string is** command with a **string is long** that
functions the same as **string is integer** in every respect except for the
fact that it accepts any string containing a substring that is valid as a long
integer \(that is, acceptable to _Tcl\_GetLongFromObj_\) possibly surrounded by
whitespace.

 * augmenting the **string is** command with a **string is entier** that
functions the same as **string is integer** in every respect except for the
fact that it accepts any string containing a substring that is valid as a bignum
integer \(that is, acceptable to _Tcl\_GetBignumFromObj_\) possibly surrounded by
whitespace.

 * modifying the **::tcl::mathfunc::int** to convert to an integer \(that is,
acceptable to _Tcl\_GetIntFromObj_\).

 * adding the **::tcl::mathfunc::long** to convert to a long integer \(that is,
acceptable to _Tcl\_GetLongFromObj_\).

 * keeping the **string is integer** command as it can be abbreviated to
   **string is int** to align with **::tcl::mathfunc::int**.

 * keeping the **string is wideinteger** command as it can be abbreviated to
   **string is wide** to align with **::tcl::mathfunc::wide**.

# Compatibility

On platforms where a **long_ variable has a different range than an **int**
variable, renaming the **::tcl::mathfunc::int** to **::tcl::mathfunc::long**
will let code like:

 \| set a [expr {int($b)}]

behave differently for **long** values outside the **int** range.

# Alternatives

The **bignum** was rejected in favor of **entier** because **entier** is
already used in **::tcl::mathfunc::entier**.

# Reference Implementation

Patches that implement the above, provide test cases for it, and update
documentation to include it are available at SourceForge as Tcl Patch
\#2581150<http://sourceforge.net/tracker2/?func=detail&aid=2581150&group_id=10894&atid=310894> .

# Copyright

This document has been placed in the public domain.

Name change from tip/348.tip to tip/348.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

TIP:            348
Title:          Substituted 'errorstack' / 'traceback'
Version:        $Revision: 1.17 $
Author:         Alexandre Ferrieux <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        26-Feb-2009
Post-History:   
Keywords:       Tcl,debugging
Tcl-Version:    8.6


~ Abstract

This TIP proposes to add an '''errorstack''' options dict entry and associated
'''info''' subcommand, giving a "substituted" traceback similar to Python's or
gdb's ones.

~ Background

The '''::errorInfo''' variable is a valuable tool for debugging; however, it
yields mostly static information regarding each level of procedure call, as it
only gives the static text (extracted from the source) at the call site. This
leads to frustrating situations, like when an error occurs at a deep level of
a recursive function, '''::errorInfo''' repeatedly reporting "f $x [[foo
[[bar]]]]" or similar un-substituted commands. In other languages, the
traceback is more useful in that it contains the actual values passed as
arguments.

~ Proposed Change

This TIP proposes to create an '''-errorstack''' options dictionary entry, and
an associated '''info errorstack''' ?''interp''? command returning a list
containing the [['''info level''' 0]] lists of command-and-args at each
stack frame level at the time of error unwinding.

~ Rationale

In a natural implementation, its construction is analogous to that of
'''::errorInfo''', which is built incrementally, one level at a time while
popping back from the error site.  The only differences are that:

 1. dynamic arglists (from [['''info level''' 0]]) are stored,

 2. the result is a true list built by (the equivalent of) '''lappend''', and

 3. the granularity is coarser than with '''::errorInfo''' since there is just
    one element per stack frame level (and not for intervening '''while''' or
    '''foreach''' constructs) and no adornment like "... while executing ..."

Measurements show that the performance hit of maintaining the error stack is
small, being under 5% for realistic error stack sizes, and hits only the error
cases. To achieve this speed, the list-growing is done carefully, reusing
earlier optimizations made on list operations for the in-place case, so that
in routine use the allocated Tcl_Obj, internal representation, and element
array storage backing the list never change. This way, even code heavily
relying on '''catch''' across dozens of stack frame levels won't noticeably
suffer from the error stack machinery.

~ Definition

The error stack is an even-sized list alternating tokens and parameters.
Tokens are currently either '''CALL''' or '''UP''', but other values may be
introduced in the future; '''CALL''' indicates a procedure call, and its
parameter is the corresponding [['''info level''' 0]]; '''UP'''' indicates a
shift in variable frames generated by '''uplevel''' or similar, and applies to
the previous '''CALL''' item:

 > CALL {foo a} UP 1 CALL {bar b} CALL {baz c} UP 2 CALL {gnu d}
   CALL {gnats e}

The above value indicates that [[foo a]] was called by [[bar b]] through
[[uplevel 1]]. Similarly, [[baz c]] was itself lifted to toplevel by an
[[uplevel 2]] in [[gnu d]].

~ Reference Implementation

The reference implementation can be found on
SourceForge[https://sourceforge.net/support/tracker.php?aid=2868499].

An earlier, extremely slow, pure-Tcl proof of concept based on write traces on
'''::errorInfo''' can be found on the Wiki[http://wiki.tcl.tk/traceback].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|


|

|

|

|
|



|

|
|
|


|


|


|

|

|
|
|





|

|


|


|
|
|
|
|

|
|

|
|
|

|


|


|

|


>

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

# TIP 348: Substituted 'errorstack' / 'traceback'

	Author:         Alexandre Ferrieux <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        26-Feb-2009
	Post-History:   
	Keywords:       Tcl,debugging
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes to add an **errorstack** options dict entry and associated
**info** subcommand, giving a "substituted" traceback similar to Python's or
gdb's ones.

# Background

The **::errorInfo** variable is a valuable tool for debugging; however, it
yields mostly static information regarding each level of procedure call, as it
only gives the static text \(extracted from the source\) at the call site. This
leads to frustrating situations, like when an error occurs at a deep level of
a recursive function, **::errorInfo** repeatedly reporting "f $x [foo
[bar]]" or similar un-substituted commands. In other languages, the
traceback is more useful in that it contains the actual values passed as
arguments.

# Proposed Change

This TIP proposes to create an **-errorstack** options dictionary entry, and
an associated **info errorstack** ?_interp_? command returning a list
containing the [**info level** 0] lists of command-and-args at each
stack frame level at the time of error unwinding.

# Rationale

In a natural implementation, its construction is analogous to that of
**::errorInfo**, which is built incrementally, one level at a time while
popping back from the error site.  The only differences are that:

 1. dynamic arglists \(from [**info level** 0]\) are stored,

 2. the result is a true list built by \(the equivalent of\) **lappend**, and

 3. the granularity is coarser than with **::errorInfo** since there is just
    one element per stack frame level \(and not for intervening **while** or
    **foreach** constructs\) and no adornment like "... while executing ..."

Measurements show that the performance hit of maintaining the error stack is
small, being under 5% for realistic error stack sizes, and hits only the error
cases. To achieve this speed, the list-growing is done carefully, reusing
earlier optimizations made on list operations for the in-place case, so that
in routine use the allocated Tcl\_Obj, internal representation, and element
array storage backing the list never change. This way, even code heavily
relying on **catch** across dozens of stack frame levels won't noticeably
suffer from the error stack machinery.

# Definition

The error stack is an even-sized list alternating tokens and parameters.
Tokens are currently either **CALL** or **UP**, but other values may be
introduced in the future; **CALL** indicates a procedure call, and its
parameter is the corresponding [**info level** 0]; **UP**' indicates a
shift in variable frames generated by **uplevel** or similar, and applies to
the previous **CALL** item:

 > CALL \{foo a\} UP 1 CALL \{bar b\} CALL \{baz c\} UP 2 CALL \{gnu d\}
   CALL \{gnats e\}

The above value indicates that [foo a] was called by [bar b] through
[uplevel 1]. Similarly, [baz c] was itself lifted to toplevel by an
[uplevel 2] in [gnu d].

# Reference Implementation

The reference implementation can be found on
SourceForge<https://sourceforge.net/support/tracker.php?aid=2868499> .

An earlier, extremely slow, pure-Tcl proof of concept based on write traces on
**::errorInfo** can be found on the Wiki<http://wiki.tcl.tk/traceback> .

# Copyright

This document has been placed in the public domain.

Name change from tip/349.tip to tip/349.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

TIP:           349
Title:         New "-cargo" option for every Tk widget
Version:       $Revision: 1.1 $
Author:        Zbigniew Baniewski <[email protected]>
State:         Draft
Type:          Project
Tcl-Version:   8.7
Vote:          Pending
Created:       17-Apr-2009
Post-History:


~ Abstract

This TIP proposes adding a '''-cargo''' option to every Tk widget that
will be kept free for code that uses the widget to use as it sees fit;
the Tk library will assign no interpretation to the option.

~ Proposal

TCL users have long been at a disadvantage not having a possibility to
attach arbitrary widget-related values (e.g., "tooltip"-texts)
directly to widget, being forced to use workarounds (e.g. external
variables to hold the data) or even entire additional packages/frameworks
(like Snit) exactly because of the lack of the proposed option.

So the proposal is "solutions instead of workarounds": let's introduce
the option - further named "-cargo" (the name taken from Clipper) - which
will cancel the current need for fixes of different kind. The option should
allow to access a string field (or even better: a dictionary), allowing to
keep there any widget-related data, choosen by script creator. It's value
should be accessible both by "cget" and "percent substitution" (like "%C").

~ Rationale

In a talk at news:comp.lang.tcl everyone - or almost everyone - posting in the
appropriate threads, appreciated the proposed solution as useful. There
were some fears about possible "clashes" while using that option (or that
the proposed option will be even "too useful"). I would to mention here,
that "cargo" idea has been taken from Clipper, where - during over 20 past
years - there is no evidence at all of any "clashes" (neither of any other
damage) only because of availability of such option. Being sure, that TCL
programmers aren't less skilled than those Clipper guys, I cannot describe
such fears differently, than as not reasonable ones.

So because such option has been successfully tested in other language (there
are no complaints from Clipper programmers about any "cargo"-harmness),
there's no need for "prophecies" of the type "it will do damage", because
there has been proved exactly the contrary.

Some more possible usage gave Bryan Oakley in his post:

 > What sort of data would I potentially keep with a widget? Perhaps an
   index that points to context sensitive help. Or, I might keep an undo
   stack, or a copy of the original value. Think of a label widget that
   automatically truncates it's text and adds "..." if the widget is
   resized smaller than it's preferred size -- you need to keep the
   unadulterated original value that  you can refer to as the widget
   grows and shrinks. Better to keep that with the widget than in a
   global variable, IMO. Or, I could use it to keep track of a "dirty"
   bit that gets set when the original value of a radiobutton or
   checkbutton changes. Or I could store a database primary key that
   points to where the data for the widget came from.

I believe, that's not all, because we cannot predict today, what other
useful things can be done with option of such "universal" (not "targetted")
nature. Two things for sure: a) It'll make the life of every TCL-scriptor
easier, b) Its use won't be obligatory, if someone will be afraid of
"clashes" possibility, or something like this.

~ License

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|



|


|
|
|
|


|

|

|

|



|
|

|
|



|
|


















|
|
|


|


>

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

# TIP 349: New "-cargo" option for every Tk widget

	Author:        Zbigniew Baniewski <[email protected]>
	State:         Draft
	Type:          Project
	Tcl-Version:   8.7
	Vote:          Pending
	Created:       17-Apr-2009
	Post-History:
-----

# Abstract

This TIP proposes adding a **-cargo** option to every Tk widget that
will be kept free for code that uses the widget to use as it sees fit;
the Tk library will assign no interpretation to the option.

# Proposal

TCL users have long been at a disadvantage not having a possibility to
attach arbitrary widget-related values \(e.g., "tooltip"-texts\)
directly to widget, being forced to use workarounds \(e.g. external
variables to hold the data\) or even entire additional packages/frameworks
\(like Snit\) exactly because of the lack of the proposed option.

So the proposal is "solutions instead of workarounds": let's introduce
the option - further named "-cargo" \(the name taken from Clipper\) - which
will cancel the current need for fixes of different kind. The option should
allow to access a string field \(or even better: a dictionary\), allowing to
keep there any widget-related data, choosen by script creator. It's value
should be accessible both by "cget" and "percent substitution" \(like "%C"\).

# Rationale

In a talk at news:comp.lang.tcl everyone - or almost everyone - posting in the
appropriate threads, appreciated the proposed solution as useful. There
were some fears about possible "clashes" while using that option \(or that
the proposed option will be even "too useful"\). I would to mention here,
that "cargo" idea has been taken from Clipper, where - during over 20 past
years - there is no evidence at all of any "clashes" \(neither of any other
damage\) only because of availability of such option. Being sure, that TCL
programmers aren't less skilled than those Clipper guys, I cannot describe
such fears differently, than as not reasonable ones.

So because such option has been successfully tested in other language \(there
are no complaints from Clipper programmers about any "cargo"-harmness\),
there's no need for "prophecies" of the type "it will do damage", because
there has been proved exactly the contrary.

Some more possible usage gave Bryan Oakley in his post:

 > What sort of data would I potentially keep with a widget? Perhaps an
   index that points to context sensitive help. Or, I might keep an undo
   stack, or a copy of the original value. Think of a label widget that
   automatically truncates it's text and adds "..." if the widget is
   resized smaller than it's preferred size -- you need to keep the
   unadulterated original value that  you can refer to as the widget
   grows and shrinks. Better to keep that with the widget than in a
   global variable, IMO. Or, I could use it to keep track of a "dirty"
   bit that gets set when the original value of a radiobutton or
   checkbutton changes. Or I could store a database primary key that
   points to where the data for the widget came from.

I believe, that's not all, because we cannot predict today, what other
useful things can be done with option of such "universal" \(not "targetted"\)
nature. Two things for sure: a\) It'll make the life of every TCL-scriptor
easier, b\) Its use won't be obligatory, if someone will be afraid of
"clashes" possibility, or something like this.

# License

This document has been placed in the public domain.

Name change from tip/35.tip to tip/35.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

TIP:            35
Title:          Enhanced Support for Serial Communications
Version:        $Revision: 1.12 $
Author:         Rolf Schroedter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        06-Jun-2001
Post-History:   
Tcl-Version:    8.4


~ Abstract

Tcl's support for RS-232 is very rudimentary.  Mainly it allows to
setup the communication rate [[fconfigure -mode]] and to read and
write data with the standard Tcl functions.  Real serial
communications are often more complex.  Therefore it is proposed to
add support for hardware and software flow control, polling RS-232
(modem) status lines, and watching the input and output queue.  This
is all to be implemented via additional [[fconfigure]] options.

~ Rationale

There is an undamped interest in serial communications, because it's
very easy to connect external hardware to a computer using the RS-232
ports.

However Tcl's support for serial communications is not complete.  Real
applications often need more than setting the baud rate and to
read/write data bytes.

Especially if the external hardware is slow or the communication rate
is high one needs support for flow-control (hard- and software).
These features are provided by the operating system drivers, but Tcl's
[[fconfigure]] doesn't support it.

On the the other hand there are cases that the external hardware makes
static use of the RS-232 signals to signal external events via the
modem status lines or even to be powered by the RS-232 control lines.

Additionally for non-blocking serial I/O it may be interesting for the
Tcl application to know about the status of the input and output
queues to read a fixed size block or to support communication
timeouts.

At this opportunity it is proposed to move the documentation of the
serial port fconfigure options form the ''open.n'' man-page to
''fconfigure.n''.

~ Specification

It is proposed to have following set of [[fconfigure]] options for
serial communications:

 -mode baud,parity,data,stop: ''(Windows and Unix)''.  Already
    implemented.

 -handshake mode: ''(Windows and Unix)''.  This option is used to
    setup automatic handshake control.  Note that not all handshake
    modes maybe supported by your operating system.  The mode
    parameter is case-independent.

  > If mode is ''none'' then any handshake is switched off.
    ''rtscts'' activates hardware handshake.  For software handshake
    ''xonxoff'' the handshake characters can be redefined with
    [[fconfigure -xchar]].  An additional hardware handshake
    ''dtrdsr'' is available only for Windows.  There is no default
    handshake configuration, the initial value depends on your
    operating system settings.  The -handshake option cannot be
    queried, because the operating system settings may be ambiguous.

 -xchar {xonChar xoffChar}: ''(Windows and Unix)''.  This option is
    used to change the software handshake characters.  Normally the
    operating system default should be DC1 (0x11 hex) and DC3 (0x13
    hex) representing the ASCII standard XON and XOFF characters.  
    When queried -xchar returns a list of two characters representing 
    the XON and XOFF characters respectively.

 -timeout msec: ''(Windows and Unix''. This option is used to set 
    the timeout for blocking read operations. It specifies the 
    maximum interval between the receiption of two bytes in
    milliseconds. For Unix systems the granularity is 100 milliseconds.
    The -timeout option does not affect write operations or
    nonblocking reads. This option cannot be queried.

 -ttycontrol {signal boolean signal boolean ...}: ''(Windows and
    Unix)''.  This option is used to setup the handshake output lines
    permanently or to send a BREAK over the serial line.  The
    ''signal'' names are case-independent.

  > {RTS 1 DTR 0} sets the RTS output to high and the DTR output to
    low.  For POSIX systems {BREAK 1} sends a break signal
    (zero-valued bits) for 0.25 to 0.5 seconds and {BREAK 0} does
    nothing.  For Windows the break is enabled and disabled with
    {BREAK 1} and {BREAK 0} respectively.  It's not a good idea to
    change the RTS (or DTR) signal with active hardware handshake
    ''rtscts'' (or ''dtrdsr'').  The result is unpredictable.  The
    -ttycontrol option cannot be queried.

 -ttystatus: ''(Windows and Unix)''.  The -ttystatus option can only
    be queried.  It returns the current modem status and handshake
    input signals.  The result is a list of signal,value pairs with a
    fixed order, e.g. {CTS 1 DSR 0 RING 1 DCD 0}.  The ''signal''
    names are returned upper case.

 -queue: ''(Windows and Unix)''.  The -queue option can only be
    queried.  It returns a list of two integers representing the
    current number of bytes in the input and output queue respectively.

 -sysbuffer inSize: 

 -sysbuffer {inSize outSize}: ''(Windows only, Unix ?)''.  This option
    is used to change the size of Windows system buffers for a serial
    channel.  Especially at higher communication rates the default
    input buffer size of 4096 bytes can overrun for latent systems.
    The first form specifies the input buffer size, in the second form
    both input and output buffers are defined.

 -pollinterval msec: ''(Windows only)''.  Already implemented.

 -lasterror: ''(Windows only, Unix?)''.  Already implemented for
    Windows.

~ Implementation Details

For Unix (''termios.h'') systems the proposed changes are very
straight forward, because Unix channels can be configured blocking or
non-blocking.  One only needs to add the serial [[fconfigure]] options
calling the appropriate ''ioctl()'' functions to configure the serial
port.

For Windows reading and writing files is generally blocking.
Especially with activated handshake the serial communication can stop
forever.  Therefore the Windows implementation needs at least a
writing thread preventing Tcl's main application to block.
Additionally Windows provides a reach set of special APIs for serial
communication which needs to be translated to [[fconfigure]] options.

There is one special point about Windows: For making multiple threads
accessing a serial port, it needs to be opened with the OVERLAPPED
flag set.  Tcl detects a serial port only after opening it without the
OVERLAPPED flag.  Therefore this port has to be reopened, which
requires a little change to ''tclWinChan.c'' and ''tclWinPort.h''.

Macintosh systems - ?

~ Changed Files

 tclUnixChan.c: Add [[fconfigure]] options.

 tclWinPort.h: Declare a new function ''TclWinSerialReopen()''

 tclWinChan.h: Call ''TclWinSerialReopen()'' after detecting the
   serial port.

 tclWinSerial.c: Partial rewrite of Tcl's serial driver.  The current
    implementation only performs blocking output.  Add [[fconfigure]]
    options.

 fconfigure.n: Serial [[fconfigure]] options should be documented
    here.

 open.n: Serial port filenames are documented here.  Add a link to
    [[fconfigure]] for additional serial options.

~ Timeouts

It has also been proposed to add a [[fconfigure -timeout]] option
specifying read and write timeouts.  Together with a blocking read a
timeout could be used to wait for an expected number of data bytes
from the serial port.  There are two arguments against timeouts:

 1. Adding timeout to blocking I/O at the driver level radically
    changes the behaviour of write operations.  This adds a lot
    of oddity to serial communications.

 2. Timeouts can easily be implemented at Tcl level using non-blocking
    I/O together with Tcl's event loop.  Additional support is given
    by [[fconfigure -queue]].

July 03, 2001:
On the other hand timeout for read operations can easily be 
implemented in a cross-platform way by using the VMIN/VTIME settings
for Unix and the COMTIMEOUTS for Windows.
That's why the author finally agrees with the -timeout proposal.

~ Restore settings at close ?

It has also been proposed that Tcl should not restore the original
serial ports settings at [[close $chan]]. IMO it doesn't hurt, 
because anyway an application should care about setting up the serial
port properly before using. Without restoring a Tcl script could be 
used as a ''poor'' stty, considering however that Tcl 
does not provide a complete control over serial settings.

So the proposal is to remove the current save/restore mechanism
from the Unix implementation for serial ports.

~ Source code patches

The patches have been uploaded to the sourceforge patch tracker:
    ID=438509 TIP#35 Patches: Serial Port Enhancements
    file=tip35patch.tgz

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|



|
|

|










|

|











|
|

|

|


|


|




|
|
|
|
|




|

|
|



|






|
|

|

|
|
|

|
|
|


|


|


|





|






|

|


|

|

|
|







|





|



|

|

|

|



|


|



|

|

|










|







|


|


|





|


|


|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

# TIP 35: Enhanced Support for Serial Communications

	Author:         Rolf Schroedter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        06-Jun-2001
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

Tcl's support for RS-232 is very rudimentary.  Mainly it allows to
setup the communication rate [fconfigure -mode] and to read and
write data with the standard Tcl functions.  Real serial
communications are often more complex.  Therefore it is proposed to
add support for hardware and software flow control, polling RS-232
\(modem\) status lines, and watching the input and output queue.  This
is all to be implemented via additional [fconfigure] options.

# Rationale

There is an undamped interest in serial communications, because it's
very easy to connect external hardware to a computer using the RS-232
ports.

However Tcl's support for serial communications is not complete.  Real
applications often need more than setting the baud rate and to
read/write data bytes.

Especially if the external hardware is slow or the communication rate
is high one needs support for flow-control \(hard- and software\).
These features are provided by the operating system drivers, but Tcl's
[fconfigure] doesn't support it.

On the the other hand there are cases that the external hardware makes
static use of the RS-232 signals to signal external events via the
modem status lines or even to be powered by the RS-232 control lines.

Additionally for non-blocking serial I/O it may be interesting for the
Tcl application to know about the status of the input and output
queues to read a fixed size block or to support communication
timeouts.

At this opportunity it is proposed to move the documentation of the
serial port fconfigure options form the _open.n_ man-page to
_fconfigure.n_.

# Specification

It is proposed to have following set of [fconfigure] options for
serial communications:

 -mode baud,parity,data,stop: _\(Windows and Unix\)_.  Already
    implemented.

 -handshake mode: _\(Windows and Unix\)_.  This option is used to
    setup automatic handshake control.  Note that not all handshake
    modes maybe supported by your operating system.  The mode
    parameter is case-independent.

  > If mode is _none_ then any handshake is switched off.
    _rtscts_ activates hardware handshake.  For software handshake
    _xonxoff_ the handshake characters can be redefined with
    [fconfigure -xchar].  An additional hardware handshake
    _dtrdsr_ is available only for Windows.  There is no default
    handshake configuration, the initial value depends on your
    operating system settings.  The -handshake option cannot be
    queried, because the operating system settings may be ambiguous.

 -xchar \{xonChar xoffChar\}: _\(Windows and Unix\)_.  This option is
    used to change the software handshake characters.  Normally the
    operating system default should be DC1 \(0x11 hex\) and DC3 \(0x13
    hex\) representing the ASCII standard XON and XOFF characters.  
    When queried -xchar returns a list of two characters representing 
    the XON and XOFF characters respectively.

 -timeout msec: _\(Windows and Unix_. This option is used to set 
    the timeout for blocking read operations. It specifies the 
    maximum interval between the receiption of two bytes in
    milliseconds. For Unix systems the granularity is 100 milliseconds.
    The -timeout option does not affect write operations or
    nonblocking reads. This option cannot be queried.

 -ttycontrol \{signal boolean signal boolean ...\}: _\(Windows and
    Unix\)_.  This option is used to setup the handshake output lines
    permanently or to send a BREAK over the serial line.  The
    _signal_ names are case-independent.

  > \{RTS 1 DTR 0\} sets the RTS output to high and the DTR output to
    low.  For POSIX systems \{BREAK 1\} sends a break signal
    \(zero-valued bits\) for 0.25 to 0.5 seconds and \{BREAK 0\} does
    nothing.  For Windows the break is enabled and disabled with
    \{BREAK 1\} and \{BREAK 0\} respectively.  It's not a good idea to
    change the RTS \(or DTR\) signal with active hardware handshake
    _rtscts_ \(or _dtrdsr_\).  The result is unpredictable.  The
    -ttycontrol option cannot be queried.

 -ttystatus: _\(Windows and Unix\)_.  The -ttystatus option can only
    be queried.  It returns the current modem status and handshake
    input signals.  The result is a list of signal,value pairs with a
    fixed order, e.g. \{CTS 1 DSR 0 RING 1 DCD 0\}.  The _signal_
    names are returned upper case.

 -queue: _\(Windows and Unix\)_.  The -queue option can only be
    queried.  It returns a list of two integers representing the
    current number of bytes in the input and output queue respectively.

 -sysbuffer inSize: 

 -sysbuffer \{inSize outSize\}: _\(Windows only, Unix ?\)_.  This option
    is used to change the size of Windows system buffers for a serial
    channel.  Especially at higher communication rates the default
    input buffer size of 4096 bytes can overrun for latent systems.
    The first form specifies the input buffer size, in the second form
    both input and output buffers are defined.

 -pollinterval msec: _\(Windows only\)_.  Already implemented.

 -lasterror: _\(Windows only, Unix?\)_.  Already implemented for
    Windows.

# Implementation Details

For Unix \(_termios.h_\) systems the proposed changes are very
straight forward, because Unix channels can be configured blocking or
non-blocking.  One only needs to add the serial [fconfigure] options
calling the appropriate _ioctl\(\)_ functions to configure the serial
port.

For Windows reading and writing files is generally blocking.
Especially with activated handshake the serial communication can stop
forever.  Therefore the Windows implementation needs at least a
writing thread preventing Tcl's main application to block.
Additionally Windows provides a reach set of special APIs for serial
communication which needs to be translated to [fconfigure] options.

There is one special point about Windows: For making multiple threads
accessing a serial port, it needs to be opened with the OVERLAPPED
flag set.  Tcl detects a serial port only after opening it without the
OVERLAPPED flag.  Therefore this port has to be reopened, which
requires a little change to _tclWinChan.c_ and _tclWinPort.h_.

Macintosh systems - ?

# Changed Files

 tclUnixChan.c: Add [fconfigure] options.

 tclWinPort.h: Declare a new function _TclWinSerialReopen\(\)_

 tclWinChan.h: Call _TclWinSerialReopen\(\)_ after detecting the
   serial port.

 tclWinSerial.c: Partial rewrite of Tcl's serial driver.  The current
    implementation only performs blocking output.  Add [fconfigure]
    options.

 fconfigure.n: Serial [fconfigure] options should be documented
    here.

 open.n: Serial port filenames are documented here.  Add a link to
    [fconfigure] for additional serial options.

# Timeouts

It has also been proposed to add a [fconfigure -timeout] option
specifying read and write timeouts.  Together with a blocking read a
timeout could be used to wait for an expected number of data bytes
from the serial port.  There are two arguments against timeouts:

 1. Adding timeout to blocking I/O at the driver level radically
    changes the behaviour of write operations.  This adds a lot
    of oddity to serial communications.

 2. Timeouts can easily be implemented at Tcl level using non-blocking
    I/O together with Tcl's event loop.  Additional support is given
    by [fconfigure -queue].

July 03, 2001:
On the other hand timeout for read operations can easily be 
implemented in a cross-platform way by using the VMIN/VTIME settings
for Unix and the COMTIMEOUTS for Windows.
That's why the author finally agrees with the -timeout proposal.

# Restore settings at close ?

It has also been proposed that Tcl should not restore the original
serial ports settings at [close $chan]. IMO it doesn't hurt, 
because anyway an application should care about setting up the serial
port properly before using. Without restoring a Tcl script could be 
used as a _poor_ stty, considering however that Tcl 
does not provide a complete control over serial settings.

So the proposal is to remove the current save/restore mechanism
from the Unix implementation for serial ports.

# Source code patches

The patches have been uploaded to the sourceforge patch tracker:
    ID=438509 TIP\#35 Patches: Serial Port Enhancements
    file=tip35patch.tgz

# Copyright

This document has been placed in the public domain.

Name change from tip/350.tip to tip/350.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

151
152
153
154

155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269

TIP:		350
Title:		Tcl Database Connectivity - Corrigenda
Version:	$Revision: 1.1 $
Author:		Kevin B. Kenny <[email protected]>
State:		Draft
Type:		Informative
Created:	18-Apr-2009
Post-History:
Vote:		Pending
Obsoletes:	308


~ Abstract

This TIP defines a common database access interface for Tcl scripts. It is an
update to [308] to take into account experience gained since that TIP was
written. Note that this TIP does ''not'' repeat the contents of that one,
which is mostly correct apart from the changes described in this document.

~ Summary of Changes

Implementation experience on Tcl Database Connectivity [308] has exposed
several issues with its specification that require editorial corrections. In
brief:

   1. The error codes returned from TDBC drivers are detailed in such a way as
      to make them more usable in the '''try''' command.

   1. The '''starttransaction''' method on a database connection is renamed,
      '''begintransaction'''

   1. The '''execute''' method on a statement, and all of the methods that
      invoke it ('''allrows''' and '''foreach''' on database connections)
      changes its behaviour in the case where a bound variable in its SQL code
      refers to a Tcl variable that is an array, or a read trace on the
      associated variable fails.

   1. The order of arguments on the '''foreach''' methods on database
      connections, statements and result sets is changed.

   1. The ''statementClass'' and ''resultSetClass'' instance variables, and
      the ''init'' method of connections, statements and result sets, are
      deprecated; a new initialization API is provided.

   1. A Tcl command, '''tdbc::mapSqlState''', and a C function,
      '''Tdbc_MapSqlState''' are provided for the convenience of driver
      writers.

~ Introduction

The actual implementation of TDBC and three database drivers for it has
revealed a handful of mistakes in the TDBC specification [308].  The purpose
of this TIP is to correct those errors and promulgate a specification that
matches TDBC as implemented.

~ Specification

~~ Error Codes

Whenever a TDBC driver reports an error in interacting with an underlying
database, it SHOULD set the interpreter error code to a list of at least four
elements. The first element should be the constant string '''TDBC'''. The
second should be an 'error class' chosen from the list below.  The third
should be the (usually five-character) SQL state that the database reported,
or the constant string '''HY000''' if the SQL state cannot be determined.  (In
the latter case, the error class should be '''GENERAL_ERROR'''.)  The fourth
element should be the name of the TDBC driver that reported the error. Any
elements beyond the fourth SHOULD give further details (for example an error
code returned by a native API), and are driver dependent.

The permissible values for the error class are as follows.  Note that each one
corresponds to the first two characters of a five-character 'SQL state' that
is common to most SQL database API's; the SQL state corresponding to the class
is also given.

| SQL State
| Prefix     Error Class
| --------------------------------------------------------
|    00      UNQUALIFIED_SUCCESSFUL_COMPLETION
|    01      WARNING
|    02      NO_DATA
|    07      DYNAMIC_SQL_ERROR
|    08      CONNECTION_EXCEPTION
|    09      TRIGGERED_ACTION_EXCEPTION
|    0A      FEATURE_NOT_SUPPORTED
|    0B      INVALID_TRANSACTION_INITIATION
|    0D      INVALID_TARGET_TYPE_SPECIFICATION
|    0F      LOCATOR_EXCEPTION
|    0K      INVALID_RESIGNAL_STATEMENT
|    0L      INVALID_GRANTOR
|    0P      INVALID_ROLE_SPECIFICATION
|    0W      INVALID_STATEMENT_UN_TRIGGER
|    20      CASE_NOT_FOUND_FOR_CASE_STATEMENT
|    21      CARDINALITY_VIOLATION
|    22      DATA_EXCEPTION
|    23      CONSTRAINT_VIOLATION
|    24      INVALID_CURSOR_STATE
|    25      INVALID_TRANSACTION_STATE
|    26      INVALID_SQL_STATEMENT_IDENTIFIER
|    27      TRIGGERED_DATA_CHANGE_VIOLATION
|    28      INVALID_AUTHORIZATION_SPECIFICATION
|    2B      DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST
|    2C      INVALID_CHARACTER_SET_NAME
|    2D      INVALID_TRANSACTION_TERMINATION
|    2E      INVALID_CONNECTION_NAME
|    2F      SQL_ROUTINE_EXCEPTION
|    33      INVALID_SQL_DESCRIPTOR_NAME
|    34      INVALID_CURSOR_NAME
|    35      INVALID_CONDITION_NUMBER
|    36      CURSOR_SENSITIVITY_EXCEPTION
|    37      SYNTAX_ERROR_OR_ACCESS_VIOLATION
|    38      EXTERNAL_ROUTINE_EXCEPTION
|    39      EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
|    3B      SAVEPOINT_EXCEPTION
|    3C      AMBIGUOUS_CURSOR_NAME
|    3D      INVALID_CATALOG_NAME
|    3F      INVALID_SCHEMA_NAME
|    40      TRANSACTION_ROLLBACK
|    42      SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION
|    44      WITH_CHECK_OPTION_VIOLATION
|    45      UNHANDLED_USER_DEFINED_EXCEPTION
|    46      JAVA_DDL
|    51      INVALID_APPLICATION_STATE
|    53      INSUFFICIENT_RESOURCES
|    54      PROGRAM_LIMIT_EXCEEDED
|    55      OBJECT_NOT_IN_PREREQUISITE_STATE
|    56      MISCELLANEOUS_SQL_OR_PRODUCT_ERROR
|    57      RESOURCE_NOT_AVAILABLE_OR_OPERATOR_INTERVENTION
|    58      SYSTEM_ERROR
|    70      INTERRUPTED
|    F0      CONFIGURATION_FILE_ERROR
|    HY      GENERAL_ERROR
|    HZ      REMOTE_DATABASE_ACCESS_ERROR
|    IM      DRIVER_ERROR
|    P0      PGSQL_PLSQL_ERROR
|    S0      ODBC_2_0_DML_ERROR
|    S1      ODBC_2_0_GENERAL_ERROR
|    XA      TRANSACTION_ERROR
|    XX      INTERNAL_ERROR
|  anything
|   else     UNKNOWN_SQLSTATE

The reason for structuring the error codes in this way is to make errors more
accessible to the '''try''' command [329]. For instance, a Tcl script that
wishes to detect and handle division by zero in a SQL statement might look
like:

|  try {
|      $statement foreach row {
|          # ... process the row
|      }

| } trap {TDBC DATA_EXCEPTION 22012} {
|      puts "Division by zero!"
| }


Since the previous specification [308] left the error code unspecified, this
change is not expected to impact any client code.

~~ Transaction Control

The '''begintransaction''' method was inadvertently called,
'''starttransaction''' in the TDBC specification. Therefore, the word
'''starttransaction''' should be replaced with '''begintransaction''' wherever
it appears.

This change will break no existing code; no '''starttransaction''' method has
been defined for any TDBC driver.

~~ The '''execute''' Method of a Statement - Variable Substitution

The rule that an array variable provided as a bound value to a substituent in
a SQL statement MUST result in an error has proven to be awkward to implement
in practice.  Moreover, the original specification [308] fails to indicate
what happens if a read trace on one of a statement's bound variables throws an
error.

The sentence,

 > An array variable provided to a substituent MUST result in an error.

is therefore to be replaced with:

 > An array variable provided to a substituent, or a variable in which
   substitution results in an error being reported by a read trace, MUST
   result in a NULL value being provided.

This change is expected to have minimal impact on existing code; the behaviour
being described is simply providing a NULL value for a case that was an error
before (an array where a scalar is expected) and a case that was unspecified
before (an error within a variable trace).

~~ The ''foreach'' Methods

The syntax of the ''foreach'' method of connections, statements, and result
sets in the original specification contains editorial errors.  The correct
syntax is:

 > ''dbHandle'' '''foreach''' ?'''-as''' '''lists'''|'''dicts'''?
   ?'''-columnsvariable''' ''varName''? ?--? 
   ''varName'' ''sql'' ?''dictionary''? ''script''

 > ''statement'' '''foreach''' ?'''-as''' '''lists'''|'''dicts'''?
   ?'''-columnsvariable''' ''varName''? ?--? 
   ''varName'' ?''dictionary''? ''script''

 > ''resultset'' '''foreach'''  ?'''-as''' '''lists'''|'''dicts'''?
   ?'''-columnsvariable''' ''varName''? ?--? 
   ''varName'' ''script''

This change represents an editorial correction; the reference implementation
functioned in this way even prior to the acceptance of the original
specification [308].

~~ The Constructor Patterns

The ''statementClass'' variable, and the '''init''' method, are no longer
recommended for use in the constructors of connection classes.  Instead, the
recommended pattern is that a connection class SHOULD implement a
'''statementCreate''' method that accepts the fully qualified name of the
command that is to represent the statement, the connection handle and the SQL
statement, and returns a handle to the statement object.  The usual way to do
so is with a forwarded method:

|  forward statementCreate ::driver::statement create

If the '''statementCreate''' method is not present, the default one looks for
a variable named ''statementClass'' in the connection object, and invokes its
'''create''' command.

In this way, drivers that are written to the original specification continue
to operate.

Similarly, the ''resultSetClass'' variable, and the '''init''' method, are no
longer recommended for use in the constructors of statement classes. Instead,
the statement class SHOULD implement a '''resultSetCreate''' method that
accepts the fully qualified name of the command that will represent the result
set, the statement handle, and the parameters to the '''prepare''' method.
Once again, this method will usually simply be forwarded to the appropriate
constructor:

|  forward resultSetCreate ::driver::resultSet create

Once again, backward compatibility is provided by a '''resultSetCreate'''
method in the base class.  This method looks for a ''resultSetClass'' variable
in the statement instance, and interprets it as a class name, invoking the
''create'' method in that class.

''Rationale:'' These changes eliminate several jumps among methods with
'''uplevel''' calls, and yield both simpler code and improved performance.

~~ SQL State Mapping

For the convenience of drivers that deal with database APIs that provide a
standard SQL dtate in the event of errors, a Tcl command,
'''tdbc::mapSqlState''' is provided.  This command accepts a (usually five
character) SQL state, and returns the error class that should go in the second
element of the error code.  The mapping is described in the table in the
'''Error Codes''' section above.

Similarly, A C function is provided:

 > const char * '''Tdbc_MapSqlState'''(const char *''sqlstate'');

This call looks up the given ''sqlstate'' and returns its error class
according to the table.

~ License

This file is explicitly released to the public domain and the author
explicitly disclaims all rights under copyright law.

<
|
<
|
|
|
|
|
|
|
>

|


|
|


|

|




|

|
|

|
|




|


|
|


|
|


|


|



|

|



|

|
|
|

|
|






|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


|



|
|
|
<
>
|
|
<
|
>
|


|

|
|
|


|


|



|















|
|

|

|



|
|
|

|
|
|

|
|
|



|

|

|


|




|

|
|
|




|

|

|



|

|
|

|

|
|

|



|
|

|



|

|


|



>

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
136
137
138
139
140
141
142
143
144
145
146
147
148

149
150
151

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269

# TIP 350: Tcl Database Connectivity - Corrigenda

	Author:		Kevin B. Kenny <[email protected]>
	State:		Draft
	Type:		Informative
	Created:	18-Apr-2009
	Post-History:
	Vote:		Pending
	Obsoletes:	308
-----

# Abstract

This TIP defines a common database access interface for Tcl scripts. It is an
update to [[308]](308.md) to take into account experience gained since that TIP was
written. Note that this TIP does _not_ repeat the contents of that one,
which is mostly correct apart from the changes described in this document.

# Summary of Changes

Implementation experience on Tcl Database Connectivity [[308]](308.md) has exposed
several issues with its specification that require editorial corrections. In
brief:

   1. The error codes returned from TDBC drivers are detailed in such a way as
      to make them more usable in the **try** command.

   1. The **starttransaction** method on a database connection is renamed,
      **begintransaction**

   1. The **execute** method on a statement, and all of the methods that
      invoke it \(**allrows** and **foreach** on database connections\)
      changes its behaviour in the case where a bound variable in its SQL code
      refers to a Tcl variable that is an array, or a read trace on the
      associated variable fails.

   1. The order of arguments on the **foreach** methods on database
      connections, statements and result sets is changed.

   1. The _statementClass_ and _resultSetClass_ instance variables, and
      the _init_ method of connections, statements and result sets, are
      deprecated; a new initialization API is provided.

   1. A Tcl command, **tdbc::mapSqlState**, and a C function,
      **Tdbc\_MapSqlState** are provided for the convenience of driver
      writers.

# Introduction

The actual implementation of TDBC and three database drivers for it has
revealed a handful of mistakes in the TDBC specification [[308]](308.md).  The purpose
of this TIP is to correct those errors and promulgate a specification that
matches TDBC as implemented.

# Specification

## Error Codes

Whenever a TDBC driver reports an error in interacting with an underlying
database, it SHOULD set the interpreter error code to a list of at least four
elements. The first element should be the constant string **TDBC**. The
second should be an 'error class' chosen from the list below.  The third
should be the \(usually five-character\) SQL state that the database reported,
or the constant string **HY000** if the SQL state cannot be determined.  \(In
the latter case, the error class should be **GENERAL\_ERROR**.\)  The fourth
element should be the name of the TDBC driver that reported the error. Any
elements beyond the fourth SHOULD give further details \(for example an error
code returned by a native API\), and are driver dependent.

The permissible values for the error class are as follows.  Note that each one
corresponds to the first two characters of a five-character 'SQL state' that
is common to most SQL database API's; the SQL state corresponding to the class
is also given.

	 SQL State
	 Prefix     Error Class
	 --------------------------------------------------------
	    00      UNQUALIFIED_SUCCESSFUL_COMPLETION
	    01      WARNING
	    02      NO_DATA
	    07      DYNAMIC_SQL_ERROR
	    08      CONNECTION_EXCEPTION
	    09      TRIGGERED_ACTION_EXCEPTION
	    0A      FEATURE_NOT_SUPPORTED
	    0B      INVALID_TRANSACTION_INITIATION
	    0D      INVALID_TARGET_TYPE_SPECIFICATION
	    0F      LOCATOR_EXCEPTION
	    0K      INVALID_RESIGNAL_STATEMENT
	    0L      INVALID_GRANTOR
	    0P      INVALID_ROLE_SPECIFICATION
	    0W      INVALID_STATEMENT_UN_TRIGGER
	    20      CASE_NOT_FOUND_FOR_CASE_STATEMENT
	    21      CARDINALITY_VIOLATION
	    22      DATA_EXCEPTION
	    23      CONSTRAINT_VIOLATION
	    24      INVALID_CURSOR_STATE
	    25      INVALID_TRANSACTION_STATE
	    26      INVALID_SQL_STATEMENT_IDENTIFIER
	    27      TRIGGERED_DATA_CHANGE_VIOLATION
	    28      INVALID_AUTHORIZATION_SPECIFICATION
	    2B      DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST
	    2C      INVALID_CHARACTER_SET_NAME
	    2D      INVALID_TRANSACTION_TERMINATION
	    2E      INVALID_CONNECTION_NAME
	    2F      SQL_ROUTINE_EXCEPTION
	    33      INVALID_SQL_DESCRIPTOR_NAME
	    34      INVALID_CURSOR_NAME
	    35      INVALID_CONDITION_NUMBER
	    36      CURSOR_SENSITIVITY_EXCEPTION
	    37      SYNTAX_ERROR_OR_ACCESS_VIOLATION
	    38      EXTERNAL_ROUTINE_EXCEPTION
	    39      EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
	    3B      SAVEPOINT_EXCEPTION
	    3C      AMBIGUOUS_CURSOR_NAME
	    3D      INVALID_CATALOG_NAME
	    3F      INVALID_SCHEMA_NAME
	    40      TRANSACTION_ROLLBACK
	    42      SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION
	    44      WITH_CHECK_OPTION_VIOLATION
	    45      UNHANDLED_USER_DEFINED_EXCEPTION
	    46      JAVA_DDL
	    51      INVALID_APPLICATION_STATE
	    53      INSUFFICIENT_RESOURCES
	    54      PROGRAM_LIMIT_EXCEEDED
	    55      OBJECT_NOT_IN_PREREQUISITE_STATE
	    56      MISCELLANEOUS_SQL_OR_PRODUCT_ERROR
	    57      RESOURCE_NOT_AVAILABLE_OR_OPERATOR_INTERVENTION
	    58      SYSTEM_ERROR
	    70      INTERRUPTED
	    F0      CONFIGURATION_FILE_ERROR
	    HY      GENERAL_ERROR
	    HZ      REMOTE_DATABASE_ACCESS_ERROR
	    IM      DRIVER_ERROR
	    P0      PGSQL_PLSQL_ERROR
	    S0      ODBC_2_0_DML_ERROR
	    S1      ODBC_2_0_GENERAL_ERROR
	    XA      TRANSACTION_ERROR
	    XX      INTERNAL_ERROR
	  anything
	   else     UNKNOWN_SQLSTATE

The reason for structuring the error codes in this way is to make errors more
accessible to the **try** command [[329]](329.md). For instance, a Tcl script that
wishes to detect and handle division by zero in a SQL statement might look
like:

	  try {
	      $statement foreach row {
	          # ... process the row

	      }
	 } trap {TDBC DATA_EXCEPTION 22012} {
	      puts "Division by zero!"

	 }

Since the previous specification [[308]](308.md) left the error code unspecified, this
change is not expected to impact any client code.

## Transaction Control

The **begintransaction** method was inadvertently called,
**starttransaction** in the TDBC specification. Therefore, the word
**starttransaction** should be replaced with **begintransaction** wherever
it appears.

This change will break no existing code; no **starttransaction** method has
been defined for any TDBC driver.

## The **execute** Method of a Statement - Variable Substitution

The rule that an array variable provided as a bound value to a substituent in
a SQL statement MUST result in an error has proven to be awkward to implement
in practice.  Moreover, the original specification [[308]](308.md) fails to indicate
what happens if a read trace on one of a statement's bound variables throws an
error.

The sentence,

 > An array variable provided to a substituent MUST result in an error.

is therefore to be replaced with:

 > An array variable provided to a substituent, or a variable in which
   substitution results in an error being reported by a read trace, MUST
   result in a NULL value being provided.

This change is expected to have minimal impact on existing code; the behaviour
being described is simply providing a NULL value for a case that was an error
before \(an array where a scalar is expected\) and a case that was unspecified
before \(an error within a variable trace\).

## The _foreach_ Methods

The syntax of the _foreach_ method of connections, statements, and result
sets in the original specification contains editorial errors.  The correct
syntax is:

 > _dbHandle_ **foreach** ?**-as** **lists**\|**dicts**?
   ?**-columnsvariable** _varName_? ?--? 
   _varName_ _sql_ ?_dictionary_? _script_

 > _statement_ **foreach** ?**-as** **lists**\|**dicts**?
   ?**-columnsvariable** _varName_? ?--? 
   _varName_ ?_dictionary_? _script_

 > _resultset_ **foreach**  ?**-as** **lists**\|**dicts**?
   ?**-columnsvariable** _varName_? ?--? 
   _varName_ _script_

This change represents an editorial correction; the reference implementation
functioned in this way even prior to the acceptance of the original
specification [[308]](308.md).

## The Constructor Patterns

The _statementClass_ variable, and the **init** method, are no longer
recommended for use in the constructors of connection classes.  Instead, the
recommended pattern is that a connection class SHOULD implement a
**statementCreate** method that accepts the fully qualified name of the
command that is to represent the statement, the connection handle and the SQL
statement, and returns a handle to the statement object.  The usual way to do
so is with a forwarded method:

	  forward statementCreate ::driver::statement create

If the **statementCreate** method is not present, the default one looks for
a variable named _statementClass_ in the connection object, and invokes its
**create** command.

In this way, drivers that are written to the original specification continue
to operate.

Similarly, the _resultSetClass_ variable, and the **init** method, are no
longer recommended for use in the constructors of statement classes. Instead,
the statement class SHOULD implement a **resultSetCreate** method that
accepts the fully qualified name of the command that will represent the result
set, the statement handle, and the parameters to the **prepare** method.
Once again, this method will usually simply be forwarded to the appropriate
constructor:

	  forward resultSetCreate ::driver::resultSet create

Once again, backward compatibility is provided by a **resultSetCreate**
method in the base class.  This method looks for a _resultSetClass_ variable
in the statement instance, and interprets it as a class name, invoking the
_create_ method in that class.

_Rationale:_ These changes eliminate several jumps among methods with
**uplevel** calls, and yield both simpler code and improved performance.

## SQL State Mapping

For the convenience of drivers that deal with database APIs that provide a
standard SQL dtate in the event of errors, a Tcl command,
**tdbc::mapSqlState** is provided.  This command accepts a \(usually five
character\) SQL state, and returns the error class that should go in the second
element of the error code.  The mapping is described in the table in the
**Error Codes** section above.

Similarly, A C function is provided:

 > const char \* **Tdbc\_MapSqlState**\(const char \*_sqlstate_\);

This call looks up the given _sqlstate_ and returns its error class
according to the table.

# License

This file is explicitly released to the public domain and the author
explicitly disclaims all rights under copyright law.

Name change from tip/351.tip to tip/351.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

TIP:            351
Title:          Add Striding Support to lsearch
Version:        $Revision: 1.19 $
Author:         Peter da Silva <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         Harald Oehlmann <[email protected]>
Author:         Andreas Leitgeb <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        09-Jul-2009
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP allows the searching of lists that are grouped into collections of
several elements.

~ Rationale

When operating on strided lists (for example key-value lists) it's normal to
convert them between lists and arrays and back again. If it was possible to
efficiently perform a strided search of the list it would be possible to (for
example) search just the keys and ignore the values. Indeed, Tcl has a long
tradition of working with lists which are structured into groups through
'''foreach''' and '''array get''', and this is strengthened further with
dictionaries [111] and striding sorts [326]. However, there is currently no
facility for searching such lists; this TIP proposes fixing this.

~ Proposed Change

We propose adding a '''-stride''' option to '''lsearch''', by exact analogy with the option added to '''lsort''' in [326], whose semantics it should closely match.

If '''-stride''' is supplied, the list will be treated as consisting of groups of grpSize elements.
The search will be operated within this group as it is a first level of nested lists (see ''Conceptual Backround'' below).

The first element of '''-index''' is used to seach for an item of the group.

The option '''-start''' always points to the beginning of the group, even if a position within the group is given.

Returned indices are the first element of the striding group(s) that is/are being indicated.

The list length must be a multiple of '''grpSize''', which in turn must be at least 2.

~ Conceptual Backround

~~ Striding equivalent to first level of nested lists

The striding within the list is seen as the first level of list nesting.
E.g.

'''Nested list''':

|set deep {{1 a A} {2 b B} {3 c C}}

'''Flat strided list''': 

|set flat {1 a A 2 b B 3 c C}

Functions should operate the same way on both representation, with the only difference, that '''-stride 3''' must be specified in the second case.

Unfortunately, the current implementation of '''lsort''' is not doing this.
It interpretes '''-index ""''' as '''-index 0''':

|% lsort -stride 2 {A 1 A 2 A 0}
|A 1 A 2 A 0
|% lsort -stride 2 -index "" {B 2 B 1 A 3}
|A 3 B 2 B 1

~~ Numeric position indices

Numerical positional indices (-start parameter, return value) follow the flattened list and not the grouped list.
This is different to the nested list view.

Furthermore, if option '''-subindices''' is given and a non-empty argument for '''-index''', then the group-start and index-into-group are added up. This gives compatibility with lindex, as in the no-stride case.

~ Examples

In these examples, the variable ''kvlist'' holds the key-value list:

|set kvlist {K1 V1 K2 V1 K1 K1}

Example 1: find keys even if they exist multiple times:

|% lsearch -all -stride 2 -index 0 -exact $kvlist K1
|0 4

Example 2: find existance of a value:

|% lsearch -all -stride 2 -index 1 -exact $kvlist V1
|0 2

Remark that the indexes of the first group elements are returned.
The real values are at "result+index" eq '''1 3'''.

Example 3: extract a sub-kv-list starting from key K2:

|% lrange $kvlist [lsearch -stride 2 -index 0 -exact $kvlist K2] end
|K2 V1 K1 K1

Example 4: find a group within a list:

|% lsearch -stride 2 -exact $kvlist {K2 V1}
|2


Example 5: find in combined strided and nested list

|% lsearch -stride 2 -index {1 1} -exact\
|        {K0 {V0.0 V0.1} K1 {V1.0 V1.1}}\
|        V1.1
|2


Example 6: subindices with strided list:

|% lsearch -stride 2 -index {1 1} -subindices {1 {a A} 2 {b B}} B
|3 1   (that is: 2 for the group-start plus 1 for the intra-group
|       index, and separately 1 for the further nested index.
|% lindex {1 {a A} 2 {b B}} 3 1
|B


to be consisten with:

|% lsearch -index {1 1} -subindices {{1 {a A}} {2 {b B}}} B
|1 1 1
|% lindex {{1 {a A}} {2 {b B}}} 1 1 1
|B


~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|




|

|

|
|

|
|


|

|

|
|

|

|

|

|

|

|




|

|

|

|

|

|
|

|
|
|
|

|

|


|

|

|

|



|
|



|
|


|



|
|



|
<
>



|
|
|
<
>



|
|
|
|
<
>



|
|
|
<
|
>
|


>

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

# TIP 351: Add Striding Support to lsearch

	Author:         Peter da Silva <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         Harald Oehlmann <[email protected]>
	Author:         Andreas Leitgeb <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        09-Jul-2009
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP allows the searching of lists that are grouped into collections of
several elements.

# Rationale

When operating on strided lists \(for example key-value lists\) it's normal to
convert them between lists and arrays and back again. If it was possible to
efficiently perform a strided search of the list it would be possible to \(for
example\) search just the keys and ignore the values. Indeed, Tcl has a long
tradition of working with lists which are structured into groups through
**foreach** and **array get**, and this is strengthened further with
dictionaries [[111]](111.md) and striding sorts [[326]](326.md). However, there is currently no
facility for searching such lists; this TIP proposes fixing this.

# Proposed Change

We propose adding a **-stride** option to **lsearch**, by exact analogy with the option added to **lsort** in [[326]](326.md), whose semantics it should closely match.

If **-stride** is supplied, the list will be treated as consisting of groups of grpSize elements.
The search will be operated within this group as it is a first level of nested lists \(see _Conceptual Backround_ below\).

The first element of **-index** is used to seach for an item of the group.

The option **-start** always points to the beginning of the group, even if a position within the group is given.

Returned indices are the first element of the striding group\(s\) that is/are being indicated.

The list length must be a multiple of **grpSize**, which in turn must be at least 2.

# Conceptual Backround

## Striding equivalent to first level of nested lists

The striding within the list is seen as the first level of list nesting.
E.g.

**Nested list**:

	set deep {{1 a A} {2 b B} {3 c C}}

**Flat strided list**: 

	set flat {1 a A 2 b B 3 c C}

Functions should operate the same way on both representation, with the only difference, that **-stride 3** must be specified in the second case.

Unfortunately, the current implementation of **lsort** is not doing this.
It interpretes **-index ""** as **-index 0**:

	% lsort -stride 2 {A 1 A 2 A 0}
	A 1 A 2 A 0
	% lsort -stride 2 -index "" {B 2 B 1 A 3}
	A 3 B 2 B 1

## Numeric position indices

Numerical positional indices \(-start parameter, return value\) follow the flattened list and not the grouped list.
This is different to the nested list view.

Furthermore, if option **-subindices** is given and a non-empty argument for **-index**, then the group-start and index-into-group are added up. This gives compatibility with lindex, as in the no-stride case.

# Examples

In these examples, the variable _kvlist_ holds the key-value list:

	set kvlist {K1 V1 K2 V1 K1 K1}

Example 1: find keys even if they exist multiple times:

	% lsearch -all -stride 2 -index 0 -exact $kvlist K1
	0 4

Example 2: find existance of a value:

	% lsearch -all -stride 2 -index 1 -exact $kvlist V1
	0 2

Remark that the indexes of the first group elements are returned.
The real values are at "result\+index" eq **1 3**.

Example 3: extract a sub-kv-list starting from key K2:

	% lrange $kvlist [lsearch -stride 2 -index 0 -exact $kvlist K2] end
	K2 V1 K1 K1

Example 4: find a group within a list:

	% lsearch -stride 2 -exact $kvlist {K2 V1}

	2

Example 5: find in combined strided and nested list

	% lsearch -stride 2 -index {1 1} -exact\
	        {K0 {V0.0 V0.1} K1 {V1.0 V1.1}}\
	        V1.1

	2

Example 6: subindices with strided list:

	% lsearch -stride 2 -index {1 1} -subindices {1 {a A} 2 {b B}} B
	3 1   (that is: 2 for the group-start plus 1 for the intra-group
	       index, and separately 1 for the further nested index.
	% lindex {1 {a A} 2 {b B}} 3 1

	B

to be consisten with:

	% lsearch -index {1 1} -subindices {{1 {a A}} {2 {b B}}} B
	1 1 1
	% lindex {{1 {a A}} {2 {b B}}} 1 1 1

	B

# Copyright

This document has been placed in the public domain.

Name change from tip/352.tip to tip/352.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
TIP:            352
Title:          Tcl Style Guide
Version:        $Revision: 1.5 $
Author:         Ray Johnson <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         Mark Janssen <[email protected]>
State:          Draft
Type:           Informative
Vote:           Pending
Created:        14-Jul-2009
Post-History:   


~ Abstract

This document describes a set of conventions that it is suggested people use
when writing Tcl code. It is substantially based on the Tcl/Tk Engineering
Manual [247].

~~NOTE

''A transcription of the original version (dated August 22, 1997) of this file
into PDF is available online at http://www.tcl.tk/doc/styleGuide.pdf - Donal
K. Fellows.''

~ Introduction

This is a manual for people who are developing Tcl code for Wish or any other
Tcl application. It describes a set of conventions for writing code and the
associated test scripts. There are three reasons for the conventions. First,
the conventions ensure that certain important things get done; for example,
every procedure must have documentation that describes each of its arguments
and its result, and there must exist test scripts that exercise every line of
code. Second, the conventions guarantee that all of the Tcl and Tk code has a
uniform style. This makes it easier for us to use, read, and maintain each
other's code. Third, the conventions help to avoid some common mistakes by
prohibiting error-prone constructs such as building lists by hand instead of
using the list building procedures.

This document is based heavily on the ''Tcl/Tk Engineering Manual'' written by
John Ousterhout. John's engineering manual specified the style of the C code
used in the implementation of Tcl/Tk and many of its extensions. The manual is
very valuable to the development of Tcl/Tk and is an important reason why Tcl
is a relatively easy system to maintain.

Deciding any style standard involves making trade-offs that are usually
subjective. This standard was created in an iterative process involving the
<
|
<
|
|
|
|
|
|
|
|
>

|



|

|

|
|
|

|













|








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

# TIP 352: Tcl Style Guide

	Author:         Ray Johnson <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         Mark Janssen <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        14-Jul-2009
	Post-History:   
-----

# Abstract

This document describes a set of conventions that it is suggested people use
when writing Tcl code. It is substantially based on the Tcl/Tk Engineering
Manual [[247]](247.md).

## NOTE

_A transcription of the original version \(dated August 22, 1997\) of this file
into PDF is available online at <http://www.tcl.tk/doc/styleGuide.pdf> - Donal
K. Fellows._

# Introduction

This is a manual for people who are developing Tcl code for Wish or any other
Tcl application. It describes a set of conventions for writing code and the
associated test scripts. There are three reasons for the conventions. First,
the conventions ensure that certain important things get done; for example,
every procedure must have documentation that describes each of its arguments
and its result, and there must exist test scripts that exercise every line of
code. Second, the conventions guarantee that all of the Tcl and Tk code has a
uniform style. This makes it easier for us to use, read, and maintain each
other's code. Third, the conventions help to avoid some common mistakes by
prohibiting error-prone constructs such as building lists by hand instead of
using the list building procedures.

This document is based heavily on the _Tcl/Tk Engineering Manual_ written by
John Ousterhout. John's engineering manual specified the style of the C code
used in the implementation of Tcl/Tk and many of its extensions. The manual is
very valuable to the development of Tcl/Tk and is an important reason why Tcl
is a relatively easy system to maintain.

Deciding any style standard involves making trade-offs that are usually
subjective. This standard was created in an iterative process involving the
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307

308
309
310

311
312
313
314
315
316
317
318
319

320
321
322
323
324
325
326
and how to write procedure headers. Section 5 desribes the Tcl naming
conventions. Section 6 presents low-level coding conventions, such as how to
indent and where to put curly braces. Section 7 contains a collection of rules
and suggestions for writing comments. Section 8 describes how to write and
maintain test suites. Section 9 contains a few miscellaneous topics, such as
keeping a change log.

~ Executable files

An executable is a file, collection of files, or some other collection of Tcl
code and necessary runtime environment. Often referred to as applications, an
executable is simply what you run to start your program. The format and exact
make up of an executable is platform-specific. At some point, however, a Tcl
''start-up script'' will be evaluated. It is the start-up script that will
bootstrap any Tcl based application.

The role of the start-up script is to load any needed ''packages'', set up any
non-package specific state, and finally start the Tcl application by calling
routines inside a Tcl package. If the start-up script is more than a few lines
it should probably be a package itself.

There are several ways to create executable scripts. Each major platform
usually has a unique way of creating an executable application. Here is a
brief description of how these applications should be created on each
platform:

 1. The most common method for creating executable applications on UNIX
    platforms is the infamous '''#!''' mechanism built into most shells.
    Unfortunately, the most common approach of just giving a path to wish is
    not recommended. Don't do:

|    #! /usr/local/tclsh8.0 -f "$0" "$@"

 >  This method will not work if the file '''tclsh''' is another script that,
    for example, locates and starts the most recent version of Tcl. It also
    requires '''tclsh''' to be in a particular place, which makes the script
    less portable. Instead, the following method should be used which calls
    '''/bin/sh''' which will in turn exec the '''wish''' application.

|    #!/bin/sh
|    # the next line restarts using wish \
|    exec wish8.0 "$0" "$@"

 >  This example will actually locate the '''wish''' application in the user's
    path which can be very useful for developers. The backslash is recognized
    as part of a comment to ''sh'', but in Tcl the backslash continues the
    comment into the next line which keeps the ''exec'' command from executing
    again. However, more stable sites would probably want to include the full
    path instead of just '''wish'''. Note that the version number of the
    '''tclsh''' or '''wish''' interpreter is usually added to the end of the
    program name. This allows you use a specific version of Tcl. In addition,
    many sites include a link of '''wish''' to the latest version currently
    installed. This is useful if you know that your code will work on any
    version of Tcl.

 2. On the Windows platform you only need to end a file with the '''.tcl'''
    extension and the file will be run when the user double clicks on the
    file. This is, of course, assuming you have installed Tcl/Tk.

 >  Alternatively, you may create a '''.bat''' file which explicitly executes
    '''tclsh''' or '''wish''' with an absolute path to your start-up script.
    Please check the Windows documentation for more details about '''.bat'''
    files.

 3. The Macintosh platform doesn't really have a notion of an executable Tcl
    file. One of the reasons for this is that, unlike UNIX or Windows, you can
    only run one instance of an application at a time. So instead of
    callingwish with a specific script to load, we must create a copy of the
    '''wish''' application that is tied to our script.

 >  The easiest way to do this is to use the application ''Drag&Drop Tclets''
    or the ''SpecTcl'' GUI builder which can do this work for you. You can
    also do this by hand by putting the start-up script into a TEXT resource
    and name it ''tclshrc'' - which ensures it gets sourced on start-up. This
    can be done with ''ResEdit'' (a tool provided by Apple) or other tools
    that manipulate resources. Additional scripts can also be placed in TEXT
    resource to make the application completely contained.

~ Packages and namespaces

Tcl applications consist of collections of ''packages''. Each package provides
code to implement a related set of features. For example, Tcl itself is a
package, as is Tk; these packages happen to be implemented in both C and Tcl.
Other packages are implemented completely in Tcl such as the '''http'''
package included in the Tcl distribution. Packages are the units in which code
is developed and distributed: a single package is typically developed by a
single person or group and distributed as a unit. It is possible to combine
many independently-developed packages into a single application; packages
should be designed with this in mind. The notion of ''namespaces'' were
created to help make this easier. Namespaces help to hide private aspects of
packages and avoid name collisions. A package will generally export one public
namespace which will include all state and routines that are associated with
the package. A package should not contain any global variables or global
procedures. Side effects when loading a package should be avoided. This
document will focus on packages written entirely in Tcl. For a discussion of
packages built in C or C and Tcl see the ''Tcl/Tk Engineering Manual''.

~~ Package names

Each package should have a unique ''name''. The name of the package is used to
identify the package. It is also used as the name of the namespace that the
package exports. It is best to have a simple one word name in all lower-case
like '''http'''. Multi-word names are ok as well. Additional words should
just be concatenated with the first word but start with a capital letter like
'''specMenu'''.

Coming up with a unique name for your package requires a collaborative
component. For internal projects this is an easy task and can usually be
decided among the management or principal engineers in your organization. For
packages you wish to publish, however, you should make an effort to make sure
that an existing package isn't already using the same name you are. This can
often be done by checking the comp.lang.tcl newsgroup or the standard Tcl ftp
sites. It is also suggested (but not required) that you register your name on
the NIST Identifier Collaboration Service (NICS). It is located at:
http://pitch.nist.gov/nics

~~ Version numbers

Each package has a two-part version number such as 7.4. The first number (7)
is called the major version number and the second (4) is called the minor
version number. The version number changes with each public release of the
package. If a new release contains only bug fixes, new features, and other
upwardly compatible changes, so that code and scripts that worked with the old
version will also work with the new version, then the minor version number
increments and the major version number stays the same (e.g., from 7.4 to
7.5). If the new release contains substantial incompatibilities, so that
existing code and scripts will have to be modified to run with the new
version, then the major version number increments and the minor version number
resets to zero (e.g., from 7.4 to 8.0).

~~ Package namespaces

As of version 8.0, Tcl supports namespaces to hide the internal structure of a
package. This helps avoid name collisions and provides a simpler way to manage
packages. All packages written for Tcl 8.0 or newer should use namespaces. The
name of the name space should be the same as the package name.

~~ Structure

There are a couple of ways to deploy a package of Tcl commands.

 * A '''pkgIndex.tcl''' file is used to create ''packages'' that can be loaded
   on demand by any Tcl script. Like a '''tclIndex''' file, a package
   specifies a set of Tcl and/or shared libraries that can be loaded when
   needed. A package, however, must be explicitly requested by using the
   '''package require''' command. You can use the '''pkg_mkIndex''' command to
   create a package index file for your use. In most cases, particularly in
   code you distribute to others, it is better to use a package instead of
   the '''tclIndex''' auto-loading mechanism.

 * On the Macintosh platform, shared libraries can be made into self contained
   packages. You simply need to add a TEXT resource with the name of
   '''pkgIndex'''. It will be treated in the exact same fashion as a
   '''pkgIndex.tcl''' file. The '''pkgIndex''' resource should have the same
   format as the '''pkgIndex.tcl''' file.

~ How to organize a code file

Each source code file should either contain an entire application or a set of
related procedures that make up a package or a another type of identifiable
module, such as the implementation of the menus for your application, or a set
of procedures to implement HTTP access. Before writing any code you should
think carefully about what functions are to be provided and divide them into
files in a logical way. The most manageable size for files is usually in the
range of 500-2000 lines. If a file gets much larger than this, it will be hard
to remember everything that the file does. If a file is much shorter than
this, then you may end up with too many files in a directory, which is also
hard to manage.

~~ The file header

The first part of a code file is referred to as the ''header''. It contains
overall information that is relevant throughout the file. It consists of
everything but the definitions of the file's procedures. The header typically
has four parts, as shown below:

|           /   # specMenu.tcl --
|           |   #
|Abstract   |   #       This file implements the Tcl code for creating and
|           |   #       managing the menus in the SpecTcl application.
|           \   #
|           /   # Copyright (c) 1994-1997 Sun Microsystems, Inc.
|           |   #
|Copyright  |   # See the file "license.terms" for information on usage and
|           |   # redistribution of this file, and for a DISCLAIMER OF ALL
|           \   # WARRANTIES.
|               #

|Revision       # SCCS: %Z% %M% %I% %E% %U%
|String         # RCS: Id
|
|           /   package require specTable
|Package    |   package provide specMenu 1.0
|Definition |   namespace eval specMenu {
|           |       namespace export addMenu
|           |       array set menuData {one two three}
|           |       ...
|           \   }

 Abstract: The first few lines give the name of the file and a brief
    description of the overall functions provided by the file, just as in
    header files.

 Copyright notice: The notice protects ownership of the file. The copyright
    shown above is included in the Tcl and Tk sources. More product specific
    packages would probably have the words ''All rights reserved included''
    instead. If more than one entity contributed to the page they should each
    have a distinct copyright line.

 Revision string: The contents of this string are managed automatically by the
    source code control system for the file, such as RCS or SCCS (both are
    shown in the example). It identifies the file's current revision, date of
    last modification, and so on.

 Package definition: Also any '''require''' statements for other packages that
    this package depends on should be the first code in the file. Any global
    variables that are managed by this file should be declared at the top of
    the page. The name space definition should be next and the export list
    should be the first item in the namespace definition.

Please structure your header pages in exactly the order given above and follow
the syntax of the example as closely as possible. The file '''fileHead.tcl'''
[[''not available'']] provides a template for a header page.

~~ Multi-file packages

Some packages may be too large to fit into one file. You may want to consider
breaking the package into multiple independent packages. However, when that is
not an option you need to make one of the files the ''primary'' file. The
primary file will include the complete export list and the definitions of all
exported variables and procedures. The secondary files should only contain
supporting routines to the primary file. It is important to construct your
package in this manner or utilities like '''pkg_mkIndex''' will not work
correctly. Finally, the header to the various files should make it clear which
file is the primary file and which are supporting files.

~~ Procedure headers

After the header you will have one or more procedures. Each procedure will
begin with a ''procedure header'' that gives overall documentation for the
procedure, followed by the declaration and body for the procedure. See below
for an example.

|# tcl::HistRedo --
|#

|#       Fetch the previous or specified event, execute it, and then
|#       replace the current history item with that event.
|#

|# Arguments:
|#       event   (optional) index of history item to redo.  Defaults
|#                to -1, which means the previous event.
|# Results:
|#        The result is that of the command being redone.  Also replaces
|#        the current history list item with the one being redone.
|proc tcl::HistRedo {{event -1}} {
|    ...
|}


The header should contain everything that a caller of the procedure needs to
know in order to use the procedure, and nothing else. It consists of three
parts:

 Abstract: The first lines in the header give the procedure's name, followed
    by a brief description of what the procedure does. This should not be a







|





|


|










|



|

|

|

|

|
|
|

|

|
|

|
|

|



|



|
|
|






|

|
|

|
|



|

|


|




|






|

|

|


|

|







|
|
|

|

|
|




|
|


|

|






|



|
|


|


|



|
|
|

|












|

|




|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|







|




|
|


|






|
|

|



|



|



|


|



|
<
>
|
|
<
>
|
|
|
|
|
|
|
|
<
>







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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248

249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305

306
307
308

309
310
311
312
313
314
315
316
317

318
319
320
321
322
323
324
325
and how to write procedure headers. Section 5 desribes the Tcl naming
conventions. Section 6 presents low-level coding conventions, such as how to
indent and where to put curly braces. Section 7 contains a collection of rules
and suggestions for writing comments. Section 8 describes how to write and
maintain test suites. Section 9 contains a few miscellaneous topics, such as
keeping a change log.

# Executable files

An executable is a file, collection of files, or some other collection of Tcl
code and necessary runtime environment. Often referred to as applications, an
executable is simply what you run to start your program. The format and exact
make up of an executable is platform-specific. At some point, however, a Tcl
_start-up script_ will be evaluated. It is the start-up script that will
bootstrap any Tcl based application.

The role of the start-up script is to load any needed _packages_, set up any
non-package specific state, and finally start the Tcl application by calling
routines inside a Tcl package. If the start-up script is more than a few lines
it should probably be a package itself.

There are several ways to create executable scripts. Each major platform
usually has a unique way of creating an executable application. Here is a
brief description of how these applications should be created on each
platform:

 1. The most common method for creating executable applications on UNIX
    platforms is the infamous **\#!** mechanism built into most shells.
    Unfortunately, the most common approach of just giving a path to wish is
    not recommended. Don't do:

		    #! /usr/local/tclsh8.0 -f "$0" "$@"

	 >  This method will not work if the file **tclsh** is another script that,
    for example, locates and starts the most recent version of Tcl. It also
    requires **tclsh** to be in a particular place, which makes the script
    less portable. Instead, the following method should be used which calls
    **/bin/sh** which will in turn exec the **wish** application.

		    #!/bin/sh
		    # the next line restarts using wish \
		    exec wish8.0 "$0" "$@"

	 >  This example will actually locate the **wish** application in the user's
    path which can be very useful for developers. The backslash is recognized
    as part of a comment to _sh_, but in Tcl the backslash continues the
    comment into the next line which keeps the _exec_ command from executing
    again. However, more stable sites would probably want to include the full
    path instead of just **wish**. Note that the version number of the
    **tclsh** or **wish** interpreter is usually added to the end of the
    program name. This allows you use a specific version of Tcl. In addition,
    many sites include a link of **wish** to the latest version currently
    installed. This is useful if you know that your code will work on any
    version of Tcl.

 2. On the Windows platform you only need to end a file with the **.tcl**
    extension and the file will be run when the user double clicks on the
    file. This is, of course, assuming you have installed Tcl/Tk.

	 >  Alternatively, you may create a **.bat** file which explicitly executes
    **tclsh** or **wish** with an absolute path to your start-up script.
    Please check the Windows documentation for more details about **.bat**
    files.

 3. The Macintosh platform doesn't really have a notion of an executable Tcl
    file. One of the reasons for this is that, unlike UNIX or Windows, you can
    only run one instance of an application at a time. So instead of
    callingwish with a specific script to load, we must create a copy of the
    **wish** application that is tied to our script.

	 >  The easiest way to do this is to use the application _Drag&Drop Tclets_
    or the _SpecTcl_ GUI builder which can do this work for you. You can
    also do this by hand by putting the start-up script into a TEXT resource
    and name it _tclshrc_ - which ensures it gets sourced on start-up. This
    can be done with _ResEdit_ \(a tool provided by Apple\) or other tools
    that manipulate resources. Additional scripts can also be placed in TEXT
    resource to make the application completely contained.

# Packages and namespaces

Tcl applications consist of collections of _packages_. Each package provides
code to implement a related set of features. For example, Tcl itself is a
package, as is Tk; these packages happen to be implemented in both C and Tcl.
Other packages are implemented completely in Tcl such as the **http**
package included in the Tcl distribution. Packages are the units in which code
is developed and distributed: a single package is typically developed by a
single person or group and distributed as a unit. It is possible to combine
many independently-developed packages into a single application; packages
should be designed with this in mind. The notion of _namespaces_ were
created to help make this easier. Namespaces help to hide private aspects of
packages and avoid name collisions. A package will generally export one public
namespace which will include all state and routines that are associated with
the package. A package should not contain any global variables or global
procedures. Side effects when loading a package should be avoided. This
document will focus on packages written entirely in Tcl. For a discussion of
packages built in C or C and Tcl see the _Tcl/Tk Engineering Manual_.

## Package names

Each package should have a unique _name_. The name of the package is used to
identify the package. It is also used as the name of the namespace that the
package exports. It is best to have a simple one word name in all lower-case
like **http**. Multi-word names are ok as well. Additional words should
just be concatenated with the first word but start with a capital letter like
**specMenu**.

Coming up with a unique name for your package requires a collaborative
component. For internal projects this is an easy task and can usually be
decided among the management or principal engineers in your organization. For
packages you wish to publish, however, you should make an effort to make sure
that an existing package isn't already using the same name you are. This can
often be done by checking the comp.lang.tcl newsgroup or the standard Tcl ftp
sites. It is also suggested \(but not required\) that you register your name on
the NIST Identifier Collaboration Service \(NICS\). It is located at:
<http://pitch.nist.gov/nics>

## Version numbers

Each package has a two-part version number such as 7.4. The first number \(7\)
is called the major version number and the second \(4\) is called the minor
version number. The version number changes with each public release of the
package. If a new release contains only bug fixes, new features, and other
upwardly compatible changes, so that code and scripts that worked with the old
version will also work with the new version, then the minor version number
increments and the major version number stays the same \(e.g., from 7.4 to
7.5\). If the new release contains substantial incompatibilities, so that
existing code and scripts will have to be modified to run with the new
version, then the major version number increments and the minor version number
resets to zero \(e.g., from 7.4 to 8.0\).

## Package namespaces

As of version 8.0, Tcl supports namespaces to hide the internal structure of a
package. This helps avoid name collisions and provides a simpler way to manage
packages. All packages written for Tcl 8.0 or newer should use namespaces. The
name of the name space should be the same as the package name.

## Structure

There are a couple of ways to deploy a package of Tcl commands.

 * A **pkgIndex.tcl** file is used to create _packages_ that can be loaded
   on demand by any Tcl script. Like a **tclIndex** file, a package
   specifies a set of Tcl and/or shared libraries that can be loaded when
   needed. A package, however, must be explicitly requested by using the
   **package require** command. You can use the **pkg\_mkIndex** command to
   create a package index file for your use. In most cases, particularly in
   code you distribute to others, it is better to use a package instead of
   the **tclIndex** auto-loading mechanism.

 * On the Macintosh platform, shared libraries can be made into self contained
   packages. You simply need to add a TEXT resource with the name of
   **pkgIndex**. It will be treated in the exact same fashion as a
   **pkgIndex.tcl** file. The **pkgIndex** resource should have the same
   format as the **pkgIndex.tcl** file.

# How to organize a code file

Each source code file should either contain an entire application or a set of
related procedures that make up a package or a another type of identifiable
module, such as the implementation of the menus for your application, or a set
of procedures to implement HTTP access. Before writing any code you should
think carefully about what functions are to be provided and divide them into
files in a logical way. The most manageable size for files is usually in the
range of 500-2000 lines. If a file gets much larger than this, it will be hard
to remember everything that the file does. If a file is much shorter than
this, then you may end up with too many files in a directory, which is also
hard to manage.

## The file header

The first part of a code file is referred to as the _header_. It contains
overall information that is relevant throughout the file. It consists of
everything but the definitions of the file's procedures. The header typically
has four parts, as shown below:

	           /   # specMenu.tcl --
	           |   #
	Abstract   |   #       This file implements the Tcl code for creating and
	           |   #       managing the menus in the SpecTcl application.
	           \   #
	           /   # Copyright (c) 1994-1997 Sun Microsystems, Inc.
	           |   #
	Copyright  |   # See the file "license.terms" for information on usage and
	           |   # redistribution of this file, and for a DISCLAIMER OF ALL
	           \   # WARRANTIES.

	               #
	Revision       # SCCS: %Z% %M% %I% %E% %U%
	String         # RCS: Id
	
	           /   package require specTable
	Package    |   package provide specMenu 1.0
	Definition |   namespace eval specMenu {
	           |       namespace export addMenu
	           |       array set menuData {one two three}
	           |       ...
	           \   }

 Abstract: The first few lines give the name of the file and a brief
    description of the overall functions provided by the file, just as in
    header files.

 Copyright notice: The notice protects ownership of the file. The copyright
    shown above is included in the Tcl and Tk sources. More product specific
    packages would probably have the words _All rights reserved included_
    instead. If more than one entity contributed to the page they should each
    have a distinct copyright line.

 Revision string: The contents of this string are managed automatically by the
    source code control system for the file, such as RCS or SCCS \(both are
    shown in the example\). It identifies the file's current revision, date of
    last modification, and so on.

 Package definition: Also any **require** statements for other packages that
    this package depends on should be the first code in the file. Any global
    variables that are managed by this file should be declared at the top of
    the page. The name space definition should be next and the export list
    should be the first item in the namespace definition.

Please structure your header pages in exactly the order given above and follow
the syntax of the example as closely as possible. The file **fileHead.tcl**
[_not available_] provides a template for a header page.

## Multi-file packages

Some packages may be too large to fit into one file. You may want to consider
breaking the package into multiple independent packages. However, when that is
not an option you need to make one of the files the _primary_ file. The
primary file will include the complete export list and the definitions of all
exported variables and procedures. The secondary files should only contain
supporting routines to the primary file. It is important to construct your
package in this manner or utilities like **pkg\_mkIndex** will not work
correctly. Finally, the header to the various files should make it clear which
file is the primary file and which are supporting files.

## Procedure headers

After the header you will have one or more procedures. Each procedure will
begin with a _procedure header_ that gives overall documentation for the
procedure, followed by the declaration and body for the procedure. See below
for an example.

	# tcl::HistRedo --

	#
	#       Fetch the previous or specified event, execute it, and then
	#       replace the current history item with that event.

	#
	# Arguments:
	#       event   (optional) index of history item to redo.  Defaults
	#                to -1, which means the previous event.
	# Results:
	#        The result is that of the command being redone.  Also replaces
	#        the current history list item with the one being redone.
	proc tcl::HistRedo {{event -1}} {
	    ...

	}

The header should contain everything that a caller of the procedure needs to
know in order to use the procedure, and nothing else. It consists of three
parts:

 Abstract: The first lines in the header give the procedure's name, followed
    by a brief description of what the procedure does. This should not be a
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465

466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481

482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518

519
520
521
522
523
524
525
526
527
528
529


530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569

570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607


608
609
610
611
612
613
614
615
616
617


618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634

635
636
637

638
639
640
641
642


643
644
645
646
647
648
649
650
651
652
653
654
655
656
657

658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725

726
727
728
729
730
731
732
733

734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014

    comment should describe the expected type and describe it's function.
    Optional arguments should be pointed out and the default behavior of an
    unspecified argument should be mentioned. Comments for all of the
    arguments should line up on the same tab stop.

 Results: The last part of the header describes the value returned by the
    procedure. The type and the intended use of the result should be
    described. This section should also mention any ''side effects'' that are
    worth noting.

The file '''tclProcHead''' [[''not available'']] contains a template for a
procedure header which should be used as a base for all new Tcl commands.
Follow the syntax of the above example exactly (same indentation, double-dash
after the procedure name, etc.).

~~ Procedure declarations

The procedure declaration should also follow exactly the syntax in the example
above. Note that the procedure is defined outside the namespace command that
defines the export list and namespace globals. The first line gives the
'''proc''' keyword, the procedure name, and an argument list. If there are
many arguments, they may spill onto additional lines (see Sections 6.1 and 6.3
for information about indentation).

~~ Parameter order

Procedure parameters may be divided into three categories. ''In'' parameters
only pass information into the procedure (either directly or by pointing to
information that the procedure reads). ''Out'' parameters point to things in
the caller's memory that the procedure modifies such as the name of a variable
the procedure will modify. ''In-out'' parameters do both. Below is a set of
rules for deciding on the order of parameters to a procedure:

 1. Parameters should normally appear in the order in, in/out, out, except
    where overridden by the rules below.

 2. If an argument is actually a sub-command for the command than it should be
    the first argument of the command. For example:

|   proc graph::tree {subCmd args} {
|       switch $subCmd {
|           add {
|               eval add_node $args
|           }

|           draw {...

 3. If there is a group of procedures, all of which operate on an argument of
    a particular type, such as a file path or widget path, the argument should
    be the first argument to each of the procedures (or after the sub-command
    argument).

~~ Procedure bodies

The body of a procedure follows the declaration. See Section 6 for the coding
conventions that govern procedure bodies. The curly braces enclosing the body
should be on different lines, as shown in the examples above, even if the body
of the procedure is empty.

~ Naming conventions

Choosing names is one of the most important aspects of programming. Good names
clarify the function of a program and reduce the need for other documentation.
Poor names result in ambiguity, confusion, and error. This section gives some
general principles to follow when choosing names and lists specific rules for
name syntax, such as capitalization.

~~ General considerations

The ideal variable name is one that instantly conveys as much information as
possible about the purpose of the variable it refers to. When choosing names,
play devil's advocate with yourself to see if there are ways that a name might
be misinterpreted or confused. Here are some things to consider:

 1. Are you consistent? Use the same name to refer to the same thing
    everywhere. For example, within the code for handling standard bindings in
    Tk widgets, a standard name '''w''' is always used to refer to the window
    associated with the current event.

 2. If someone sees the name out of context, will they realize what it stands
    for, or could they confuse it with something else? For example, the
    procedure name '''buildStructure''' could get confused with some other
    part of the system. A name like '''buildGraphNode''' both describes what
    part of the system it belongs to and what it is probably used for.

 3. Could this name be confused with some other name? For example, it's
    probably a mistake to have two variables '''str''' and '''string''' in the
    same procedure: it will be hard for anyone to remember which is which.
    Instead, change the names to reflect their functions. For example, if the
    strings are used as source and destination for a copy operation, name
    them '''src''' and '''dst'''.

 4. Is the name so generic that it doesn't convey any information? The
    variable '''str''' from the previous paragraph is an example of this;
    changing its name to '''src''' makes the name less generic and hence
    conveys more information.

~~ Basic syntax rules

Below are some specific rules governing the syntax of names. Please follow the
rules exactly, since they make it possible to determine certain properties of
a variable just from its name.

 1. Exported names for both procedures and variables always start with a
    ''lower''-case letter. Procedures and variables that are meant only for
    use with in the current package or namespace should start with an
    ''upper''-case letter. We chose lower-case for the exported symbols
    because it is possible they may be commonly used from the command line and
    they should be easy to write. For example:

|   # CountNum is a private variable
|   set CountNum 0
|   # The function addWindow is public
|   proc addWindow {} {...
|   # newWindow is a public interface in the spectcl namespace
|   proc spectcl::newWindow {} {...

 2. In multi-word names, the first letter of each trailing word is
    capitalized. Do not use underscores or dashes as separators between the
    words of a name.

|   set numWindows 0

 3. Any variable whose value refers to another variable has a name that ends
    in '''Name'''. Furthermore, the name should also indicate what type of
    variable the name is referring to. These names are often used in arguments
    to procedures that are taking a name of a variable.

|   proc foo::Bar {arrayName} {
|       upvar 1 $arrayName array
|       ...
|   }


 4. Variables that hold Tcl code that will be '''eval'''ed should have names
    ending in '''Script'''.

|   proc log::eval {logScript} {
|       if {$Log::logOn} {
|           set result [catch {eval $logScript} msg]
|           ...

 5. Variables that hold a partial Tcl command that must have additional
    arguments appended before being a valid script should have names ending in
    '''Cmd'''.

|   foreach scrollCmd $listScrollCmds {
|       eval $scrollCmd $args
|   }


~ Low-level coding conventions

This section describes several low-level syntactic rules for writing Tcl code.
These rules help to ensure that all of the Tcl code looks the same, and they
prohibit a few confusing coding constructs.

~~ Indents are 4 spaces

Each level of indentation should be four spaces. There are ways to set 4-space
indents in all of the most common editors. Be sure that your editor really
uses four spaces for the indent, rather than just displaying tabs as four
spaces wide; if you use the latter approach then the indents will appear eight
spaces wide in other editors.

~~ Code comments occupy full lines

Comments that document code should occupy full lines, rather than being tacked
onto the ends of lines containing code. The reason for this is that
side-by-side comments are hard to see, particularly if neighboring statements
are long enough to overlap the side-by-side comments. Also it is easy to place
comments in a place that could cause errors. Comments must have exactly the
structure shown in the example below, with a blank line above and below the
comment. The leading blank line can be omitted if the comment is at the
beginning of a block, as is the case in the second comment in the example
below. Each comment should be indented to the same level as the surrounding
code. Use proper English in comments: write complete sentences, capitalize the
first word of each sentence, and so on.

|# If we are running on the Macintosh platform then we can
|# assume that the sources are located in the resource fork
|# of our application, and we do not need to search for them.
|# Note that there is a blank line below it to separate it
|# more strongly from the code.
|
|if {$tcl_platform(platform) == "macintosh"} {
|    return
|}

|
|foreach dir $dirList {
|    # If the source succeds then we are done.
|    # Note there is no blank line above the comment;
|    # the indentation change is visible enough.
|
|    if {![catch {source [file join $dir file.tcl]}]} {
|        break
|    }
|}



~~ Continuation lines are indented 8 spaces

You should use continuation lines to make sure that no single line exceeds 80
characters in length. Continuation lines should be indented 8 spaces so that
they won't be confused with an immediately-following nested block. Pick clean
places to break your lines for continuation, so that the continuation doesn't
obscure the structure of the statement. For example, if a procedure call
requires continuation lines, try to avoid situations where a single argument
spans multiple lines. If the test for an '''if''' or '''while''' command spans
lines, try to make each line have the same nesting level of parentheses and/or
brackets if possible. I try to start each continuation line with an operator
such as '''*''', '''&&''', or '''||'''; this makes it clear that the line is a
continuation, since a new statement would never start with such an operator.

~~ Only one command per line

You should only have one Tcl command per line on the page. Do not use the
semi-colon character to place multiple commands on the same line. This makes
the code easier to read and helps with debugging.

~~ Curly braces: { goes at the end of a line

Open curly braces can not appear on lines by themselves in Tcl. Instead, they
should be placed at the end of the preceding line. Close curly braces are
indented to the same level as the outer code, i.e., four spaces less than the
statements they enclose. However, you shouldalways use curly braces rather
than some other list generating mechanism that will work in the Tcl language.
This will help make code more readable, will avoid unwanted side effects, and
in many cases will generate faster code with the Tcl compiler.

Control structures should always use curly braces, even if there is only one
statement in the block. Thus you shouldn't write code like

|   if {$tcl_platform(platform) == "unix"} return

but rather

|   if {$tcl_platform(platform) == "unix"} {
|       return
|   }


This approach makes code less dense, but it avoids potential mistakes like
unwanted Tcl substitutions. It also makes it easier to set breakpoints in a
debugger, since it guarantees that each statement is on a separate line and
can be named individually.

~~ Parenthesize expressions

Use parentheses around each subexpression in an expression to make it
absolutely clear what is the evaluation order of the expression (a reader of
your code should not need to remember Tcl's precedence rules). For example,
don't type

|   if {$x > 22 && $y <= 47} ...

Instead, type this:

|   if {($x > 22) && ($y <= 47)} ...

~~ Always use the return statement

You should always explicitly use the '''return''' statement to return values
from a Tcl procedure. By default Tcl will return the value of the last Tcl
statement executed in a Tcl procedure as the return value of the procedure
which often leads to confusion as to where the result is coming from. In
addition, you should use a '''return''' statement with no argument for
procedures whose results are ignored. Supplying this return will actually
speed up your application with the new Tcl compiler. For example, don't write
code like this:

|   proc foo {x y} {
|       if {$x < 0} {
|           incr x
|       } else {
|           expr $x + $y
|       }
|   }



But rather, type this:

|   proc foo {x y} {
|       if {$x < 0} {
|           return [incr x]
|       } else {
|           return [expr $x + $y]
|       }
|   }



For Tcl procedures that have no return value a single '''return''' statement
with no arguments is placed at the end of the procedure.

~~ Switch statements

The '''switch''' statement should be formatted as below. Always use the
'''--''' option to avoid having the string be confused with an option. This
can happen when the string is user generated. Comments can be added on the
same line as the pattern to comment the pattern case. The comments for each
case should line up on the same tab stop and must be within the braces. Note
that this is an exception to the standard commenting conventions.

|   switch -regexp -- $string {
|       plus -
|       add {       # Do add task
|           ...
|       }

|       subtract {  # Do subtract case
|           ...
|       }

|       default {
|           ...
|       }
|   }



~~ If statements

Never use the '''then''' word of an '''if''' statement. It is syntactic sugar
that really isn't that useful. However, the '''else''' word should always be
used as it does impart some semantic information and it is more like the C
language. Here is an example:

|   if {$x < 0} {
|       ...
|   } elseif {$x == 0} {
|       ...
|   } else {
|       ...
|   }


~ Documenting code

The purpose of documentation is to save time and reduce errors. Documentation
is typically used for two purposes. First, people will read the documentation
to find out how to use your code. For example, they will read procedure
headers to learn how to call the procedures. Ideally, people should have to
learn as little as possible about your code in order to use it correctly.
Second, people will read the documentation to find out how your code works
internally, so they can fix bugs or add new features; again, good
documentation will allow them to make their fixes or enhancements while
learning the minimum possible about your code. More documentation isn't
necessarily better: wading through pages of documentation may not be any
easier than deciphering the code. Try to pick out the most important things
that will help people to understand your code and focus on these in your
documentation.

~~ Document things with wide impact

The most important things to document are those that affect many different
pieces of a program. Thus it is essential that every procedure interface,
every structure declaration, and every global variable be documented clearly.
If you haven't documented one of these things it will be necessary to look at
all the uses of the thing to figure out how it's supposed to work; this will
be time-consuming and error-prone.

On the other hand, things with only local impact may not need much
documentation. For example, in short procedures I don't usually have comments
explaining the local variables. If the overall function of the procedure has
been explained, and if there isn't much code in the procedure, and if the
variables have meaningful names, then it will be easy to figure out how they
are used. On the other hand, for long procedures with many variables I usually
document the key variables. Similarly, when I write short procedures I don't
usually have any comments in the procedure's code: the procedure header
provides enough information to figure out what is going on. For long
procedures I place a comment block before each major piece of the procedure to
clarify the overall flow through the procedure.

~~ Don't just repeat what's in the code

The most common mistake I see in documentation (besides it not being there at
all) is that it repeats what is already obvious from the code, such as this
trivial (but exasperatingly common) example:

|   # Increment i.
|
|   incr i

Documentation should provide higher-level information about the overall
function of the code, helping readers to understand what a complex collection
of statements really means. For example, the comment

|   # Probe into the array to see if the symbol exists.

is likely to be much more helpful than

|   # Loop through every array index, get the third value of the
|   # list in the content to determine if it has the symbol we are
|   # looking for. Set the result to the symbol if we find it.

Everything in this second comment is probably obvious from the code that
follows it.

Another thing to consider in your comments is word choice. Use different words
in the comments than the words that appear in variable or procedure names. For
example, the comment

|   # SwapPanels --
|   #

|   # Swap the panels.
|   # ...

is not a very useful comment. Everything in the comment is already obvious
from the procedure's name. Here is a much more useful comment:

|   # SwapPanels --
|   #

|   # Unmap the current UI panel from the parent frame and replace
|   # it with the newly specified frame. Make sure that the new
|   # panel fits into the old frame and resize if needed.
|   # ...

This comment tells ''why'' you might want to use the procedure, in addition to
''what'' it does, which makes the comment much more useful.

~~ Document each thing in exactly one place

Systems evolve over time. If something is documented in several places, it
will be hard to keep the documentation up to date as the system changes.
Instead, try to document each major design decision in exactly one place, as
near as possible to the code that implements the design decision. The
principal documentation for each procedure goes in the procedure header.
There's no need to repeat this information again in the body of the procedure
(but you might have additional comments in the procedure body to fill in
details not described in the procedure header). If a library procedure is
documented thoroughly in a manual entry, then I may make the header for the
procedure very terse, simply referring to the manual entry.

The other side of this coin is that every major design decision needs to be
documented ''at least'' once. If a design decision is used in many places, it
may be hard to pick a central place to document it. Try to find a data
structure or key procedure where you can place the main body of comments; then
reference this body in the other places where the decision is used. If all
else fails, add a block of comments to the header page of one of the files
implementing the decision.

~~ Write clean code

The best way to produce a well-documented system is to write clean and simple
code. This way there won't be much to document. If code is clean, it means
that there are a few simple ideas that explain its operation; all you have to
do is to document those key ideas. When writing code, ask yourself if there is
a simple concept behind the code. If not, perhaps you should rethink the code.
If it takes a lot of documentation to explain a piece of code, it is a sign
that you haven't found a clean solution to the problem.

~~ Document as you go

It is extremely important to write the documentation as you write the code.
It's very tempting to put off the documentation until the end; after all, the
code will change, so why waste time writing documentation now when you'll have
to change it later? The problem is that the end never comes - there is always
more code to write. Also, the more undocumented code that you accumulate, the
harder it is to work up the energy to document it. So, you just write more
undocumented code. I've seen many people start a project fully intending to go
back at the end and write all the documentation, but I've never seen anyone
actually do it.

If you do the documentation as you go, it won't add much to your coding time
and you won't have to worry about doing it later. Also, the best time to
document code is when the key ideas are fresh in your mind, which is when
you're first writing the code. When I write new code, I write all of the
header comments for a group of procedures before I fill in any of the bodies
of the procedures. This way I can think about the overall structure and how
the pieces fit together before getting bogged down in the details of
individual procedures.

~~ Document tricky situations

If code is non-obvious, meaning that its structure and correctness depend on
information that won't be obvious to someone reading it for the first time, be
sure to document the non-obvious information. One good indicator of a tricky
situation is a bug. If you discover a subtle property of your program while
fixing a bug, be sure to add a comment explaining the problem and its
solution. Of course, it's even better if you can fix the bug in a way that
eliminates the subtle behavior, but this isn't always possible.

~ Testing

One of the environments where Tcl works best is for testing. While Tcl has
traditionally been used for testing C code it is equally as good at testing
other Tcl code. Whenever you write new code you should write Tcl test scripts
to go with that code and save the tests in files so that they can be re-run
later. Writing test scripts isn't as tedious as it may sound. If you're
developing your code carefully you're already doing a lot of testing; all you
need to do is type your test cases into a script file where they can be
reused, rather than typing them interactively where they vanish after they're
run.

~~ Basics

Tests should be organized into script files, where each file contains a
collection of related tests. Individual tests should be based on the procedure
'''test''', just like in the Tcl and Tk test suites. Here are two examples:

|   test expr-3.1 {floating-point operators} {
|       expr 2.3*.6
|   } 1.38
|   test expr-3.2 {floating-point operators} {unixOnly} {
|       list [catch {expr 2.3/0} msg] $msg
|   } {1 {divide by zero}}

'''test''' is a procedure defined in a script file named '''defs''', which is
'''source'''d by each test file. '''test''' takes four or five arguments: a
test identifier, a string describing the test, an optional argument describing
the conditions under which this test should run, a test script, and the
expected result of the script. '''test''' evaluates the script and checks to
be sure that it produces the expected result. If not, it prints a message like
the following:

|   ==== expr-3.1 floating-point operators
|   ==== Contents of test case:
|       expr 2.3*.6
|   ==== Result was:
|   1.39
|   ---- Result should have been:
|   1.38
|   ---- expr-3.1 FAILED

To run a set of tests, you start up the application and '''source''' a test
file. If all goes well no messages appear; if errors are detected, a message
is printed for each error.

The test identifier, such as '''expr-3.1''', is printed when errors occur. It
can be used to search a test script to locate the source for a failed test.
The first part of the identifier, such as '''expr''', should be the same as
the name of the test file, except that the test file should have a '''.test'''
extension, such as '''expr.test'''. The two numbers allow you to divide your
tests into groups. The tests in a particular group (e.g., all the
'''expr-3.'''''n'' tests) relate to a single sub-feature, such as a single
procedure. The tests should appear in the test file in the same order as their
numbers.

The test name, such as '''floating-point operators''', is printed when errors
occur. It provides human-readable information about the general nature of the
test.

Before writing tests I suggest that you look over some of the test files for
Tcl and Tk to see how they are structured. You may also want to look at the
'''README''' files in the Tcl and Tk test directories to learn about
additional features that provide more verbose output or restrict the set of
tests that are run.

~~ Organizing tests

Organize your tests to match the code being tested. The best way to do this is
to have one test file for each source code file, with the name of the test
file derived from the name of the source file in an obvious way (e.g.
'''http.test''' contains tests for the code in '''http.tcl'''). Within the
test file, have one group of tests for each procedure (for example, all the
'''http-3.'''''n'' tests in '''http.test''' are for the procedure
'''http::geturl'''). The order of the tests within a group should be the same
as the order of the code within the procedure. This approach makes it easy to
find the tests for a particular piece of code and add new tests as the code
changes.

The Tcl test suite was written a long time ago and uses a different style
where there is one file for each Tcl command or group of related commands, and
the tests are grouped within the file by sub-command or features. In this
approach the relationship between tests and particular pieces of code is much
less obvious, so it is harder to maintain the tests as the code evolves. I
don't recommend using this approach for new tests.

~~ Coverage

When writing tests, you should attempt to exercise every line of source code
at least once. There will be occasionally be code that you can't exercise,
such as code that exits the application, but situations like this are rare.
You may find it hard to exercise some pieces of code because existing Tcl
commands don't provide fine enough control to generate all the possible
execution paths. In situations like this, write one or more new Tcl commands
just for testing purposes. It's much better to test a facility directly then
to rely on some side effect for testing that may change over time. Use a
similar approach in your own code, where you have an extra file with
additional commands for testing.

It's not sufficient just to make sure each line of code is executed by your
tests. In addition, your tests must discriminate between code that executes
correctly and code that isn't correct. For example, write tests to make sure
that the '''then''' and '''else''' branches of each '''if''' statement are
taken under the correct conditions. For a loop, run different tests to make
the loop execute zero times, one time, and two or more times. If a piece of
code removes an element from a list, try cases where the element to be removed
is the first element, last element, only element, and neither first element
nor last. Try to find all the places where different pieces of code interact
in unusual ways, and exercise the different possible interactions.

~~ Fixing bugs

Whenever you find a bug in your code it means that the test suite wasn't
complete. As part of fixing the bug, you should add new tests that detect the
presence of the bug. I recommend writing the tests after you've located the
bug but ''before'' you fix it. That way you can verify that the bug happens
before you implement the fix and the bug doesn't happen afterwards, so you'll
know you've really fixed something. Use bugs to refine your testing approach:
think about what you might be able to do differently when you write tests in
the future to keep bugs like this one from going undetected.

~~ Tricky features

I also use tests as a way of illustrating the need for tricky code. If a piece
of code has an unusual structure, and particularly if the code is hard to
explain, I try to write additional tests that will fail if the code is
implemented in the obvious manner instead of using the tricky approach. This
way, if someone comes along later, doesn't understand the documentation for
the code, decides the complex structure is unnecessary, and changes the code
back to the simple (but incorrect) form, the test will fail and the person
will be able to use the test to understand why the code needs to be the way it
is. Illustrative tests are not a substitute for good documentation, but they
provide a useful addition.

~~ Test independence

Try to make tests independent of each other, so that each test can be
understood in isolation. For example, one test shouldn't depend on commands
executed in a previous test. This is important because the test suite allows
tests to be run selectively: if the tests depend on each other, then false
errors will be reported when someone runs a few of the tests without the
others.

For convenience, you may execute a few statements in the test file to set up a
test configuration and then run several tests based on that configuration. If
you do this, put the setup code outside the calls to thetest procedure so it
will always run even if the individual tests aren't run. I suggest keeping a
very simple structure consisting of setup followed by a group of tests. Don't
perform some setup, run a few tests, modify the setup slightly, run a few more
tests, modify the setup again, and so on. If you do this, it will be hard for
people to figure out what the setup is at any given point and when they add
tests later they are likely to break the setup.

~ Miscellaneous

~~ Porting issues

Writing portable scripts in Tcl is actually quite easy as Tcl itself is quite
portable. However, issues do arise that may require writing platform specific
code. To conditionalize your code in this manner you should use the
'''tcl_platform''' array to determine platform specific differences. You
should avoid the use of theenv variable unless you have already determined the
platform you are running on via the '''tcl_platform''' array.

As Tcl/Tk has become more cross platform we have added commands that aid in
making your code more portable. The most common porting mistakes result from
assumptions about file names and locations. To avoid such mistakes always use
the '''file join''' command and list commands so that you will handle
different file separation characters or spaces in file names. In Tk, you
should always use provided high level dialog boxes instead or creating your
own. The '''font''' and '''menu''' commands has also be revamped to make
writing cross-platform code easier.

~~ Changes files

Each package should contain a file namedchanges that keeps a log of all
significant changes made to the package. The '''changes''' file provides a way
for users to find out what's new in each new release, what bugs have been
fixed, and what compatibility problems might be intro- duced by the new
release. The '''changes''' file should be in chronological order. Just add
short blurbs to it each time you make a change. Here is a sample from the Tk
'''changes''' file:

|   5/19/94 (bug fix) Canvases didn't generate proper Postscript for
|   stippled text. (RJ)
|
|   5/20/94 (new feature) Added "bell" command to ring the display's
|   bell. (JO)
|
|   5/26/94 (feature removed) Removed support for "fill" justify mode
|   from Tk_GetJustify and from the TK_CONFIG_JUSTIFY configuration
|   option.  None of the built-in widgets ever supported this mode
|   anyway. (SS)
|   *** POTENTIAL INCOMPATIBILITY ***

The entries in the '''changes''' file can be relatively terse; once someone
finds a change that is relevant, they can always go to the manual entries or
code to find out more about it. Be sure to highlight changes that cause
compatibility problems, so people can scan the '''changes''' file quickly to
locate the incompatibilities. Also be sure to add your initials to the entry
so that people scanning the log will know who made a particular change.

''(The Tcl and Tk core additionally uses a ChangeLog file that has a much
higher detail within it. This has the advantage of having more tooling
support, but tends to be so verbose that the shorter summaries in the changes
file are still written up by the core maintainers before each release.)''

~ Copyright

The original version of this document is copyright (C) 1997 Sun Microsystems,
Inc. Revisions to reflect current community best-practice are public domain.








|


|

|
|

|




|
|
|

|

|
|
|

|








|
|
|
|
<
>
|



|
|

|






|







|








|




|
|



|



|


|
|


|






|

|



|
|
|
|
|
|





|


|



|
|
|
<
|
>
|
|

|
|
|
|



|

|
|
<
|
>
|





|







|













|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
<
<
|
>
>
|







|


|


|





|












|



|
|
<
>






|


|
|


|



|

|

|



|




|
|
|
|
|
<
<
|
>
>


|
|
|
|
|
<
<
|
>
>
|


|

|
|





|
|
|
|
<
>
|
|
<
>
|
|
<
<
|
>
>
|

|
|



|
|
|
|
|
|
<
|
>
|















|




















|

|
|
|

|
|
|





|



|
|
|








|
<
>
|
|




|
<
>
|
|
|
|

|
|

|







|
|




|






|









|




















|









|











|



|

|
|
|
|
|
|

|
|


|



|
|
|
|
|
|
|
|

|



|

|
|
|
|
|



|





|



|



|
|
|
|
|











|















|







|




|





|







|




|


















|

|




|

|




|


|


|


|


|

|

|
|
|
|
|
|
|
|
|
|
|

|


|



|


|

|

|

>
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462

463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478

479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516

517
518
519
520
521
522
523
524
525


526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567

568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603


604
605
606
607
608
609
610
611
612
613


614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632

633
634
635

636
637
638


639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654

655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723

724
725
726
727
728
729
730
731

732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
    comment should describe the expected type and describe it's function.
    Optional arguments should be pointed out and the default behavior of an
    unspecified argument should be mentioned. Comments for all of the
    arguments should line up on the same tab stop.

 Results: The last part of the header describes the value returned by the
    procedure. The type and the intended use of the result should be
    described. This section should also mention any _side effects_ that are
    worth noting.

The file **tclProcHead** [_not available_] contains a template for a
procedure header which should be used as a base for all new Tcl commands.
Follow the syntax of the above example exactly \(same indentation, double-dash
after the procedure name, etc.\).

## Procedure declarations

The procedure declaration should also follow exactly the syntax in the example
above. Note that the procedure is defined outside the namespace command that
defines the export list and namespace globals. The first line gives the
**proc** keyword, the procedure name, and an argument list. If there are
many arguments, they may spill onto additional lines \(see Sections 6.1 and 6.3
for information about indentation\).

## Parameter order

Procedure parameters may be divided into three categories. _In_ parameters
only pass information into the procedure \(either directly or by pointing to
information that the procedure reads\). _Out_ parameters point to things in
the caller's memory that the procedure modifies such as the name of a variable
the procedure will modify. _In-out_ parameters do both. Below is a set of
rules for deciding on the order of parameters to a procedure:

 1. Parameters should normally appear in the order in, in/out, out, except
    where overridden by the rules below.

 2. If an argument is actually a sub-command for the command than it should be
    the first argument of the command. For example:

		   proc graph::tree {subCmd args} {
		       switch $subCmd {
		           add {
		               eval add_node $args

		           }
		           draw {...

 3. If there is a group of procedures, all of which operate on an argument of
    a particular type, such as a file path or widget path, the argument should
    be the first argument to each of the procedures \(or after the sub-command
    argument\).

## Procedure bodies

The body of a procedure follows the declaration. See Section 6 for the coding
conventions that govern procedure bodies. The curly braces enclosing the body
should be on different lines, as shown in the examples above, even if the body
of the procedure is empty.

# Naming conventions

Choosing names is one of the most important aspects of programming. Good names
clarify the function of a program and reduce the need for other documentation.
Poor names result in ambiguity, confusion, and error. This section gives some
general principles to follow when choosing names and lists specific rules for
name syntax, such as capitalization.

## General considerations

The ideal variable name is one that instantly conveys as much information as
possible about the purpose of the variable it refers to. When choosing names,
play devil's advocate with yourself to see if there are ways that a name might
be misinterpreted or confused. Here are some things to consider:

 1. Are you consistent? Use the same name to refer to the same thing
    everywhere. For example, within the code for handling standard bindings in
    Tk widgets, a standard name **w** is always used to refer to the window
    associated with the current event.

 2. If someone sees the name out of context, will they realize what it stands
    for, or could they confuse it with something else? For example, the
    procedure name **buildStructure** could get confused with some other
    part of the system. A name like **buildGraphNode** both describes what
    part of the system it belongs to and what it is probably used for.

 3. Could this name be confused with some other name? For example, it's
    probably a mistake to have two variables **str** and **string** in the
    same procedure: it will be hard for anyone to remember which is which.
    Instead, change the names to reflect their functions. For example, if the
    strings are used as source and destination for a copy operation, name
    them **src** and **dst**.

 4. Is the name so generic that it doesn't convey any information? The
    variable **str** from the previous paragraph is an example of this;
    changing its name to **src** makes the name less generic and hence
    conveys more information.

## Basic syntax rules

Below are some specific rules governing the syntax of names. Please follow the
rules exactly, since they make it possible to determine certain properties of
a variable just from its name.

 1. Exported names for both procedures and variables always start with a
    _lower_-case letter. Procedures and variables that are meant only for
    use with in the current package or namespace should start with an
    _upper_-case letter. We chose lower-case for the exported symbols
    because it is possible they may be commonly used from the command line and
    they should be easy to write. For example:

		   # CountNum is a private variable
		   set CountNum 0
		   # The function addWindow is public
		   proc addWindow {} {...
		   # newWindow is a public interface in the spectcl namespace
		   proc spectcl::newWindow {} {...

 2. In multi-word names, the first letter of each trailing word is
    capitalized. Do not use underscores or dashes as separators between the
    words of a name.

		   set numWindows 0

 3. Any variable whose value refers to another variable has a name that ends
    in **Name**. Furthermore, the name should also indicate what type of
    variable the name is referring to. These names are often used in arguments
    to procedures that are taking a name of a variable.

		   proc foo::Bar {arrayName} {
		       upvar 1 $arrayName array
		       ...

		   }

 4. Variables that hold Tcl code that will be **eval**ed should have names
    ending in **Script**.

		   proc log::eval {logScript} {
		       if {$Log::logOn} {
		           set result [catch {eval $logScript} msg]
		           ...

 5. Variables that hold a partial Tcl command that must have additional
    arguments appended before being a valid script should have names ending in
    **Cmd**.

		   foreach scrollCmd $listScrollCmds {
		       eval $scrollCmd $args

		   }

# Low-level coding conventions

This section describes several low-level syntactic rules for writing Tcl code.
These rules help to ensure that all of the Tcl code looks the same, and they
prohibit a few confusing coding constructs.

## Indents are 4 spaces

Each level of indentation should be four spaces. There are ways to set 4-space
indents in all of the most common editors. Be sure that your editor really
uses four spaces for the indent, rather than just displaying tabs as four
spaces wide; if you use the latter approach then the indents will appear eight
spaces wide in other editors.

## Code comments occupy full lines

Comments that document code should occupy full lines, rather than being tacked
onto the ends of lines containing code. The reason for this is that
side-by-side comments are hard to see, particularly if neighboring statements
are long enough to overlap the side-by-side comments. Also it is easy to place
comments in a place that could cause errors. Comments must have exactly the
structure shown in the example below, with a blank line above and below the
comment. The leading blank line can be omitted if the comment is at the
beginning of a block, as is the case in the second comment in the example
below. Each comment should be indented to the same level as the surrounding
code. Use proper English in comments: write complete sentences, capitalize the
first word of each sentence, and so on.

	# If we are running on the Macintosh platform then we can
	# assume that the sources are located in the resource fork
	# of our application, and we do not need to search for them.
	# Note that there is a blank line below it to separate it
	# more strongly from the code.
	
	if {$tcl_platform(platform) == "macintosh"} {
	    return

	}
	
	foreach dir $dirList {
	    # If the source succeds then we are done.
	    # Note there is no blank line above the comment;
	    # the indentation change is visible enough.
	
	    if {![catch {source [file join $dir file.tcl]}]} {
	        break


	    }
	}

## Continuation lines are indented 8 spaces

You should use continuation lines to make sure that no single line exceeds 80
characters in length. Continuation lines should be indented 8 spaces so that
they won't be confused with an immediately-following nested block. Pick clean
places to break your lines for continuation, so that the continuation doesn't
obscure the structure of the statement. For example, if a procedure call
requires continuation lines, try to avoid situations where a single argument
spans multiple lines. If the test for an **if** or **while** command spans
lines, try to make each line have the same nesting level of parentheses and/or
brackets if possible. I try to start each continuation line with an operator
such as **\***, **&&**, or **\|\|**; this makes it clear that the line is a
continuation, since a new statement would never start with such an operator.

## Only one command per line

You should only have one Tcl command per line on the page. Do not use the
semi-colon character to place multiple commands on the same line. This makes
the code easier to read and helps with debugging.

## Curly braces: \{ goes at the end of a line

Open curly braces can not appear on lines by themselves in Tcl. Instead, they
should be placed at the end of the preceding line. Close curly braces are
indented to the same level as the outer code, i.e., four spaces less than the
statements they enclose. However, you shouldalways use curly braces rather
than some other list generating mechanism that will work in the Tcl language.
This will help make code more readable, will avoid unwanted side effects, and
in many cases will generate faster code with the Tcl compiler.

Control structures should always use curly braces, even if there is only one
statement in the block. Thus you shouldn't write code like

	   if {$tcl_platform(platform) == "unix"} return

but rather

	   if {$tcl_platform(platform) == "unix"} {
	       return

	   }

This approach makes code less dense, but it avoids potential mistakes like
unwanted Tcl substitutions. It also makes it easier to set breakpoints in a
debugger, since it guarantees that each statement is on a separate line and
can be named individually.

## Parenthesize expressions

Use parentheses around each subexpression in an expression to make it
absolutely clear what is the evaluation order of the expression \(a reader of
your code should not need to remember Tcl's precedence rules\). For example,
don't type

	   if {$x > 22 && $y <= 47} ...

Instead, type this:

	   if {($x > 22) && ($y <= 47)} ...

## Always use the return statement

You should always explicitly use the **return** statement to return values
from a Tcl procedure. By default Tcl will return the value of the last Tcl
statement executed in a Tcl procedure as the return value of the procedure
which often leads to confusion as to where the result is coming from. In
addition, you should use a **return** statement with no argument for
procedures whose results are ignored. Supplying this return will actually
speed up your application with the new Tcl compiler. For example, don't write
code like this:

	   proc foo {x y} {
	       if {$x < 0} {
	           incr x
	       } else {
	           expr $x + $y


	       }
	   }

But rather, type this:

	   proc foo {x y} {
	       if {$x < 0} {
	           return [incr x]
	       } else {
	           return [expr $x + $y]


	       }
	   }

For Tcl procedures that have no return value a single **return** statement
with no arguments is placed at the end of the procedure.

## Switch statements

The **switch** statement should be formatted as below. Always use the
**--** option to avoid having the string be confused with an option. This
can happen when the string is user generated. Comments can be added on the
same line as the pattern to comment the pattern case. The comments for each
case should line up on the same tab stop and must be within the braces. Note
that this is an exception to the standard commenting conventions.

	   switch -regexp -- $string {
	       plus -
	       add {       # Do add task
	           ...

	       }
	       subtract {  # Do subtract case
	           ...

	       }
	       default {
	           ...


	       }
	   }

## If statements

Never use the **then** word of an **if** statement. It is syntactic sugar
that really isn't that useful. However, the **else** word should always be
used as it does impart some semantic information and it is more like the C
language. Here is an example:

	   if {$x < 0} {
	       ...
	   } elseif {$x == 0} {
	       ...
	   } else {
	       ...

	   }

# Documenting code

The purpose of documentation is to save time and reduce errors. Documentation
is typically used for two purposes. First, people will read the documentation
to find out how to use your code. For example, they will read procedure
headers to learn how to call the procedures. Ideally, people should have to
learn as little as possible about your code in order to use it correctly.
Second, people will read the documentation to find out how your code works
internally, so they can fix bugs or add new features; again, good
documentation will allow them to make their fixes or enhancements while
learning the minimum possible about your code. More documentation isn't
necessarily better: wading through pages of documentation may not be any
easier than deciphering the code. Try to pick out the most important things
that will help people to understand your code and focus on these in your
documentation.

## Document things with wide impact

The most important things to document are those that affect many different
pieces of a program. Thus it is essential that every procedure interface,
every structure declaration, and every global variable be documented clearly.
If you haven't documented one of these things it will be necessary to look at
all the uses of the thing to figure out how it's supposed to work; this will
be time-consuming and error-prone.

On the other hand, things with only local impact may not need much
documentation. For example, in short procedures I don't usually have comments
explaining the local variables. If the overall function of the procedure has
been explained, and if there isn't much code in the procedure, and if the
variables have meaningful names, then it will be easy to figure out how they
are used. On the other hand, for long procedures with many variables I usually
document the key variables. Similarly, when I write short procedures I don't
usually have any comments in the procedure's code: the procedure header
provides enough information to figure out what is going on. For long
procedures I place a comment block before each major piece of the procedure to
clarify the overall flow through the procedure.

## Don't just repeat what's in the code

The most common mistake I see in documentation \(besides it not being there at
all\) is that it repeats what is already obvious from the code, such as this
trivial \(but exasperatingly common\) example:

	   # Increment i.
	
	   incr i

Documentation should provide higher-level information about the overall
function of the code, helping readers to understand what a complex collection
of statements really means. For example, the comment

	   # Probe into the array to see if the symbol exists.

is likely to be much more helpful than

	   # Loop through every array index, get the third value of the
	   # list in the content to determine if it has the symbol we are
	   # looking for. Set the result to the symbol if we find it.

Everything in this second comment is probably obvious from the code that
follows it.

Another thing to consider in your comments is word choice. Use different words
in the comments than the words that appear in variable or procedure names. For
example, the comment

	   # SwapPanels --

	   #
	   # Swap the panels.
	   # ...

is not a very useful comment. Everything in the comment is already obvious
from the procedure's name. Here is a much more useful comment:

	   # SwapPanels --

	   #
	   # Unmap the current UI panel from the parent frame and replace
	   # it with the newly specified frame. Make sure that the new
	   # panel fits into the old frame and resize if needed.
	   # ...

This comment tells _why_ you might want to use the procedure, in addition to
_what_ it does, which makes the comment much more useful.

## Document each thing in exactly one place

Systems evolve over time. If something is documented in several places, it
will be hard to keep the documentation up to date as the system changes.
Instead, try to document each major design decision in exactly one place, as
near as possible to the code that implements the design decision. The
principal documentation for each procedure goes in the procedure header.
There's no need to repeat this information again in the body of the procedure
\(but you might have additional comments in the procedure body to fill in
details not described in the procedure header\). If a library procedure is
documented thoroughly in a manual entry, then I may make the header for the
procedure very terse, simply referring to the manual entry.

The other side of this coin is that every major design decision needs to be
documented _at least_ once. If a design decision is used in many places, it
may be hard to pick a central place to document it. Try to find a data
structure or key procedure where you can place the main body of comments; then
reference this body in the other places where the decision is used. If all
else fails, add a block of comments to the header page of one of the files
implementing the decision.

## Write clean code

The best way to produce a well-documented system is to write clean and simple
code. This way there won't be much to document. If code is clean, it means
that there are a few simple ideas that explain its operation; all you have to
do is to document those key ideas. When writing code, ask yourself if there is
a simple concept behind the code. If not, perhaps you should rethink the code.
If it takes a lot of documentation to explain a piece of code, it is a sign
that you haven't found a clean solution to the problem.

## Document as you go

It is extremely important to write the documentation as you write the code.
It's very tempting to put off the documentation until the end; after all, the
code will change, so why waste time writing documentation now when you'll have
to change it later? The problem is that the end never comes - there is always
more code to write. Also, the more undocumented code that you accumulate, the
harder it is to work up the energy to document it. So, you just write more
undocumented code. I've seen many people start a project fully intending to go
back at the end and write all the documentation, but I've never seen anyone
actually do it.

If you do the documentation as you go, it won't add much to your coding time
and you won't have to worry about doing it later. Also, the best time to
document code is when the key ideas are fresh in your mind, which is when
you're first writing the code. When I write new code, I write all of the
header comments for a group of procedures before I fill in any of the bodies
of the procedures. This way I can think about the overall structure and how
the pieces fit together before getting bogged down in the details of
individual procedures.

## Document tricky situations

If code is non-obvious, meaning that its structure and correctness depend on
information that won't be obvious to someone reading it for the first time, be
sure to document the non-obvious information. One good indicator of a tricky
situation is a bug. If you discover a subtle property of your program while
fixing a bug, be sure to add a comment explaining the problem and its
solution. Of course, it's even better if you can fix the bug in a way that
eliminates the subtle behavior, but this isn't always possible.

# Testing

One of the environments where Tcl works best is for testing. While Tcl has
traditionally been used for testing C code it is equally as good at testing
other Tcl code. Whenever you write new code you should write Tcl test scripts
to go with that code and save the tests in files so that they can be re-run
later. Writing test scripts isn't as tedious as it may sound. If you're
developing your code carefully you're already doing a lot of testing; all you
need to do is type your test cases into a script file where they can be
reused, rather than typing them interactively where they vanish after they're
run.

## Basics

Tests should be organized into script files, where each file contains a
collection of related tests. Individual tests should be based on the procedure
**test**, just like in the Tcl and Tk test suites. Here are two examples:

	   test expr-3.1 {floating-point operators} {
	       expr 2.3*.6
	   } 1.38
	   test expr-3.2 {floating-point operators} {unixOnly} {
	       list [catch {expr 2.3/0} msg] $msg
	   } {1 {divide by zero}}

**test** is a procedure defined in a script file named **defs**, which is
**source**d by each test file. **test** takes four or five arguments: a
test identifier, a string describing the test, an optional argument describing
the conditions under which this test should run, a test script, and the
expected result of the script. **test** evaluates the script and checks to
be sure that it produces the expected result. If not, it prints a message like
the following:

	   ==== expr-3.1 floating-point operators
	   ==== Contents of test case:
	       expr 2.3*.6
	   ==== Result was:
	   1.39
	   ---- Result should have been:
	   1.38
	   ---- expr-3.1 FAILED

To run a set of tests, you start up the application and **source** a test
file. If all goes well no messages appear; if errors are detected, a message
is printed for each error.

The test identifier, such as **expr-3.1**, is printed when errors occur. It
can be used to search a test script to locate the source for a failed test.
The first part of the identifier, such as **expr**, should be the same as
the name of the test file, except that the test file should have a **.test**
extension, such as **expr.test**. The two numbers allow you to divide your
tests into groups. The tests in a particular group \(e.g., all the
**expr-3.**_n_ tests\) relate to a single sub-feature, such as a single
procedure. The tests should appear in the test file in the same order as their
numbers.

The test name, such as **floating-point operators**, is printed when errors
occur. It provides human-readable information about the general nature of the
test.

Before writing tests I suggest that you look over some of the test files for
Tcl and Tk to see how they are structured. You may also want to look at the
**README** files in the Tcl and Tk test directories to learn about
additional features that provide more verbose output or restrict the set of
tests that are run.

## Organizing tests

Organize your tests to match the code being tested. The best way to do this is
to have one test file for each source code file, with the name of the test
file derived from the name of the source file in an obvious way \(e.g.
**http.test** contains tests for the code in **http.tcl**\). Within the
test file, have one group of tests for each procedure \(for example, all the
**http-3.**_n_ tests in **http.test** are for the procedure
**http::geturl**\). The order of the tests within a group should be the same
as the order of the code within the procedure. This approach makes it easy to
find the tests for a particular piece of code and add new tests as the code
changes.

The Tcl test suite was written a long time ago and uses a different style
where there is one file for each Tcl command or group of related commands, and
the tests are grouped within the file by sub-command or features. In this
approach the relationship between tests and particular pieces of code is much
less obvious, so it is harder to maintain the tests as the code evolves. I
don't recommend using this approach for new tests.

## Coverage

When writing tests, you should attempt to exercise every line of source code
at least once. There will be occasionally be code that you can't exercise,
such as code that exits the application, but situations like this are rare.
You may find it hard to exercise some pieces of code because existing Tcl
commands don't provide fine enough control to generate all the possible
execution paths. In situations like this, write one or more new Tcl commands
just for testing purposes. It's much better to test a facility directly then
to rely on some side effect for testing that may change over time. Use a
similar approach in your own code, where you have an extra file with
additional commands for testing.

It's not sufficient just to make sure each line of code is executed by your
tests. In addition, your tests must discriminate between code that executes
correctly and code that isn't correct. For example, write tests to make sure
that the **then** and **else** branches of each **if** statement are
taken under the correct conditions. For a loop, run different tests to make
the loop execute zero times, one time, and two or more times. If a piece of
code removes an element from a list, try cases where the element to be removed
is the first element, last element, only element, and neither first element
nor last. Try to find all the places where different pieces of code interact
in unusual ways, and exercise the different possible interactions.

## Fixing bugs

Whenever you find a bug in your code it means that the test suite wasn't
complete. As part of fixing the bug, you should add new tests that detect the
presence of the bug. I recommend writing the tests after you've located the
bug but _before_ you fix it. That way you can verify that the bug happens
before you implement the fix and the bug doesn't happen afterwards, so you'll
know you've really fixed something. Use bugs to refine your testing approach:
think about what you might be able to do differently when you write tests in
the future to keep bugs like this one from going undetected.

## Tricky features

I also use tests as a way of illustrating the need for tricky code. If a piece
of code has an unusual structure, and particularly if the code is hard to
explain, I try to write additional tests that will fail if the code is
implemented in the obvious manner instead of using the tricky approach. This
way, if someone comes along later, doesn't understand the documentation for
the code, decides the complex structure is unnecessary, and changes the code
back to the simple \(but incorrect\) form, the test will fail and the person
will be able to use the test to understand why the code needs to be the way it
is. Illustrative tests are not a substitute for good documentation, but they
provide a useful addition.

## Test independence

Try to make tests independent of each other, so that each test can be
understood in isolation. For example, one test shouldn't depend on commands
executed in a previous test. This is important because the test suite allows
tests to be run selectively: if the tests depend on each other, then false
errors will be reported when someone runs a few of the tests without the
others.

For convenience, you may execute a few statements in the test file to set up a
test configuration and then run several tests based on that configuration. If
you do this, put the setup code outside the calls to thetest procedure so it
will always run even if the individual tests aren't run. I suggest keeping a
very simple structure consisting of setup followed by a group of tests. Don't
perform some setup, run a few tests, modify the setup slightly, run a few more
tests, modify the setup again, and so on. If you do this, it will be hard for
people to figure out what the setup is at any given point and when they add
tests later they are likely to break the setup.

# Miscellaneous

## Porting issues

Writing portable scripts in Tcl is actually quite easy as Tcl itself is quite
portable. However, issues do arise that may require writing platform specific
code. To conditionalize your code in this manner you should use the
**tcl\_platform** array to determine platform specific differences. You
should avoid the use of theenv variable unless you have already determined the
platform you are running on via the **tcl\_platform** array.

As Tcl/Tk has become more cross platform we have added commands that aid in
making your code more portable. The most common porting mistakes result from
assumptions about file names and locations. To avoid such mistakes always use
the **file join** command and list commands so that you will handle
different file separation characters or spaces in file names. In Tk, you
should always use provided high level dialog boxes instead or creating your
own. The **font** and **menu** commands has also be revamped to make
writing cross-platform code easier.

## Changes files

Each package should contain a file namedchanges that keeps a log of all
significant changes made to the package. The **changes** file provides a way
for users to find out what's new in each new release, what bugs have been
fixed, and what compatibility problems might be intro- duced by the new
release. The **changes** file should be in chronological order. Just add
short blurbs to it each time you make a change. Here is a sample from the Tk
**changes** file:

	   5/19/94 (bug fix) Canvases didn't generate proper Postscript for
	   stippled text. (RJ)
	
	   5/20/94 (new feature) Added "bell" command to ring the display's
	   bell. (JO)
	
	   5/26/94 (feature removed) Removed support for "fill" justify mode
	   from Tk_GetJustify and from the TK_CONFIG_JUSTIFY configuration
	   option.  None of the built-in widgets ever supported this mode
	   anyway. (SS)
	   *** POTENTIAL INCOMPATIBILITY ***

The entries in the **changes** file can be relatively terse; once someone
finds a change that is relevant, they can always go to the manual entries or
code to find out more about it. Be sure to highlight changes that cause
compatibility problems, so people can scan the **changes** file quickly to
locate the incompatibilities. Also be sure to add your initials to the entry
so that people scanning the log will know who made a particular change.

_\(The Tcl and Tk core additionally uses a ChangeLog file that has a much
higher detail within it. This has the advantage of having more tooling
support, but tends to be so verbose that the shorter summaries in the changes
file are still written up by the core maintainers before each release.\)_

# Copyright

The original version of this document is copyright \(C\) 1997 Sun Microsystems,
Inc. Revisions to reflect current community best-practice are public domain.

Name change from tip/353.tip to tip/353.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

TIP:		353
Title:		NR-enabled Expressions for Extensions
Version:	$Revision: 1.7 $
Author:		Don Porter <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	29-Jul-2009
Tcl-Version:	8.6
Post-History:


~ Abstract

This TIP proposes the new public routine '''Tcl_NRExprObj''' to provide
extension commands that evaluate Tcl expressions the ability to do so in a
non-recursive manner.

~ Background

In a few contexts, expressions that contain '''yield''' raise the error
"''cannot yield: C stack busy''"; see Tcl Bugs 2823282
[https://sourceforge.net/support/tracker.php?aid=2823282] and 2823276
[https://sourceforge.net/support/tracker.php?aid=2823276]. This is because a
few little-visited corners of Tcl's implementation call the routine
'''Tcl_ExprObj''' and that routine is not NR-enabled.

For extensions wishing to evaluate Tcl expressions, '''Tcl_ExprObj''' is not
little-visited.  It is the public, supported, recommended tool for the job.
Just as [322] provided a routine '''Tcl_NREvalObj''' as an NR-enabled
replacement for '''Tcl_EvalObj''', extensions wishing to NR-enable their
commands need an analogous replacement for '''Tcl_ExprObj'''.

~ Rationale

Tcl has a long history of providing extensions access to the same capabilities
available to the built-in command set so that extension commands are on an
equal footing, not in a second class status.  Keeping with that, we want
extensions to be able to create NR-enabled commands, so we need to provide an
interface for extensions to evaluate expressions in an NR-enabled manner. This
TIP can be seen as filling up a hole in [322].

~ Scope Limitations

The Tcl public C interface provides a whole family of variants of
'''Tcl_ExprObj''': '''Tcl_ExprLongObj''', '''Tcl_ExprDoubleObj''',
'''Tcl_ExprBooleanObj''', '''Tcl_ExprLong''', '''Tcl_ExprDouble''',
'''Tcl_ExprBoolean''', '''Tcl_ExprString'''.  NR-enabled counterparts to these
routines are ''not'' proposed.  Extensions rewriting their command procedures
to use the proposed '''Tcl_NRExprObj''' for sake of NR-enabling can at the
same time be expected to convert from these convenience wrappers to more
direct use of a single NR-enabled primitive.

~ Proposal

Add the following routine to Tcl's public interface:

   > int '''Tcl_NRExprObj'''(Tcl_Interp *''interp'', Tcl_Obj *''objPtr'',
     Tcl_Obj *''resultPtr'')

This routine places on the NR stack a request that the Tcl non-recursive
trampoline evaluate the ''objPtr'' value as a Tcl expression in interpreter
''interp''.  This routine returns the value '''TCL_OK''', since there is
(currently) no way this request operation can fail.  The proposed interface
still provides for an int return value so that future revisions to Tcl's
internals have the freedom to change that without need to change the public
interface.

The ''resultPtr'' argument must be an unshared Tcl value.  When expression
evaluation succeeds, the result of the expression is written to ''resultPtr''
in the same way that '''Tcl_SetStringObj''' would write a string value to an
unshared Tcl value.  If expression evaluation produces any return code other
than '''TCL_OK''', the value of ''resultPtr'' is left untouched.

Callers of '''Tcl_NRExprObj''' will also need to call '''Tcl_NRAddCallback'''
to request a '''Tcl_NRPostProc''' callback routine be placed on the NR stack
which can take care of managing ''resultPtr'' as appropriate depending on the
''result'' value.

~ Implementation

The patch attached to Tcl Bug 2823282
[https://sourceforge.net/support/tracker.php?aid=2823282] implements this
proposal.

~ Compatibility

There should be no compatibility issues, since at the interface level this is
just the addition of a new routine.  Revisions to the internal implementations
of existing routines should be harmless.

~ Migration

As an example for extensions to follow, consider this template for a
'''Tcl_ObjCmdProc''' currently calling '''Tcl_ExprObj'''.

|int ObjCmd(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
|{   int code;
|    Tcl_Obj *resultPtr;
|    /* determine expression, objPtr */
|    code = Tcl_ExprObj(interp, objPtr, &resultPtr);
|    if (code != TCL_OK) {return code}
|    /* resultPtr holds expression result; continue */
|}

|
|Tcl_CreateObjCommand(interp, name, ObjCmd, /* ... */);

To use '''Tcl_NRExprObj''' to NR-enable this command, rewrite along these
lines:

|int ObjCmd(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
|{   return Tcl_NRCallObjProc(interp, NRObjCmd, cd, objc, objv);  }
|
|int NRObjCmd(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
|{   Tcl_Obj *resultPtr = Tcl_NewObj();
|    /* determine expression, objPtr */
|    Tcl_NRAddCallback(interp, Callback, resultPtr, /*...*/);
|    return Tcl_NRExprObj(interp, objPtr, resultPtr);
|}

|
|int Callback(ClientData data[], Tcl_Interp *interp, int code)
|{   Tcl_Obj *resultPtr = data[0];
|    if (code != TCL_OK) {Tcl_DecrRefCount(resultPtr); return code;}
|    /* resultPtr holds expression result; continue */
|}

|
|Tcl_NRCreateCommand(interp, name, ObjCmd, NRObjCmd, /*...*/);

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|



|

|
|
|
|

|

|

|
|
|

|






|

|


|
|
|
|
|



|



|
|


|
|
|




|
|
|

|

|
|
|
|

|


|


|





|


|

|
|
|
|
|
|
|
<
>
|
|

|


|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|

|


>

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

# TIP 353: NR-enabled Expressions for Extensions

	Author:		Don Porter <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	29-Jul-2009
	Tcl-Version:	8.6
	Post-History:
-----

# Abstract

This TIP proposes the new public routine **Tcl\_NRExprObj** to provide
extension commands that evaluate Tcl expressions the ability to do so in a
non-recursive manner.

# Background

In a few contexts, expressions that contain **yield** raise the error
"_cannot yield: C stack busy_"; see Tcl Bugs 2823282
<https://sourceforge.net/support/tracker.php?aid=2823282>  and 2823276
<https://sourceforge.net/support/tracker.php?aid=2823276> . This is because a
few little-visited corners of Tcl's implementation call the routine
**Tcl\_ExprObj** and that routine is not NR-enabled.

For extensions wishing to evaluate Tcl expressions, **Tcl\_ExprObj** is not
little-visited.  It is the public, supported, recommended tool for the job.
Just as [[322]](322.md) provided a routine **Tcl\_NREvalObj** as an NR-enabled
replacement for **Tcl\_EvalObj**, extensions wishing to NR-enable their
commands need an analogous replacement for **Tcl\_ExprObj**.

# Rationale

Tcl has a long history of providing extensions access to the same capabilities
available to the built-in command set so that extension commands are on an
equal footing, not in a second class status.  Keeping with that, we want
extensions to be able to create NR-enabled commands, so we need to provide an
interface for extensions to evaluate expressions in an NR-enabled manner. This
TIP can be seen as filling up a hole in [[322]](322.md).

# Scope Limitations

The Tcl public C interface provides a whole family of variants of
**Tcl\_ExprObj**: **Tcl\_ExprLongObj**, **Tcl\_ExprDoubleObj**,
**Tcl\_ExprBooleanObj**, **Tcl\_ExprLong**, **Tcl\_ExprDouble**,
**Tcl\_ExprBoolean**, **Tcl\_ExprString**.  NR-enabled counterparts to these
routines are _not_ proposed.  Extensions rewriting their command procedures
to use the proposed **Tcl\_NRExprObj** for sake of NR-enabling can at the
same time be expected to convert from these convenience wrappers to more
direct use of a single NR-enabled primitive.

# Proposal

Add the following routine to Tcl's public interface:

   > int **Tcl\_NRExprObj**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_objPtr_,
     Tcl\_Obj \*_resultPtr_\)

This routine places on the NR stack a request that the Tcl non-recursive
trampoline evaluate the _objPtr_ value as a Tcl expression in interpreter
_interp_.  This routine returns the value **TCL\_OK**, since there is
\(currently\) no way this request operation can fail.  The proposed interface
still provides for an int return value so that future revisions to Tcl's
internals have the freedom to change that without need to change the public
interface.

The _resultPtr_ argument must be an unshared Tcl value.  When expression
evaluation succeeds, the result of the expression is written to _resultPtr_
in the same way that **Tcl\_SetStringObj** would write a string value to an
unshared Tcl value.  If expression evaluation produces any return code other
than **TCL\_OK**, the value of _resultPtr_ is left untouched.

Callers of **Tcl\_NRExprObj** will also need to call **Tcl\_NRAddCallback**
to request a **Tcl\_NRPostProc** callback routine be placed on the NR stack
which can take care of managing _resultPtr_ as appropriate depending on the
_result_ value.

# Implementation

The patch attached to Tcl Bug 2823282
<https://sourceforge.net/support/tracker.php?aid=2823282>  implements this
proposal.

# Compatibility

There should be no compatibility issues, since at the interface level this is
just the addition of a new routine.  Revisions to the internal implementations
of existing routines should be harmless.

# Migration

As an example for extensions to follow, consider this template for a
**Tcl\_ObjCmdProc** currently calling **Tcl\_ExprObj**.

	int ObjCmd(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
	{   int code;
	    Tcl_Obj *resultPtr;
	    /* determine expression, objPtr */
	    code = Tcl_ExprObj(interp, objPtr, &resultPtr);
	    if (code != TCL_OK) {return code}
	    /* resultPtr holds expression result; continue */

	}
	
	Tcl_CreateObjCommand(interp, name, ObjCmd, /* ... */);

To use **Tcl\_NRExprObj** to NR-enable this command, rewrite along these
lines:

	int ObjCmd(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
	{   return Tcl_NRCallObjProc(interp, NRObjCmd, cd, objc, objv);  }
	
	int NRObjCmd(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
	{   Tcl_Obj *resultPtr = Tcl_NewObj();
	    /* determine expression, objPtr */
	    Tcl_NRAddCallback(interp, Callback, resultPtr, /*...*/);
	    return Tcl_NRExprObj(interp, objPtr, resultPtr);

	}
	
	int Callback(ClientData data[], Tcl_Interp *interp, int code)
	{   Tcl_Obj *resultPtr = data[0];
	    if (code != TCL_OK) {Tcl_DecrRefCount(resultPtr); return code;}
	    /* resultPtr holds expression result; continue */

	}
	
	Tcl_NRCreateCommand(interp, name, ObjCmd, NRObjCmd, /*...*/);

# Copyright

This document has been placed in the public domain.

Name change from tip/354.tip to tip/354.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

TIP:		354
Title:		Minor Production-Driven TclOO Revisions
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Post-History:	
Version:	$Revision: 1.4 $
Author:		Donal K. Fellows <[email protected]>
Created:	26-Aug-2009


~ Abstract

This TIP describes a few small changes required for solving issues that have
been found when using TclOO in production.

~ Description

TclOO (see [257]) has now had a substantial amount of use for relatively
complex functionality (as well as production deployment) and it has turned out
that there were a few small changes required.

 1. The scope of resolution for the target of a '''forward'''ed method is
    updated so that it is with respect to the object's namespace. This means
    that a class may create methods that forward to a command given by each
    instance, which makes creating megawidgets by wrapping real Tk widgets
    much easier, since the forwards do not have to be created at the instance
    level.

 2. A subcommand was added to '''info object''' to allow the discovery of the
    namespace of an object by code outside that object. This makes it far
    easier for code that needs to "break the abstraction" to do so, which
    turns out to be necessary for things like serialization. This subcommand,
    '''namespace''', takes an object name as its only argument and returns the
    name of the object's namespace.

  > To expand on the requirements for serialization, the serialization code
    needs to call a method on each object to create the serialization for that
    object. However, the method should not be part of the public API for the
    object as it cannot perform a complete serialization correctly, since the
    serialization depends on the rest of the object graph. (It also requires a
    number of global overheads that are best applied once, not repeatedly.)

  > Note that I plan to release the serialization code itself (originally
    developed as part of a solution for a Rosetta Code task) as a package via
    tcllib. This TIP does not propose its inclusion with Tcl.

 3. A new C API function has been added to allow code at that level to
    ''efficiently'' discover the name of an object that it already has a
    handle to. This new function, '''Tcl_GetObjectName''', returns a shared
    Tcl_Obj reference to the name that needs no special reference count
    management.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
>

|




|

|
|


|






|



|


|



|
|

|
|



|
|
|


|


>

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

# TIP 354: Minor Production-Driven TclOO Revisions
	State:		Final
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Done
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	26-Aug-2009
-----

# Abstract

This TIP describes a few small changes required for solving issues that have
been found when using TclOO in production.

# Description

TclOO \(see [[257]](257.md)\) has now had a substantial amount of use for relatively
complex functionality \(as well as production deployment\) and it has turned out
that there were a few small changes required.

 1. The scope of resolution for the target of a **forward**ed method is
    updated so that it is with respect to the object's namespace. This means
    that a class may create methods that forward to a command given by each
    instance, which makes creating megawidgets by wrapping real Tk widgets
    much easier, since the forwards do not have to be created at the instance
    level.

 2. A subcommand was added to **info object** to allow the discovery of the
    namespace of an object by code outside that object. This makes it far
    easier for code that needs to "break the abstraction" to do so, which
    turns out to be necessary for things like serialization. This subcommand,
    **namespace**, takes an object name as its only argument and returns the
    name of the object's namespace.

	  > To expand on the requirements for serialization, the serialization code
    needs to call a method on each object to create the serialization for that
    object. However, the method should not be part of the public API for the
    object as it cannot perform a complete serialization correctly, since the
    serialization depends on the rest of the object graph. \(It also requires a
    number of global overheads that are best applied once, not repeatedly.\)

	  > Note that I plan to release the serialization code itself \(originally
    developed as part of a solution for a Rosetta Code task\) as a package via
    tcllib. This TIP does not propose its inclusion with Tcl.

 3. A new C API function has been added to allow code at that level to
    _efficiently_ discover the name of an object that it already has a
    handle to. This new function, **Tcl\_GetObjectName**, returns a shared
    Tcl\_Obj reference to the name that needs no special reference count
    management.

# Copyright

This document has been placed in the public domain.

Name change from tip/355.tip to tip/355.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

TIP:            355
Title:          Stop Fast Recycling of Channel Names on Unix
Version:        $Revision: 1.1 $
Author:         Alexandre Ferrieux <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        01-Sep-2009
Tcl-Version:    8.7
Post-History:   


~ Abstract

This TIP proposes to put an end to the unix-specific habit of naming channels
after the underlying file descriptor, by using a much longer-lived incremented
counter instead.

~ Background

Tcl (non-reflected) channel names are of the general form $''KIND''$''HANDLE''
on all OSes, $''KIND'' being something like "'''file'''", "'''pipe'''", etc,
and $''HANDLE'' being the OS file descriptor or handle.  This is clearly a
cost-effective way of guaranteeing process-wide unicity at any given time.

However, on unix, file descriptors are in a "compact table", i.e. they are
small integers that are reused as quickly as possible, to keep the range small
for efficiency reasons (and also constraints like the select() API).  And as
witnessed by [[Bug
2826430]][https://sourceforge.net/support/tracker.php?aid=2826430], channel
name recycling is dangerous. Quite possibly a bunch of applications running
today get occasionally hit, with very hard to decipher symptoms, and an even
harder to reproduce setup.

~ Proposed Change

This TIP proposes to replace the file descriptor in unix channel names by an
ever-increasing, process-unique counter.

~ Rationale

This change would bring unix channels in line with the rest of the crowd,
since Windows handles seem to have a very long cycle, and reflected channels
already use a counter. It could even be more ambitious in that (1) even
Windows channels use the counter instead of relying on the OS's lifetime
guarantee, and (2) reflected channels use the same counter instead of their
own. Choice left open for discussion.

The implementation is trivial: a new public function,
'''Tcl_GetProcessUniqueNum''', returns a global integer counter which is
incremented under mutex.  (It will wrap at MAXINT and I am listening to
whoever thinks it is still a problem...).

~ Reference Implementation

The patch attached to the aforementioned bug
[https://sourceforge.net/support/tracker.php?aid=2826430] adds this stub
entry, and updates all unix channel naming schemes to use it.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|





|

|
|
|




|
|
|




|




|



|

|



|
|
|

|


|


|


>

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

# TIP 355: Stop Fast Recycling of Channel Names on Unix

	Author:         Alexandre Ferrieux <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        01-Sep-2009
	Tcl-Version:    8.7
	Post-History:   
-----

# Abstract

This TIP proposes to put an end to the unix-specific habit of naming channels
after the underlying file descriptor, by using a much longer-lived incremented
counter instead.

# Background

Tcl \(non-reflected\) channel names are of the general form $_KIND_$_HANDLE_
on all OSes, $_KIND_ being something like "**file**", "**pipe**", etc,
and $_HANDLE_ being the OS file descriptor or handle.  This is clearly a
cost-effective way of guaranteeing process-wide unicity at any given time.

However, on unix, file descriptors are in a "compact table", i.e. they are
small integers that are reused as quickly as possible, to keep the range small
for efficiency reasons \(and also constraints like the select\(\) API\).  And as
witnessed by [Bug
2826430]<https://sourceforge.net/support/tracker.php?aid=2826430> , channel
name recycling is dangerous. Quite possibly a bunch of applications running
today get occasionally hit, with very hard to decipher symptoms, and an even
harder to reproduce setup.

# Proposed Change

This TIP proposes to replace the file descriptor in unix channel names by an
ever-increasing, process-unique counter.

# Rationale

This change would bring unix channels in line with the rest of the crowd,
since Windows handles seem to have a very long cycle, and reflected channels
already use a counter. It could even be more ambitious in that \(1\) even
Windows channels use the counter instead of relying on the OS's lifetime
guarantee, and \(2\) reflected channels use the same counter instead of their
own. Choice left open for discussion.

The implementation is trivial: a new public function,
**Tcl\_GetProcessUniqueNum**, returns a global integer counter which is
incremented under mutex.  \(It will wrap at MAXINT and I am listening to
whoever thinks it is still a problem...\).

# Reference Implementation

The patch attached to the aforementioned bug
<https://sourceforge.net/support/tracker.php?aid=2826430>  adds this stub
entry, and updates all unix channel naming schemes to use it.

# Copyright

This document has been placed in the public domain.

Name change from tip/356.tip to tip/356.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

TIP:		356
Title:		NR-enabled Substitutions for Extensions
Version:	$Revision: 1.4 $
Author:		Don Porter <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	17-Sep-2009
Tcl-Version:	8.6
Post-History:
Keywords:	Tcl, C API, subst


~ Abstract

This TIP proposes the new public routine '''Tcl_NRSubstObj''' to provide
extension commands that evaluate Tcl substitutions the ability to do so in a
non-recursive manner.

~ Background 

Continuing in the path of [322] and [353], we want extensions to be able to
create NR-enabled commands, and any command procedures currently calling the
'''Tcl_SubstObj''' routine are not NR-enabled.  The solution is to provide the
NR-enabled counterpart.

~ Proposal

Add the following routine to Tcl's public interface:

   > int '''Tcl_NRSubstObj'''(Tcl_Interp *''interp'', Tcl_Obj *''objPtr'',
     int ''flags'')

This routine places on the NR stack a request that the Tcl non-recursive
trampoline evaluate the ''objPtr'' value as a Tcl substitution in interpreter
''interp'', as controlled by the value of ''flags''.  The ''flags'' value is
the same combination of '''TCL_SUBST_BACKSLASHES''', '''TCL_SUBST_COMMANDS''',
and '''TCL_SUBST_VARIABLES''' that control '''Tcl_SubstObj'''.  This routine
returns the value '''TCL_OK''', since there is (currently) no way this request
operation can fail.  The proposed interface still provides for an int return
value so that future revisions to Tcl's internals have the freedom to change
that without need to change the public interface.

After the trampoline completes the requested substitution, it will pass the
return code, either '''TCL_OK''' or '''TCL_ERROR''', to the next callback on
the NR-stack, and either the result of the substitution or the error message
will be stored in the result of ''interp''. The caller of '''Tcl_NRSubstObj'''
may also call '''Tcl_NRAddCallback''' to request a '''Tcl_NRPostProc'''
callback routine be placed on the NR stack to receive these results, if needed
to achieve the task the caller is performing.

~ Implementation

The proposed routine is already present in the HEAD of Tcl as the internal
routine '''TclNRSubstObj'''.  This proposal would simply promote it to Tcl's
public interface.

~ Compatibility

There should be no compatibility issues, since at the interface level this is
just the addition of a new routine.

~ Migration

As an example for extensions to follow, consider this template for a
'''Tcl_ObjCmdProc''' currently calling '''Tcl_SubstObj'''.

|int ObjCmd(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
|    Tcl_Obj *resultPtr;
|    /* determine text to be substituted, objPtr */
|    /* determine flags value to control substitution */
|    resultPtr = Tcl_SubstObj(interp, objPtr, flags);
|    if (resultPtr == NULL) {return TCL_ERROR}
|    /* resultPtr holds substitution result; continue */
|}

|
|Tcl_CreateObjCommand(interp, name, ObjCmd, /* ... */);

To use '''Tcl_NRSubstObj''' to NR-enable this command, rewrite along these
lines:

|int ObjCmd(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
|{   return Tcl_NRCallObjProc(interp, NRObjCmd, cd, objc, objv);  }
|
|int NRObjCmd(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
|{   

|    /* determine text to be substituted, objPtr */
|    /* determine flags value to control substitution */
|    Tcl_NRAddCallback(interp, Callback, /*...*/);
|    return Tcl_NRSubstObj(interp, objPtr, flags);
|}

|
|int Callback(ClientData data[], Tcl_Interp *interp, int code)
|{   Tcl_Obj *resultPtr;
|    if (code == TCL_ERROR) {return TCL_ERROR;}
|    resultPtr = Tcl_GetObjResult(interp);
|    /* resultPtr holds expression result; continue */
|}

|
|Tcl_NRCreateCommand(interp, name, ObjCmd, NRObjCmd, /*...*/);

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|

|

|


|



|
|


|
|
|
|
|





|

|
|



|


|


|




|


|

|
|
|
|
|
|
|
<
>
|
|

|


|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
|

|


>

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

# TIP 356: NR-enabled Substitutions for Extensions

	Author:		Don Porter <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	17-Sep-2009
	Tcl-Version:	8.6
	Post-History:
	Keywords:	Tcl, C API, subst
-----

# Abstract

This TIP proposes the new public routine **Tcl\_NRSubstObj** to provide
extension commands that evaluate Tcl substitutions the ability to do so in a
non-recursive manner.

# Background 

Continuing in the path of [[322]](322.md) and [[353]](353.md), we want extensions to be able to
create NR-enabled commands, and any command procedures currently calling the
**Tcl\_SubstObj** routine are not NR-enabled.  The solution is to provide the
NR-enabled counterpart.

# Proposal

Add the following routine to Tcl's public interface:

   > int **Tcl\_NRSubstObj**\(Tcl\_Interp \*_interp_, Tcl\_Obj \*_objPtr_,
     int _flags_\)

This routine places on the NR stack a request that the Tcl non-recursive
trampoline evaluate the _objPtr_ value as a Tcl substitution in interpreter
_interp_, as controlled by the value of _flags_.  The _flags_ value is
the same combination of **TCL\_SUBST\_BACKSLASHES**, **TCL\_SUBST\_COMMANDS**,
and **TCL\_SUBST\_VARIABLES** that control **Tcl\_SubstObj**.  This routine
returns the value **TCL\_OK**, since there is \(currently\) no way this request
operation can fail.  The proposed interface still provides for an int return
value so that future revisions to Tcl's internals have the freedom to change
that without need to change the public interface.

After the trampoline completes the requested substitution, it will pass the
return code, either **TCL\_OK** or **TCL\_ERROR**, to the next callback on
the NR-stack, and either the result of the substitution or the error message
will be stored in the result of _interp_. The caller of **Tcl\_NRSubstObj**
may also call **Tcl\_NRAddCallback** to request a **Tcl\_NRPostProc**
callback routine be placed on the NR stack to receive these results, if needed
to achieve the task the caller is performing.

# Implementation

The proposed routine is already present in the HEAD of Tcl as the internal
routine **TclNRSubstObj**.  This proposal would simply promote it to Tcl's
public interface.

# Compatibility

There should be no compatibility issues, since at the interface level this is
just the addition of a new routine.

# Migration

As an example for extensions to follow, consider this template for a
**Tcl\_ObjCmdProc** currently calling **Tcl\_SubstObj**.

	int ObjCmd(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
	    Tcl_Obj *resultPtr;
	    /* determine text to be substituted, objPtr */
	    /* determine flags value to control substitution */
	    resultPtr = Tcl_SubstObj(interp, objPtr, flags);
	    if (resultPtr == NULL) {return TCL_ERROR}
	    /* resultPtr holds substitution result; continue */

	}
	
	Tcl_CreateObjCommand(interp, name, ObjCmd, /* ... */);

To use **Tcl\_NRSubstObj** to NR-enable this command, rewrite along these
lines:

	int ObjCmd(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
	{   return Tcl_NRCallObjProc(interp, NRObjCmd, cd, objc, objv);  }
	
	int NRObjCmd(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])

	{   
	    /* determine text to be substituted, objPtr */
	    /* determine flags value to control substitution */
	    Tcl_NRAddCallback(interp, Callback, /*...*/);
	    return Tcl_NRSubstObj(interp, objPtr, flags);

	}
	
	int Callback(ClientData data[], Tcl_Interp *interp, int code)
	{   Tcl_Obj *resultPtr;
	    if (code == TCL_ERROR) {return TCL_ERROR;}
	    resultPtr = Tcl_GetObjResult(interp);
	    /* resultPtr holds expression result; continue */

	}
	
	Tcl_NRCreateCommand(interp, name, ObjCmd, NRObjCmd, /*...*/);

# Copyright

This document has been placed in the public domain.

Name change from tip/357.tip to tip/357.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
136

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

TIP:            357
Title:          Export TclLoadFile
Version:        $Revision: 1.14 $
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        01-Oct-2009
Post-History:   
Tcl-Version:    8.6


~ Abstract

This TIP proposes to promote the internal calls, ''TclLoadFile'' and
''TclpFindSymbol'' to the
external API, making them available to C extensions. In addition, it
proposes to introduce a ''Tcl_FSUnloadFile'' to the VFS layer, removing
the weird duplicate client data from ''TclLoadFile'' and wrapping all
necessary data into the '''Tcl_LoadHandle'''

~ Rationale

In developing TDBC [308], the author of this TIP was advised to look at the
way that the 'oratcl' extension contrives to build on a system where
Oracle is not installed as a model for TDBC extensions.  Examination
of the code revealed that it operates essentially by constructing at
run time a Stubs table for the routines in the Oracle client
library. There is a maze of '''#if''' directives selecting whether
this process is accomplished by the system calls that manage Unix .so
files (''dlopen'' and friends), Windows .DLL files (''LoadLibrary'' and
related calls), HP-UX .shl files (''shl_load,'' etc.), and so on.

Tcl already has functionality so that a caller can abstract away all
this complexity.  It provides the capability in the ''TclLoadFile''
call, but this call is '''MODULE_SCOPE''' and not exported even in the
internal Stubs table. For this reason, it is entirely unavailable to
TEA-compliant extensions.

If this call were available, it would be feasible, in the 8.6 time frame,
to bundle all the database-specific TDBC drivers with the core TDBC
distribution, since things could be set up so that they will build
anywhere, even in the absence of the databases where they connect.

However, this call was never fully rationalized in the VFS world. Its
strange API (with both a '''Tcl_LoadHandle''' and a '''ClientData''',
and a function pointer for unloading the library) is, as several reviewers
pointed out, not somehting that we want to make available to general callers.
Hence, a few more routines need rework.

~ Specification

The ''TclLoadFile'' call shall be renamed ''Tcl_LoadFile'' and exported
in the external Stubs.  Its call signature shall be changed to:

 > EXTERN int
   '''Tcl_LoadFile'''(
       Tcl_Interp *''interp'',
       Tcl_Obj *''pathPtr'',
       const char *''symbols''[],
       int ''flags'',
       void *''procPtrs'',
       Tcl_LoadHandle *''handlePtr'');

In this call, ''interp'' designates an interpreter for error reporting.
''pathPtr'' is an object containing the path of the library to be loaded.
If ''pathPtr'' is a single name, the library search path of the current
environment will be used to resolve it.  
The ''symbols'' array  contains a NULL-terminated set of
character strings that are the names
of the imported symbols. ''symbols'' may be NULL if the library is to be loaded without resolving any symbols.

The return value of ''Tcl_LoadFile'' is a standard Tcl result code. If the
result is TCL_ERROR, the interpreter result will contain an appropriate
error message.

On return, ''Tcl_LoadFile'' fills in the block of memory commencing
at the address given by ''procPtrs'' with the addresses
that correspond to the names in ''symbols.'' If a name cannot be
resolved in the given library, an error will be returned and all
entries in ''procPtrs'' will be invalid. ''procPtrs'' may be NULL
if no symbols are to be resolved.

On a successful return,
the ''loadHandle'' pointer will be a handle suitable for
passing to ''Tcl_FindSymbol'' for resolving additional symbols in the
library, or to ''Tcl_FSUnloadFile'' to unload the library.

The ''TclpFindSymbol'' call shall be renamed ''Tcl_FindSymbol'' and
exported in the external Stubs.  Its call signature shall be:

 > EXTERN void*
   '''Tcl_FindSymbol'''(
       Tcl_Interp *''interp'',
       Tcl_LoadHandle *''loadHandle'',
       const char *''symbol'');

This call searches for the given ''symbol'' in the already-loaded
library identified by ''loadHandle''. If the symbol is found, a pointer
to its memory address is returned.  Otherwise, NULL is returned, and
an error message is left in ''interp'' (if ''interp'' is not NULL).

A new call, ''Tcl_FSUnloadFile'' shall be introduced and exported in
the external Stubs.Its call signature shall be:

 > EXTERN int
   '''Tcl_FSUnloadFile'''(
       Tcl_Interp *''interp'',
       Tcl_LoadHandle *''loadHandle'');

This call unloads the library identified by ''loadHandle''.  It differs
from the [[unload]] command in that no 'unload' procedure is called; the
library is simply unloaded without first being given a chance to clean
itself up. (This function is a lower-level interface used by [[unload]]
as part of doing its work.) The return value is either TCL_OK or TCL_ERROR;
when TCL_ERROR is returned, an appropriate message is left in the
result of ''interp'' (if ''interp'' is not NULL).

~ Internals

The '''Tcl_LoadHandle''' object shall be represented internally by a
structure, declared in <tclInt.h>, looking like:

| struct Tcl_LoadHandle_ {
|     ClientData clientData;	/* Client data is the load handle in the
| 				 * native filesystem if a module was loaded
| 				 * there, or an opaque pointer to a structure
| 				 * for further bookkeeping on load-from-VFS
| 				 * and load-from-memory */
|     TclFindSymbolProc* findSymbolProcPtr;
| 				/* Procedure that resolves symbols in a
| 				 * loaded module */
|     Tcl_FSUnloadFileProc* unloadFileProcPtr;
| 				/* Procedure that unloads a loaded module */
| }

The ''Tcl_FindSymbolProc'' and ''Tcl_FSUnloadFileProc'' data types are

declared to be functions of the same type signature as ''Tcl_FindSymbol''
and ''Tcl_FSUnloadFile''.

Virtual file systems that implement the ''loadFileProc'' are responsible
for ensuring that their '''Tcl_LoadHandle'' that the ''loadFileProc''
returns conforms with this convention.  As far as the author has been
able to determine, no non-Core filesystem provides anything but NULL
for the ''loadFileProc''. Certainly, tclvfs and trofs do not. Most other
virtual filesystems layer atop tclvfs.  

~ Reference Implementation

A reference implementation is nearing completion, and the draft code is
available attached to [[Patch 2891616]][https://sourceforge.net/support/tracker.php?aid=2891616] at SourceForge.

~ License

This file is explicitly released to the public domain and the author
explicitly disclaims all rights under copyright law.

<
|
<
|
|
|
|
|
|
|
>

|

|
|

|
|
|

|

|




|

|
|


|
|









|
|



|

|



|
|
|
|
|
|
|

|
|
|

|

|

|
|


|
|
|

|



|
|
|

|


|
|
|
|
|

|
|

|

|



|
|
|

|
|

|
|
|
|

|

|


|
|
|
|
|
|
|
|
|
|
|
<
|
|
>
|
|

|
|


|


|


|

|



>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

# TIP 357: Export TclLoadFile

	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        01-Oct-2009
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes to promote the internal calls, _TclLoadFile_ and
_TclpFindSymbol_ to the
external API, making them available to C extensions. In addition, it
proposes to introduce a _Tcl\_FSUnloadFile_ to the VFS layer, removing
the weird duplicate client data from _TclLoadFile_ and wrapping all
necessary data into the **Tcl\_LoadHandle**

# Rationale

In developing TDBC [[308]](308.md), the author of this TIP was advised to look at the
way that the 'oratcl' extension contrives to build on a system where
Oracle is not installed as a model for TDBC extensions.  Examination
of the code revealed that it operates essentially by constructing at
run time a Stubs table for the routines in the Oracle client
library. There is a maze of **\#if** directives selecting whether
this process is accomplished by the system calls that manage Unix .so
files \(_dlopen_ and friends\), Windows .DLL files \(_LoadLibrary_ and
related calls\), HP-UX .shl files \(_shl\_load,_ etc.\), and so on.

Tcl already has functionality so that a caller can abstract away all
this complexity.  It provides the capability in the _TclLoadFile_
call, but this call is **MODULE\_SCOPE** and not exported even in the
internal Stubs table. For this reason, it is entirely unavailable to
TEA-compliant extensions.

If this call were available, it would be feasible, in the 8.6 time frame,
to bundle all the database-specific TDBC drivers with the core TDBC
distribution, since things could be set up so that they will build
anywhere, even in the absence of the databases where they connect.

However, this call was never fully rationalized in the VFS world. Its
strange API \(with both a **Tcl\_LoadHandle** and a **ClientData**,
and a function pointer for unloading the library\) is, as several reviewers
pointed out, not somehting that we want to make available to general callers.
Hence, a few more routines need rework.

# Specification

The _TclLoadFile_ call shall be renamed _Tcl\_LoadFile_ and exported
in the external Stubs.  Its call signature shall be changed to:

 > EXTERN int
   **Tcl\_LoadFile**\(
       Tcl\_Interp \*_interp_,
       Tcl\_Obj \*_pathPtr_,
       const char \*_symbols_[],
       int _flags_,
       void \*_procPtrs_,
       Tcl\_LoadHandle \*_handlePtr_\);

In this call, _interp_ designates an interpreter for error reporting.
_pathPtr_ is an object containing the path of the library to be loaded.
If _pathPtr_ is a single name, the library search path of the current
environment will be used to resolve it.  
The _symbols_ array  contains a NULL-terminated set of
character strings that are the names
of the imported symbols. _symbols_ may be NULL if the library is to be loaded without resolving any symbols.

The return value of _Tcl\_LoadFile_ is a standard Tcl result code. If the
result is TCL\_ERROR, the interpreter result will contain an appropriate
error message.

On return, _Tcl\_LoadFile_ fills in the block of memory commencing
at the address given by _procPtrs_ with the addresses
that correspond to the names in _symbols._ If a name cannot be
resolved in the given library, an error will be returned and all
entries in _procPtrs_ will be invalid. _procPtrs_ may be NULL
if no symbols are to be resolved.

On a successful return,
the _loadHandle_ pointer will be a handle suitable for
passing to _Tcl\_FindSymbol_ for resolving additional symbols in the
library, or to _Tcl\_FSUnloadFile_ to unload the library.

The _TclpFindSymbol_ call shall be renamed _Tcl\_FindSymbol_ and
exported in the external Stubs.  Its call signature shall be:

 > EXTERN void\*
   **Tcl\_FindSymbol**\(
       Tcl\_Interp \*_interp_,
       Tcl\_LoadHandle \*_loadHandle_,
       const char \*_symbol_\);

This call searches for the given _symbol_ in the already-loaded
library identified by _loadHandle_. If the symbol is found, a pointer
to its memory address is returned.  Otherwise, NULL is returned, and
an error message is left in _interp_ \(if _interp_ is not NULL\).

A new call, _Tcl\_FSUnloadFile_ shall be introduced and exported in
the external Stubs.Its call signature shall be:

 > EXTERN int
   **Tcl\_FSUnloadFile**\(
       Tcl\_Interp \*_interp_,
       Tcl\_LoadHandle \*_loadHandle_\);

This call unloads the library identified by _loadHandle_.  It differs
from the [unload] command in that no 'unload' procedure is called; the
library is simply unloaded without first being given a chance to clean
itself up. \(This function is a lower-level interface used by [unload]
as part of doing its work.\) The return value is either TCL\_OK or TCL\_ERROR;
when TCL\_ERROR is returned, an appropriate message is left in the
result of _interp_ \(if _interp_ is not NULL\).

# Internals

The **Tcl\_LoadHandle** object shall be represented internally by a
structure, declared in <tclInt.h>, looking like:

	 struct Tcl_LoadHandle_ {
	     ClientData clientData;	/* Client data is the load handle in the
	 				 * native filesystem if a module was loaded
	 				 * there, or an opaque pointer to a structure
	 				 * for further bookkeeping on load-from-VFS
	 				 * and load-from-memory */
	     TclFindSymbolProc* findSymbolProcPtr;
	 				/* Procedure that resolves symbols in a
	 				 * loaded module */
	     Tcl_FSUnloadFileProc* unloadFileProcPtr;
	 				/* Procedure that unloads a loaded module */

	 }

The _Tcl\_FindSymbolProc_ and _Tcl\_FSUnloadFileProc_ data types are
declared to be functions of the same type signature as _Tcl\_FindSymbol_
and _Tcl\_FSUnloadFile_.

Virtual file systems that implement the _loadFileProc_ are responsible
for ensuring that their **Tcl\_LoadHandle_ that the _loadFileProc_
returns conforms with this convention.  As far as the author has been
able to determine, no non-Core filesystem provides anything but NULL
for the _loadFileProc_. Certainly, tclvfs and trofs do not. Most other
virtual filesystems layer atop tclvfs.  

# Reference Implementation

A reference implementation is nearing completion, and the draft code is
available attached to [Patch 2891616]<https://sourceforge.net/support/tracker.php?aid=2891616>  at SourceForge.

# License

This file is explicitly released to the public domain and the author
explicitly disclaims all rights under copyright law.

Name change from tip/358.tip to tip/358.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

TIP:		358
Title:		Suppress Empty List Element Generation from the Split Command
Version:	$Revision: 1.2 $
Author:		George Petasis <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Created:	04-Oct-2009
Post-History:	
Keywords:	Tcl, list extraction, parsing


~ Abstract

The '''split''' command will create empty list elements when adjacent split
characters are found in the input. In some cases these empty list elements are
not desired, so this TIP proposes a new switch to disable their generation.

~ Rationale

The idea for this TIP came from a discussion in comp.lang.tcl:
[http://groups.google.gr/group/comp.lang.tcl/browse_thread/thread/8d46b0f10e7a5750/d7844cc739aa4310]
and the (non obvious) suggestions on how tokens can be extracted from a string
can be performed efficiently.

It should be noted that this will allow the '''split''' command to be used in
a fashion that is very similar to how splitting works in many other languages
(e.g., Perl, awk, Unix shells).

~ Specification

This TIP proposes a new optional switch ('''-noemptyelements''') to the
'''split''' command:

 > '''split -noemptyelements''' ''string'' ?''splitChars''?

If this option is present, then '''split''' will not produce an empty list
element when the ''string'' contains adjacent characters that are present in
''splitChars''.

~ Reference Implementation

Currently there is no patch, but it should be quite easy to implement this.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|


|
|


|

|

|

|
|

|

|
|
|

|



|


>

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

# TIP 358: Suppress Empty List Element Generation from the Split Command

	Author:		George Petasis <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Created:	04-Oct-2009
	Post-History:	
	Keywords:	Tcl, list extraction, parsing
-----

# Abstract

The **split** command will create empty list elements when adjacent split
characters are found in the input. In some cases these empty list elements are
not desired, so this TIP proposes a new switch to disable their generation.

# Rationale

The idea for this TIP came from a discussion in comp.lang.tcl:
<http://groups.google.gr/group/comp.lang.tcl/browse_thread/thread/8d46b0f10e7a5750/d7844cc739aa4310> 
and the \(non obvious\) suggestions on how tokens can be extracted from a string
can be performed efficiently.

It should be noted that this will allow the **split** command to be used in
a fashion that is very similar to how splitting works in many other languages
\(e.g., Perl, awk, Unix shells\).

# Specification

This TIP proposes a new optional switch \(**-noemptyelements**\) to the
**split** command:

 > **split -noemptyelements** _string_ ?_splitChars_?

If this option is present, then **split** will not produce an empty list
element when the _string_ contains adjacent characters that are present in
_splitChars_.

# Reference Implementation

Currently there is no patch, but it should be quite easy to implement this.

# Copyright

This document has been placed in the public domain.

Name change from tip/359.tip to tip/359.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

TIP:            359
Title:          Extended Window Manager Hint Support
Version:        $Revision: 1.7 $
Author:         Pat Thoyts <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        21-Dec-2009
Post-History:   
Keywords:       Tk,X11,ewmh,window manager
Tcl-Version:    8.6


~ Abstract

The '''wm attributes''' command will be extended to accept a '''-type'''
option when running on the X Window system to manipulate the extended window
manager hints for Tk toplevel windows.

~ Rationale

This enhancement will enable script-level support for setting the extended
window manager hints for Tk toplevel windows as specified in
[http://standards.freedesktop.org/wm-spec/wm-spec-latest.html].  The
'''_NET_WM_WINDOW_TYPE''' hint is used to provide information to the window
manager about the intended use of a window so that appropriate decoration and
animation can be applied. Specific examples of this include the dropdown
listbox used with '''ttk::combobox''', '''tooltips''', splash screens and
application dialog windows. Menus also need the type hint set appropriately
but this has already been handled in the C code in recent commits.

~ Specification

The '''wm attributes''' command for the X11 windowing system will have a new X11 platform-specific '''-type''' option which will return the current list of '''_NET_WM_WINDOW_TYPE''' atoms set for this '''toplevel''' or allow the list to be modified. The set of possible window type names is unconstrained to permit compatibility with future versions of the specification. However the window type names at the script level will be all
lower-case and exclude any '''_NET_WM_WINDOW_TYPE_''' prefix.

As specified in the freedesktop.org document, the property is a list of hints
with the types specified in order of preference as window managers may not implement some types. When setting a hint, the provided name is converted to upper-case, appended to
'''_NET_WM_WINDOW_TYPE_''' and converted to an atom. This permits new hints
that may be specified in the future to be handled without modification to Tk.

The Tk library scripts will set the type for all dialogs created by library
functions and will set the combo hint for the '''ttk::combobox''' dropdown listbox.

This feature is actually needed on 8.5 as well. Under compiz Tk window are
inappropriately animated. The '''combobox''' dropdown in particular tends to
bounce on Ubuntu.

~ Reference Implementation

A patch is available at [https://sourceforge.net/support/tracker.php?aid=2918731].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|



|
|


|



|

|
|



|



|


|


|

|

|


>

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

# TIP 359: Extended Window Manager Hint Support

	Author:         Pat Thoyts <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        21-Dec-2009
	Post-History:   
	Keywords:       Tk,X11,ewmh,window manager
	Tcl-Version:    8.6
-----

# Abstract

The **wm attributes** command will be extended to accept a **-type**
option when running on the X Window system to manipulate the extended window
manager hints for Tk toplevel windows.

# Rationale

This enhancement will enable script-level support for setting the extended
window manager hints for Tk toplevel windows as specified in
<http://standards.freedesktop.org/wm-spec/wm-spec-latest.html> .  The
**\_NET\_WM\_WINDOW\_TYPE** hint is used to provide information to the window
manager about the intended use of a window so that appropriate decoration and
animation can be applied. Specific examples of this include the dropdown
listbox used with **ttk::combobox**, **tooltips**, splash screens and
application dialog windows. Menus also need the type hint set appropriately
but this has already been handled in the C code in recent commits.

# Specification

The **wm attributes** command for the X11 windowing system will have a new X11 platform-specific **-type** option which will return the current list of **\_NET\_WM\_WINDOW\_TYPE** atoms set for this **toplevel** or allow the list to be modified. The set of possible window type names is unconstrained to permit compatibility with future versions of the specification. However the window type names at the script level will be all
lower-case and exclude any **\_NET\_WM\_WINDOW\_TYPE\_** prefix.

As specified in the freedesktop.org document, the property is a list of hints
with the types specified in order of preference as window managers may not implement some types. When setting a hint, the provided name is converted to upper-case, appended to
**\_NET\_WM\_WINDOW\_TYPE\_** and converted to an atom. This permits new hints
that may be specified in the future to be handled without modification to Tk.

The Tk library scripts will set the type for all dialogs created by library
functions and will set the combo hint for the **ttk::combobox** dropdown listbox.

This feature is actually needed on 8.5 as well. Under compiz Tk window are
inappropriately animated. The **combobox** dropdown in particular tends to
bounce on Ubuntu.

# Reference Implementation

A patch is available at <https://sourceforge.net/support/tracker.php?aid=2918731> .

# Copyright

This document has been placed in the public domain.

Name change from tip/36.tip to tip/36.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

TIP:		36
Title:		Library Access to 'Subst' Functionality
Version:	$Revision: 1.4 $
Author:		Donal K. Fellows <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.4
Vote:		Done
Created:	13-Jun-2001
Post-History:	


~ Abstract

Some applications make very heavy use of the ''subst'' command - it
seems particularly popular in the active-content-generation field -
and for them it is important to optimise this as much as possible.
This TIP adds a direct interface to these capabilities to the Tcl
library, allowing programmers to avoid the modest overheads of even
''Tcl_EvalObjv'' and the option parser for the ''subst'' command
implementation.

~ Functionality Changes

There will be one script-visible functionality change from the current
implementation; if the evaluation of any command substitution returns
TCL_BREAK, then the result of the ''subst'' command will be the string
up to that point and no further.  This contrasts with the current
behaviour where TCL_BREAK (like TCL_CONTINUE) just causes the current
command substitution to finish early.

~ Design Decisions

The code should be created by effectively splitting
''Tcl_SubstObjCmd'' in the current ''.../generic/tclCmdMZ.c'' into two
pieces.  One of these pieces will have the same interface as the
present code and will contain the argument parser.  The other piece
will be the implementation of the ''subst'' behaviour and will be
separately exposed at the C level as well as being called by the
front-end code.

The code should take positive flags stating what kinds of
substitutions should be performed, as this is closest to the current
internal implementation of the ''subst'' command.  These flags will be
named with the prefix TCL_SUBST_*.  For programming convenience, the
flag TCL_SUBST_ALL will also be provided allowing the common case of
wanting all substitutions to be performed with a minimum of fuss.

The string to be substituted will be passed in as a ''Tcl_Obj *'' too,
as this is both easiest to do from the point-of-view of the front-end
code and permits additional optimisation of the core at some future
point if it proves necessary and/or desirable.  By contrast, passing
in a standard C string or a ''Tcl_DString *'' does not permit any such
optimisations in the future.

The code should return a newly-allocated ''Tcl_Obj *'' as this allows
for the efficient implementation of the front-end involving no
re-copying of the resulting string.  It also allows error conditions
to be represented by NULL (with an error message in the interpreter
result) and does not force a Tcl_DString reference to be passed in as
an ''out'' parameter; returning the result gives a much clearer call
semantics.  Another advantage of using ''Tcl_Obj''s to build the
result is the fact that they have a more sophisticated memory
allocation algorithm that copes more efficiently with very large
strings; when large and small strings are being combined together (as
is easily the case in ''subst'') this can make a substantial
difference.

~ Public Interface

''Added to .../generic/tcl.h''

|#define TCL_SUBST_COMMANDS    0x01
|#define TCL_SUBST_VARIABLES   0x02
|#define TCL_SUBST_BACKSLASHES 0x04
|#define TCL_SUBST_ALL         0x07

''Added to .../generic/tcl.decls''

|declare someNumber generic {
|    Tcl_Obj * Tcl_SubstObj( Tcl_Interp *interp,
|                            Tcl_Obj *objPtr,
|                            int flags)
|}


~ Implementation

The implementation is to be developed upon acceptance of this TIP, but
will involve ''Tcl_AppendToObj'' and ''Tcl_AppendObjToObj''.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|




|


|



|

|


|


|


|





|
|
|


|



|


|


|
|
|
|


|
|


|

|

|
|
|
|

|

|
|
|
|
<
|
>
|


|

|


>

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

# TIP 36: Library Access to 'Subst' Functionality

	Author:		Donal K. Fellows <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.4
	Vote:		Done
	Created:	13-Jun-2001
	Post-History:	
-----

# Abstract

Some applications make very heavy use of the _subst_ command - it
seems particularly popular in the active-content-generation field -
and for them it is important to optimise this as much as possible.
This TIP adds a direct interface to these capabilities to the Tcl
library, allowing programmers to avoid the modest overheads of even
_Tcl\_EvalObjv_ and the option parser for the _subst_ command
implementation.

# Functionality Changes

There will be one script-visible functionality change from the current
implementation; if the evaluation of any command substitution returns
TCL\_BREAK, then the result of the _subst_ command will be the string
up to that point and no further.  This contrasts with the current
behaviour where TCL\_BREAK \(like TCL\_CONTINUE\) just causes the current
command substitution to finish early.

# Design Decisions

The code should be created by effectively splitting
_Tcl\_SubstObjCmd_ in the current _.../generic/tclCmdMZ.c_ into two
pieces.  One of these pieces will have the same interface as the
present code and will contain the argument parser.  The other piece
will be the implementation of the _subst_ behaviour and will be
separately exposed at the C level as well as being called by the
front-end code.

The code should take positive flags stating what kinds of
substitutions should be performed, as this is closest to the current
internal implementation of the _subst_ command.  These flags will be
named with the prefix TCL\_SUBST\_\*.  For programming convenience, the
flag TCL\_SUBST\_ALL will also be provided allowing the common case of
wanting all substitutions to be performed with a minimum of fuss.

The string to be substituted will be passed in as a _Tcl\_Obj \*_ too,
as this is both easiest to do from the point-of-view of the front-end
code and permits additional optimisation of the core at some future
point if it proves necessary and/or desirable.  By contrast, passing
in a standard C string or a _Tcl\_DString \*_ does not permit any such
optimisations in the future.

The code should return a newly-allocated _Tcl\_Obj \*_ as this allows
for the efficient implementation of the front-end involving no
re-copying of the resulting string.  It also allows error conditions
to be represented by NULL \(with an error message in the interpreter
result\) and does not force a Tcl\_DString reference to be passed in as
an _out_ parameter; returning the result gives a much clearer call
semantics.  Another advantage of using _Tcl\_Obj_s to build the
result is the fact that they have a more sophisticated memory
allocation algorithm that copes more efficiently with very large
strings; when large and small strings are being combined together \(as
is easily the case in _subst_\) this can make a substantial
difference.

# Public Interface

_Added to .../generic/tcl.h_

	#define TCL_SUBST_COMMANDS    0x01
	#define TCL_SUBST_VARIABLES   0x02
	#define TCL_SUBST_BACKSLASHES 0x04
	#define TCL_SUBST_ALL         0x07

_Added to .../generic/tcl.decls_

	declare someNumber generic {
	    Tcl_Obj * Tcl_SubstObj( Tcl_Interp *interp,
	                            Tcl_Obj *objPtr,
	                            int flags)

	}

# Implementation

The implementation is to be developed upon acceptance of this TIP, but
will involve _Tcl\_AppendToObj_ and _Tcl\_AppendObjToObj_.

# Copyright

This document has been placed in the public domain.

Name change from tip/360.tip to tip/360.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

TIP:		360
Title:		Modernize X11 Menus
Author:		Pat Thoyts <[email protected]>
Type:		Project
State:		Final
Vote:		Done
Created:	24-Dec-2009
Version:	$Revision: 1.5 $
Tcl-Version:	8.6
Keywords:	Tk, X11, menu
Post-History:	


~ Abstract

This TIP proposes to modernize the functionality of the Tk menus on X11 to
bring Tk up to date with reference to other toolkits on this platform.

~ Rationale

Motif is dead and buried but Tk menus are still aping the Motif feel for
'''menu''' handling on X11. Specifically all cascade menu items must be
actively clicked to open the submenu. Other current toolkits work more like
the Windows menus where once one of the menubar items has been clicked to
activate its dropdown then subsequent mouse motion is sufficient to open any
cascade menu on the menubar or from any of its dropdown menus.

Tk provides magic handling for any menubar item whose name ends in
'''.help'''. Specifically such a menu gets pinned to the extreme right of the
menubar. This is sufficiently unusual that users often miss the help menu
completely if they are used to Windows or GNOME applications. This is a
hangover from 1990 and needs to go.

~ Specification

The menu bindings will be modified to provide a concept of an activated
menubar. Once any of the menubar cascade entries has been activated then the
current active item will follow the mouse motion and explicit clicks will not
be required to activate cascade entries. A small delay will be included when
posting a cascade entry except when posting from the menubar. The activation
is cancelled on hitting escape, selecting a menu entry or clicking outside the
menu.

If the new 'focus-follows-mouse' style behaviour is undesirable it can be
disabled using the Tk options database. The Menu option '''clickToFocus''' may
be set true to restore the original menu behaviour. This can be set using the
Tk '''option''' command, the X resource database, or by calling
'''tk::classic::restore menu'''.

The special handling of '''.help''' menu entries in the menubar will be
removed unless restored using the resource option '''*Menu.useMotifHelp'''.
This can be set using the Tk '''option''' command, the X resource database or
by calling the '''tk::classic::restore''' command which will set the option
along with some others.

~ Reference Implementation

Patches posted as Tk patch item #2920409
[https://sourceforge.net/support/tracker.php?aid=2920409].

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|




|


|






|




|










|

|
|

|
|
|
|


|

|
|

|


>

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

# TIP 360: Modernize X11 Menus
	Author:		Pat Thoyts <[email protected]>
	Type:		Project
	State:		Final
	Vote:		Done
	Created:	24-Dec-2009

	Tcl-Version:	8.6
	Keywords:	Tk, X11, menu
	Post-History:	
-----

# Abstract

This TIP proposes to modernize the functionality of the Tk menus on X11 to
bring Tk up to date with reference to other toolkits on this platform.

# Rationale

Motif is dead and buried but Tk menus are still aping the Motif feel for
**menu** handling on X11. Specifically all cascade menu items must be
actively clicked to open the submenu. Other current toolkits work more like
the Windows menus where once one of the menubar items has been clicked to
activate its dropdown then subsequent mouse motion is sufficient to open any
cascade menu on the menubar or from any of its dropdown menus.

Tk provides magic handling for any menubar item whose name ends in
**.help**. Specifically such a menu gets pinned to the extreme right of the
menubar. This is sufficiently unusual that users often miss the help menu
completely if they are used to Windows or GNOME applications. This is a
hangover from 1990 and needs to go.

# Specification

The menu bindings will be modified to provide a concept of an activated
menubar. Once any of the menubar cascade entries has been activated then the
current active item will follow the mouse motion and explicit clicks will not
be required to activate cascade entries. A small delay will be included when
posting a cascade entry except when posting from the menubar. The activation
is cancelled on hitting escape, selecting a menu entry or clicking outside the
menu.

If the new 'focus-follows-mouse' style behaviour is undesirable it can be
disabled using the Tk options database. The Menu option **clickToFocus** may
be set true to restore the original menu behaviour. This can be set using the
Tk **option** command, the X resource database, or by calling
**tk::classic::restore menu**.

The special handling of **.help** menu entries in the menubar will be
removed unless restored using the resource option **\*Menu.useMotifHelp**.
This can be set using the Tk **option** command, the X resource database or
by calling the **tk::classic::restore** command which will set the option
along with some others.

# Reference Implementation

Patches posted as Tk patch item \#2920409
<https://sourceforge.net/support/tracker.php?aid=2920409> .

# Copyright

This document has been placed in the public domain.

Name change from tip/361.tip to tip/361.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

TIP:		361
Title:		Releasing Channel Buffers
Version:	$Revision: 1.3 $
Author:		Wayne Cuddy <[email protected]>
State:		Draft
Type:		Project
Vote:		Pending
Created:	03-Feb-2010
Tcl-Version:	8.7
Post-History:


~ Abstract

Tcl should provide a mechanism by which a channel's output buffer can be
released without requiring that Tcl flush any remaining data in the buffer to
the operating system. This is of particular interest with output mechanisms
which can block indefinitely causing the interpreter to consume unnecessary
resources or prevent the interpreter from exiting.

~ Problem

When working with processes that handle multiplexing/non-blocking I/O it is
not uncommon to write, or call '''puts''', with more data than the operating
system will accept. Thus Tcl begins to buffer this data using internal buffers
at the application level and flushes the data in the background. Problems
arise when the consumer of this data, be it the other end of a socket, pipe or
FIFO, refuse to read data and do not close the channel.

This has adverse effects on the '''close''' function and consequently the
interpreter/process when it attempts to flush and close channels during
finalization.

~~ Consequences

   1. When '''close''' is issued on a non-blocking channel Tcl removes the
      channel from pool of accessible channels from the current interpreter
      and attempts to flush any remaining data in the output buffers before
      closing the channel. Since the other end of the channel is not consuming
      data Tcl will never be able to flush it's internal buffers nor close the
      lower level channel driver. In a multiplexing server which opens new
      channels this will eventually result in resource starvation or denial of
      service.

   2. When '''exit''' is called Tcl attempts to flush all output buffers, if
      any open channel blocks the interpreter will be unable exit and must be
      forcibly terminated by OS specific mechanisms.

~ Propose API Additions

Provide a function and/or flags to existing functions which can be used to
clear internal buffers without flushing.

   * '''chan clear''' ''channelId''

   * '''close -noflush''' ''channelId''

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|







|


|





|



|

|








|



|




|

|

|


>

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

# TIP 361: Releasing Channel Buffers

	Author:		Wayne Cuddy <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		Pending
	Created:	03-Feb-2010
	Tcl-Version:	8.7
	Post-History:
-----

# Abstract

Tcl should provide a mechanism by which a channel's output buffer can be
released without requiring that Tcl flush any remaining data in the buffer to
the operating system. This is of particular interest with output mechanisms
which can block indefinitely causing the interpreter to consume unnecessary
resources or prevent the interpreter from exiting.

# Problem

When working with processes that handle multiplexing/non-blocking I/O it is
not uncommon to write, or call **puts**, with more data than the operating
system will accept. Thus Tcl begins to buffer this data using internal buffers
at the application level and flushes the data in the background. Problems
arise when the consumer of this data, be it the other end of a socket, pipe or
FIFO, refuse to read data and do not close the channel.

This has adverse effects on the **close** function and consequently the
interpreter/process when it attempts to flush and close channels during
finalization.

## Consequences

   1. When **close** is issued on a non-blocking channel Tcl removes the
      channel from pool of accessible channels from the current interpreter
      and attempts to flush any remaining data in the output buffers before
      closing the channel. Since the other end of the channel is not consuming
      data Tcl will never be able to flush it's internal buffers nor close the
      lower level channel driver. In a multiplexing server which opens new
      channels this will eventually result in resource starvation or denial of
      service.

   2. When **exit** is called Tcl attempts to flush all output buffers, if
      any open channel blocks the interpreter will be unable exit and must be
      forcibly terminated by OS specific mechanisms.

# Propose API Additions

Provide a function and/or flags to existing functions which can be used to
clear internal buffers without flushing.

   * **chan clear** _channelId_

   * **close -noflush** _channelId_

# Copyright

This document has been placed in the public domain.

Name change from tip/362.tip to tip/362.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

TIP:            362
Title:          Simple 32 and 64 bit Registry Support
Version:        $Revision: 1.9 $
Author:         Damon Courtney <[email protected]>
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        01-Mar-2010
Post-History:   
Keywords:       Windows,Tcl
Tcl-Version:    8.6


~ Abstract

Add new options to the '''registry''' command on Windows to allow it to
specify that the action should be taken specifically on the 32 or 64 bit
registry.

~Rationale

When Microsoft created a 64 bit version of Windows they had this idea of
separating certain areas of the registry into a new node for 32 bit programs
to access. The idea was that 64 bit programs would use the standard keys while
32 bit programs living in the 64 bit world would have their registry access
shuffled off to a separate node behind their backs. By default, a 32 bit
program will get the 32 bit registry node and a 64 bit program will get the 64
bit nodes, and in Tcl, this is what we're currently left to. It is possible to
specify which registry you want to use through flags to the various registry
commands, Tcl's '''registry''' command just doesn't know anything about them
currently.

~Specification

The '''registry''' command will receive two new (mutually exclusive) options
to specify that the given '''registry''' command should be executed against
the 32 bit or 64 bit registry. The proposed implementation is the addition of
a '''-32bit''' and a '''-64bit''' option, one of which may be placed before
the ''subcommand'' like so:

 > '''package require registry 1.3'''

 > '''registry''' ?'''-32bit'''|'''-64bit'''? ''subcommand'' ?''options''?

By default, no option will mean that the '''registry''' command does what it
has always done, which is to operate on the registry that matches the current
compiled version of the running Tcl. Specifying '''-32bit''' means to operate
on the 32 bit registry regardless of the current binary, and '''-64bit'''
means to operate on the 64 bit registry. The options will be supported by all
subcommands of '''registry'''.

Concurrently with this change, the version number of the '''registry''' package will be advanced to 1.3.

~Reference Implementation

See Patch #2960976 at SourceForge
[https://sourceforge.net/support/tracker.php?aid=2960976].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|



|









|


|

|
|

|
|

|

|

|

|
|

|

|

|

|
|

|


>

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

# TIP 362: Simple 32 and 64 bit Registry Support

	Author:         Damon Courtney <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        01-Mar-2010
	Post-History:   
	Keywords:       Windows,Tcl
	Tcl-Version:    8.6
-----

# Abstract

Add new options to the **registry** command on Windows to allow it to
specify that the action should be taken specifically on the 32 or 64 bit
registry.

# Rationale

When Microsoft created a 64 bit version of Windows they had this idea of
separating certain areas of the registry into a new node for 32 bit programs
to access. The idea was that 64 bit programs would use the standard keys while
32 bit programs living in the 64 bit world would have their registry access
shuffled off to a separate node behind their backs. By default, a 32 bit
program will get the 32 bit registry node and a 64 bit program will get the 64
bit nodes, and in Tcl, this is what we're currently left to. It is possible to
specify which registry you want to use through flags to the various registry
commands, Tcl's **registry** command just doesn't know anything about them
currently.

# Specification

The **registry** command will receive two new \(mutually exclusive\) options
to specify that the given **registry** command should be executed against
the 32 bit or 64 bit registry. The proposed implementation is the addition of
a **-32bit** and a **-64bit** option, one of which may be placed before
the _subcommand_ like so:

 > **package require registry 1.3**

 > **registry** ?**-32bit**\|**-64bit**? _subcommand_ ?_options_?

By default, no option will mean that the **registry** command does what it
has always done, which is to operate on the registry that matches the current
compiled version of the running Tcl. Specifying **-32bit** means to operate
on the 32 bit registry regardless of the current binary, and **-64bit**
means to operate on the 64 bit registry. The options will be supported by all
subcommands of **registry**.

Concurrently with this change, the version number of the **registry** package will be advanced to 1.3.

# Reference Implementation

See Patch \#2960976 at SourceForge
<https://sourceforge.net/support/tracker.php?aid=2960976> .

# Copyright

This document has been placed in the public domain.

Name change from tip/363.tip to tip/363.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

TIP:		363
Title:		Vector Math in the Tcl Core
Version:	$Revision: 1.1 $
Author:		Karl C. Hansen <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	9.0
Vote:		Pending
Created:	02-Mar-2010
Post-History:	
Keywords:	expand,{*},vector,math


~ Abstract

The "expand" operator - '''{*}''' - was adopted in Tcl 8.5 and is very useful
for simplifying code involving lists.  It is proposed to add this operator to
the list of actions performed during processing of double-quote ("), joining
the '''$''', '''[[''', and '''\''', and to modify the behavior of '''$''' in
variable substitution.  The proposed behavior ''will'' break existing
substitution, but a trivial quoted-string substitution restores original
behavior with the new approach. The proposed approach will enable eventual
incorporation of vector-math to the Tcl engine without changing any of the
existing syntax.

~ Rationale

It is desired to enhance the current math engine in TCL to handle vector math,
without having to create new syntax or add cumbersome new function calls.
Given the assignments '''set ScalarA 1''', '''set ScalarB 2''', '''set ListA
{1 2 3}''', and '''set ListB {4 5 6}''', evaluating '''$ScalarA + $ScalarB''',
'''$ListA + $ListB''', and '''$ListA + $ScalarB''' would all be trivially
understandable, with the first behaving as currently implemented, the second
returning a list containing the element-by-element sums of the two lists, and
the third returning a list containing the elements of ListA incremented by the
common ScalarB.

With the proposed enhancement (see below) the expression parser would receive
a brace-delimited set of values wherever the lists appear, and a single value
wherever the scalars appear.

With the proposed enhancement, and a vector-math core enhancement, given the
assignments above, the following would behave identically:

|expr $ListA + {4 5 6}
|expr $ListA + $ListB
|expr {1 2 3} + $ListB
|expr {1 2 3} + {4 5 6}

With the proposed enhancement, incorporating vector math into the TCL core is
vastly simplified, reducing to enhancing the current math handlers to perform
different actions based on whether they received lists or scalars or both, and
checking that the vectors have the appropriate element counts for the
operation specified.

~ Proposal

 1. Add expansion -- '''{*}''' -- to set of actions performed during double-quote processing.

 > 1. Treat expand operator as a single character 'tri-graph'.

 > 2. Escape the operator -- '''\{*}''' -- to turn it into "regular text"
      causing it to behave as it currently does during double-quote
      processing. Note that this is identical with the current behavior of
      escape, i.e., '''\{''' currently gives '''{'''.  With the new
      implementation it turns the expand operator into normal text inside of a
      quoted string.

 2. Modify '''$''' substitution so that ''lists'' are enclosed in braces
    during substitution, i.e. after '''set A {1 2}''' execution of '''puts
    "$A"''' yields '''{1 2}''' instead of '''1 2''' as it currently does.
    Note that this behavior only manifests inside of quoted strings, as the
    assignment '''set B $A''' still gives the same results as the original
    implementation, i.e. assigning a list to '''B'''.

 > 1. Prefix '''$''' with expand '''{*}''' to restore current behavior, i.e.,
   with the same assignment above, execution of '''puts "{*}$A"''' yields '''1
   2''' instead of '''{*}1 2''' as it currently does.  Note that this provides
   a fairly simple way to fix scripts broken by implementing this proposal.
   If exising scripts contain quoted lists, simply (a) replace all
   double-quoted occurrances of '''{*}''' with '''\{*}''', and (b) replace all
   double-quoted occurrances of '''$''' with '''{*}$'''.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|

|
|
|





|



|
|
|





|






|
|
|
|







|

|

|

|


|



|
|
|

|
|

|
|
|

|
|
|

|


>

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

# TIP 363: Vector Math in the Tcl Core

	Author:		Karl C. Hansen <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	9.0
	Vote:		Pending
	Created:	02-Mar-2010
	Post-History:	
	Keywords:	expand,{*},vector,math
-----

# Abstract

The "expand" operator - **\{\*\}** - was adopted in Tcl 8.5 and is very useful
for simplifying code involving lists.  It is proposed to add this operator to
the list of actions performed during processing of double-quote \("\), joining
the **$**, **[**, and **\\**, and to modify the behavior of **$** in
variable substitution.  The proposed behavior _will_ break existing
substitution, but a trivial quoted-string substitution restores original
behavior with the new approach. The proposed approach will enable eventual
incorporation of vector-math to the Tcl engine without changing any of the
existing syntax.

# Rationale

It is desired to enhance the current math engine in TCL to handle vector math,
without having to create new syntax or add cumbersome new function calls.
Given the assignments **set ScalarA 1**, **set ScalarB 2**, **set ListA
\{1 2 3\}**, and **set ListB \{4 5 6\}**, evaluating **$ScalarA \+ $ScalarB**,
**$ListA \+ $ListB**, and **$ListA \+ $ScalarB** would all be trivially
understandable, with the first behaving as currently implemented, the second
returning a list containing the element-by-element sums of the two lists, and
the third returning a list containing the elements of ListA incremented by the
common ScalarB.

With the proposed enhancement \(see below\) the expression parser would receive
a brace-delimited set of values wherever the lists appear, and a single value
wherever the scalars appear.

With the proposed enhancement, and a vector-math core enhancement, given the
assignments above, the following would behave identically:

	expr $ListA + {4 5 6}
	expr $ListA + $ListB
	expr {1 2 3} + $ListB
	expr {1 2 3} + {4 5 6}

With the proposed enhancement, incorporating vector math into the TCL core is
vastly simplified, reducing to enhancing the current math handlers to perform
different actions based on whether they received lists or scalars or both, and
checking that the vectors have the appropriate element counts for the
operation specified.

# Proposal

 1. Add expansion -- **\{\*\}** -- to set of actions performed during double-quote processing.

	 > 1. Treat expand operator as a single character 'tri-graph'.

	 > 2. Escape the operator -- **\\\{\*\}** -- to turn it into "regular text"
      causing it to behave as it currently does during double-quote
      processing. Note that this is identical with the current behavior of
      escape, i.e., **\\\{** currently gives **\{**.  With the new
      implementation it turns the expand operator into normal text inside of a
      quoted string.

 2. Modify **$** substitution so that _lists_ are enclosed in braces
    during substitution, i.e. after **set A \{1 2\}** execution of **puts
    "$A"** yields **\{1 2\}** instead of **1 2** as it currently does.
    Note that this behavior only manifests inside of quoted strings, as the
    assignment **set B $A** still gives the same results as the original
    implementation, i.e. assigning a list to **B**.

	 > 1. Prefix **$** with expand **\{\*\}** to restore current behavior, i.e.,
   with the same assignment above, execution of **puts "\{\*\}$A"** yields **1
   2** instead of **\{\*\}1 2** as it currently does.  Note that this provides
   a fairly simple way to fix scripts broken by implementing this proposal.
   If exising scripts contain quoted lists, simply \(a\) replace all
   double-quoted occurrances of **\{\*\}** with **\\\{\*\}**, and \(b\) replace all
   double-quoted occurrances of **$** with **\{\*\}$**.

# Copyright

This document has been placed in the public domain.

Name change from tip/364.tip to tip/364.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

TIP:		364
Title:		Threading Support: Configuration and Package
Author:		Donal K. Fellows <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Post-History:	
Version:	$Revision: 1.4 $
Created:	19-Mar-2010
Keywords:	Tcl


~ Abstract

This TIP changes the the default configuration for building to threaded on all
platforms where this is not already the case (primarily Unix other than MacOS
X) and adds the Thread package to the set of packages included by default.

~ Rationale

As the world of hardware changes, it is becoming clear that modern computers
will increasingly have multiple CPU cores available to them. This is driven by
the fact that it is easier for the manufacturers of processors to make them
able to do more by increasing the number of cores than by increasing the speed
of those cores. It is therefore a strongly-desirable thing to have Tcl able to
utilize these resources and, naturally, in a cross-platform way.

Threading is actually an area of considerable strength for Tcl. In particular,
we have supported a threaded build of Tcl on all platforms since Tcl 8.1, and
the performance cost of this is now minimal. In addition, the Thread package
has been in use in production for a long time and provides script-level access
to threading facilities. All that we need to do to fully enable Tcl 8.6 for
threading for all scripts is to make the Thread package into a standard
contributed package and ensure that it can be used on all our main supported
platforms. It is this which this TIP proposes.

~ Proposed Change

All that is required is to make the Thread package into one of the packages
that is handled through the contributed package mechanism (c.f., [[incr Tcl]]
[50], TDBC [308]), by locating a copy of it in the ''pkgs/'' directory of the
Tcl sources. However, to make this meaningful it is also necessary to alter
the default configuration of Tcl to be threaded. This will have no effect on
Windows and OSX, where threaded configurations are default anyway, but will
have an impact on other Unixes (Linux, Solaris, etc.) The threaded
configuration has had extensive testing over many years on all platforms, so
it is known that a majority of Tcl scripts will be wholly unaffected by this.

The main issues arising from this relate to the Expect and TclX packages. This
is because they make '''fork''' and '''signal''' commands available; these
APIs are troublesome because of how they interact with Tcl's notifier and the
POSIX Thread system in general. However, the importance of threading as a
general facility means that it is going to be more important to alter those
packages than to keep Tcl defaulting to unthreaded.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
|
<
|
|
>

|


|
|

|

















|


|
|



|




|





|


>

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

# TIP 364: Threading Support: Configuration and Package
	Author:		Donal K. Fellows <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Done
	Post-History:	

	Created:	19-Mar-2010
	Keywords:	Tcl
-----

# Abstract

This TIP changes the the default configuration for building to threaded on all
platforms where this is not already the case \(primarily Unix other than MacOS
X\) and adds the Thread package to the set of packages included by default.

# Rationale

As the world of hardware changes, it is becoming clear that modern computers
will increasingly have multiple CPU cores available to them. This is driven by
the fact that it is easier for the manufacturers of processors to make them
able to do more by increasing the number of cores than by increasing the speed
of those cores. It is therefore a strongly-desirable thing to have Tcl able to
utilize these resources and, naturally, in a cross-platform way.

Threading is actually an area of considerable strength for Tcl. In particular,
we have supported a threaded build of Tcl on all platforms since Tcl 8.1, and
the performance cost of this is now minimal. In addition, the Thread package
has been in use in production for a long time and provides script-level access
to threading facilities. All that we need to do to fully enable Tcl 8.6 for
threading for all scripts is to make the Thread package into a standard
contributed package and ensure that it can be used on all our main supported
platforms. It is this which this TIP proposes.

# Proposed Change

All that is required is to make the Thread package into one of the packages
that is handled through the contributed package mechanism \(c.f., [incr Tcl]
[[50]](50.md), TDBC [[308]](308.md)\), by locating a copy of it in the _pkgs/_ directory of the
Tcl sources. However, to make this meaningful it is also necessary to alter
the default configuration of Tcl to be threaded. This will have no effect on
Windows and OSX, where threaded configurations are default anyway, but will
have an impact on other Unixes \(Linux, Solaris, etc.\) The threaded
configuration has had extensive testing over many years on all platforms, so
it is known that a majority of Tcl scripts will be wholly unaffected by this.

The main issues arising from this relate to the Expect and TclX packages. This
is because they make **fork** and **signal** commands available; these
APIs are troublesome because of how they interact with Tcl's notifier and the
POSIX Thread system in general. However, the importance of threading as a
general facility means that it is going to be more important to alter those
packages than to keep Tcl defaulting to unthreaded.

# Copyright

This document has been placed in the public domain.

Name change from tip/365.tip to tip/365.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

TIP:		365
Title:		Add Python Compatibility Mode
State:		Draft
Type:		Project
Tcl-Version:	8.6
Vote:		No voting
Post-History:	
Version:	$Revision: 1.2 $
Author:		Donal K. Fellows <[email protected]>
Created:	01-Apr-2010
Keywords:	Look at the date


~ Abstract

This TIP adds support for reading and evaluating code written in Python to the
''tclsh'' interpreter.

~ Rationale

There is a lot of Python code out there, all of which suffers from the problem
that the implementation quality of those interpreters is distinctly below what
any reasonable person would consider "production".  This presents a major
opportunity for the well-known dynamic Tcl community to provide people across
the whole world the power of Tcl (especially through the new '''case'''
command) while requiring no changes on the users part other than a simple
recoding of the calling sequence for their code.

~ Proposed Change

A '''PythonLanguageCompatibility''' package will be provided. Upon being
'''package require'''d, the remainder of the script will be evaluated in the
Python language. This enables simple programs like this to be written:

| package require Tcl 8.6
| interp create worker
| $worker eval {
|     package require PythonLanguageCompatibility
|     romanDgts= 'ivxlcdmVXLCDM_'
|     def ToRoman(num):
|       namoR = ''
|       if num >=4000000:
|         print 'Too Big -'
|         return '-----'
|       for rdix in range(0, len(romanDgts), 2):
|         if num==0: break
|         num,r = divmod(num,10)
|         v,r = divmod(r, 5)
|         if r==4:
|           namoR += romanDgts[rdix+1+v] + romanDgts[rdix]
|         else:
|           namoR += r*romanDgts[rdix] + (romanDgts[rdix+1] if(v==1) else '')
|       return namoR[-1::-1]
| }

| interp alias {} ToRoman $worker ToRoman
| after 100 {package require PythonLanguageCompatibility}
| after 200 {package forget PythonLanguageCompatibility}
| for {set i 0} {$i < 10000} {incr i} {
|    try {
|       print '%x - %s'%(i,ToRoman(i))
|    } trap {LANGUAGE WRONG} {} {
|       puts "$i was not printed as a roman number"
|    }
| }



Clearly this allows the intermixing of both Tcl's and Python's strengths with
minimal effort on users' parts.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|


|

|





|
|


|

|
|


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
<
<
|
>
>



|


>

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

# TIP 365: Add Python Compatibility Mode
	State:		Draft
	Type:		Project
	Tcl-Version:	8.6
	Vote:		No voting
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	01-Apr-2010
	Keywords:	Look at the date
-----

# Abstract

This TIP adds support for reading and evaluating code written in Python to the
_tclsh_ interpreter.

# Rationale

There is a lot of Python code out there, all of which suffers from the problem
that the implementation quality of those interpreters is distinctly below what
any reasonable person would consider "production".  This presents a major
opportunity for the well-known dynamic Tcl community to provide people across
the whole world the power of Tcl \(especially through the new **case**
command\) while requiring no changes on the users part other than a simple
recoding of the calling sequence for their code.

# Proposed Change

A **PythonLanguageCompatibility** package will be provided. Upon being
**package require**d, the remainder of the script will be evaluated in the
Python language. This enables simple programs like this to be written:

	 package require Tcl 8.6
	 interp create worker
	 $worker eval {
	     package require PythonLanguageCompatibility
	     romanDgts= 'ivxlcdmVXLCDM_'
	     def ToRoman(num):
	       namoR = ''
	       if num >=4000000:
	         print 'Too Big -'
	         return '-----'
	       for rdix in range(0, len(romanDgts), 2):
	         if num==0: break
	         num,r = divmod(num,10)
	         v,r = divmod(r, 5)
	         if r==4:
	           namoR += romanDgts[rdix+1+v] + romanDgts[rdix]
	         else:
	           namoR += r*romanDgts[rdix] + (romanDgts[rdix+1] if(v==1) else '')
	       return namoR[-1::-1]

	 }
	 interp alias {} ToRoman $worker ToRoman
	 after 100 {package require PythonLanguageCompatibility}
	 after 200 {package forget PythonLanguageCompatibility}
	 for {set i 0} {$i < 10000} {incr i} {
	    try {
	       print '%x - %s'%(i,ToRoman(i))
	    } trap {LANGUAGE WRONG} {} {
	       puts "$i was not printed as a roman number"


	    }
	 }

Clearly this allows the intermixing of both Tcl's and Python's strengths with
minimal effort on users' parts.

# Copyright

This document has been placed in the public domain.

Name change from tip/366.tip to tip/366.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

TIP:            366
Title:          Variable Sized Indicators for Menubuttons
Version:        $Revision: 1.4 $
Author:         Russell Davidson <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        29-Apr-2010
Post-History:   
Keywords:       Tk
Tcl-Version:    8.7


~ Abstract

This TIP is to allow custom sizing of menubutton indicators using
'''-indwidth''' and '''-indheight''' as options.

~ Rationale

Currently there is no way to vary the size of the indicator for a classic Unix
menubutton widget.  Adding the ability to control this via configuration
options will give the coder more control over a GUI's appearance for when such
fine control is required.

~ Specification

The following options are proposed to be added to the '''::menubutton'''
widget:

 > The '''-indwidth''' option allows the specification of the width of the
   indicator in 10ths of a mm (will be converted to an integer number of pixels).

 > The '''-indheight''' option allows the specification of the height of the
   indicator in 10ths of a mm (will be converted to an integer number of pixels).

~ Implementation

A patch exists in SourceForge (Feature Request 2996760
[https://sourceforge.net/support/tracker.php?aid=2996760]).

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|

|






|

|


|
|

|
|

|

|
|

|


>

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

# TIP 366: Variable Sized Indicators for Menubuttons

	Author:         Russell Davidson <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        29-Apr-2010
	Post-History:   
	Keywords:       Tk
	Tcl-Version:    8.7
-----

# Abstract

This TIP is to allow custom sizing of menubutton indicators using
**-indwidth** and **-indheight** as options.

# Rationale

Currently there is no way to vary the size of the indicator for a classic Unix
menubutton widget.  Adding the ability to control this via configuration
options will give the coder more control over a GUI's appearance for when such
fine control is required.

# Specification

The following options are proposed to be added to the **::menubutton**
widget:

 > The **-indwidth** option allows the specification of the width of the
   indicator in 10ths of a mm \(will be converted to an integer number of pixels\).

 > The **-indheight** option allows the specification of the height of the
   indicator in 10ths of a mm \(will be converted to an integer number of pixels\).

# Implementation

A patch exists in SourceForge \(Feature Request 2996760
<https://sourceforge.net/support/tracker.php?aid=2996760> \).

# Copyright

This document has been placed in the public domain.

Name change from tip/367.tip to tip/367.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

TIP:		367
Title:		A Command to Remove Elements from a List
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Post-History:	
Version:	$Revision: 1.1 $
Author:		Donal K. Fellows <[email protected]>
Created:	18-May-2010
Keywords:	Tcl, delete, item


~ Abstract

This TIP proposes a command, '''lremove''', that takes a list value and a
collection of indices, and returns a list that is the input list with the
elements at those indices removed.

~ Rationale

Tcl has many operations for working with lists, such as '''list''' for
building them, '''lappend''' for adding to them, '''linsert''' for insertion,
'''lreplace''' for replacement of ranges, and '''lset''' for replacement of
individual elements, but it has none that is designed to remove elements of a
list. While the functionality can be simulated in the simple case with
'''lreplace''', this is rather more difficult when multiple indices are
present. It is particularly challenging when using a mixture of indices that
are defined relative to the start and the end of the list. Since the tools for
doing the mapping of indices to list positions are easily available at the C
level, I propose to add a command to Tcl to do the removal operation that
takes advantage of the capabilities to do this all correctly.

~ Proposed Change

This TIP proposes adding a command, '''lremove''', with the following syntax:

 > '''lremove''' ''list'' ?''index''? ?''index...''?

That is, the command takes one mandatory argument, ''list'', and an arbitrary
number of ''index'' arguments (including zero). The ''list'' argument must be
a valid Tcl list, and each of the ''index'' arguments must be a valid Tcl
index (see [176] for a description) where '''end''' will refer to the last
element of ''list''. Assuming syntactic validity, the result will be a list
that is the same as ''list'' except for the removal of the elements at each
given ''index''. The result shall be as if all removals happen simultaneously
and the order of the ''index'' arguments shall be unimportant; if an element
is indicated twice (whether through syntactically identical indices or not)
then it will be as if it was only indicated once.

~ Examples

|% lremove {a b c d e} 1
|a c d e
|% lremove {a b c d e} end-1
|a b c e
|% lremove {a b c d e} 1 3
|a c e
|% lremove {a b c d e} 3 1
|a c e
|% lremove {a b c d e} 2 2
|a b d e
|% lremove {a b c d e} 3 end-1
|a b c e
|% lremove {a b c d e} 1 3 1 4 0
|c


~ Implementation

''Pending.''

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|

|



|

|
|
|


|






|

|

|

|
|
|
|
|
|
|
|
|


|

|
|
|
|
|
|
|
|
|
|
|
|
|
<
|
>
|

|

|


>

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

# TIP 367: A Command to Remove Elements from a List
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	18-May-2010
	Keywords:	Tcl, delete, item
-----

# Abstract

This TIP proposes a command, **lremove**, that takes a list value and a
collection of indices, and returns a list that is the input list with the
elements at those indices removed.

# Rationale

Tcl has many operations for working with lists, such as **list** for
building them, **lappend** for adding to them, **linsert** for insertion,
**lreplace** for replacement of ranges, and **lset** for replacement of
individual elements, but it has none that is designed to remove elements of a
list. While the functionality can be simulated in the simple case with
**lreplace**, this is rather more difficult when multiple indices are
present. It is particularly challenging when using a mixture of indices that
are defined relative to the start and the end of the list. Since the tools for
doing the mapping of indices to list positions are easily available at the C
level, I propose to add a command to Tcl to do the removal operation that
takes advantage of the capabilities to do this all correctly.

# Proposed Change

This TIP proposes adding a command, **lremove**, with the following syntax:

 > **lremove** _list_ ?_index_? ?_index..._?

That is, the command takes one mandatory argument, _list_, and an arbitrary
number of _index_ arguments \(including zero\). The _list_ argument must be
a valid Tcl list, and each of the _index_ arguments must be a valid Tcl
index \(see [[176]](176.md) for a description\) where **end** will refer to the last
element of _list_. Assuming syntactic validity, the result will be a list
that is the same as _list_ except for the removal of the elements at each
given _index_. The result shall be as if all removals happen simultaneously
and the order of the _index_ arguments shall be unimportant; if an element
is indicated twice \(whether through syntactically identical indices or not\)
then it will be as if it was only indicated once.

# Examples

	% lremove {a b c d e} 1
	a c d e
	% lremove {a b c d e} end-1
	a b c e
	% lremove {a b c d e} 1 3
	a c e
	% lremove {a b c d e} 3 1
	a c e
	% lremove {a b c d e} 2 2
	a b d e
	% lremove {a b c d e} 3 end-1
	a b c e
	% lremove {a b c d e} 1 3 1 4 0

	c

# Implementation

_Pending._

# Copyright

This document has been placed in the public domain.

Name change from tip/368.tip to tip/368.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

TIP:		368
Title:		Listbox Justification Option
Version:	$Revision: 1.2 $
Author:		Russell Davidson <[email protected]>
State:		Withdrawn
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Created:	10-May-2010
Post-History:
Keywords:	Tk
Obsoleted-By: 441


~ Abstract

This TIP is to allow right and center justification of listboxes using
'''-justify''' as an option.

~ Rationale

Sometimes a listbox needs right or center justification for the right visual
effect.  For example lists of numbers, particularly money amounts, look better
right justified.  Currently, only left justification is possible.

~ Specification

It is proposed that a '''-justify''' option be added to the '''::listbox'''
widget, which may be '''left''', '''right''', or '''center''' to allow
different justifications.  The default setting will be '''left'''.

~ Implementation

A patch exists in SourceForge (FRQ 2996762
[https://sourceforge.net/support/tracker.php?aid=2996762"]).

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|


|

|





|

|
|
|

|

|
|

|


>

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

# TIP 368: Listbox Justification Option

	Author:		Russell Davidson <[email protected]>
	State:		Withdrawn
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Created:	10-May-2010
	Post-History:
	Keywords:	Tk
	Obsoleted-By: 441
-----

# Abstract

This TIP is to allow right and center justification of listboxes using
**-justify** as an option.

# Rationale

Sometimes a listbox needs right or center justification for the right visual
effect.  For example lists of numbers, particularly money amounts, look better
right justified.  Currently, only left justification is possible.

# Specification

It is proposed that a **-justify** option be added to the **::listbox**
widget, which may be **left**, **right**, or **center** to allow
different justifications.  The default setting will be **left**.

# Implementation

A patch exists in SourceForge \(FRQ 2996762
<https://sourceforge.net/support/tracker.php?aid=2996762"> \).

# Copyright

This document has been placed in the public domain.

Name change from tip/369.tip to tip/369.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

TIP:            369
Title:          Widget cargo command
Version:        $Revision: 1.7 $
Author:         Russell Davidson <[email protected]>
Author:         Trevor Davel <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        15-Jul-2010
Post-History:   
Keywords:       Tk,user-defined data,dictionary
Tcl-Version:    8.7


~ Abstract

This TIP is to add a '''cargo''' subcommand to widgets for storing data in a
data dictionary. This TIP is related to [349].

~ Specification

It is proposed that a '''cargo''' subcommand be added to most widgets that
will allow the user to store data related to the widget in a data dictionary.
With the '''cargo''' command there are three parameters that can go with it:
'''set''', '''unset''', and '''get'''.

'''Set''' adds and alters entries in the cargo dictionary.

 > ''pathName'' '''cargo set''' ''name value'' ?''name value ...''?

'''Unset''', with the name of an entry, will delete the entry from the cargo
dictionary and free the memory that entry used. '''Unset''', without an entry
name, will delete the entire dictionary and free all memory.

 > ''pathName'' '''cargo unset''' ?''name ...''?

'''Get''' with the name of an entry will return the associated value.
'''Get''' without an entry will return all entry-value pairs.

 > ''pathName'' '''cargo get''' ?''name''?

~ Usage

The following is based on a widget called ''.wgt'' that has already been
created:

|.wgt cargo set help "This is a widget" use "Shows a widget"

This puts two entries into the cargo dictionary, one called ''help'', with the
value "''This is a widget''", and one called ''use'' with the value "''Shows a
widget''".

|.wgt cargo set help "This is a wonderful widget" use2 "Shows a great widget"

This alters the value of the entry ''help'' to "''This is a wonderful
widget''", and adds the entry ''use2'' with the value "''Shows a great
widget''"

|.wgt cargo unset use

This erases the entry ''use'' and frees the memory.

|puts [.wgt cargo get help]

This prints "''This is a wonderful widget''", the value of the entry ''help''.

|puts [.wgt cargo get use]

This prints an empty string because the entry ''use'' has been deleted. When
an entry that doesn't exist is accessed with '''get''', a blank string is
returned.

|puts [.wgt cargo get use2]

This prints "''Shows a great widget''", the value of the entry ''use2''.

| puts [.wgt cargo get]

This prints "''help {This is a wonderful widget} use2 {Shows a great
widget}''".

|.wgt cargo unset

This deletes all entries and frees the memory

Note that when a widget is destroyed, the cargo dictionary associated with it
is erased and the memory is freed.

~ Rationale

It is possible to duplicate this functionality by creating additional
procedures and variables. But doing this in Tcl has the downside of creating
more overhead when running the script. It also makes more things for the coder
to keep track of. By putting the dictionary in the base code, there is less
overhead and less for the developer to keep track of. If no cargo dictionary
at all is wanted there is no additional overhead beyond an unused pointer in
each widget.

Memory management is a big benefit. As widgets are created/destroyed, it is
easy to inadvertently generate memory leaks where structures are created for
new widgets, filled with data, and then inadvertently left around after the
widget is destroyed. When the data is stored with the widget instance, garbage
gets cleaned up much more reliably.

The '''cargo''' subcommand can also be used to help implement tool-tip
funcionality.  We could suggest that tool tips be supported natively in Tk,
but that request would be easily argued against with the logic that it can be
easily re-created in Tcl. So '''cargo''' is suggested instead as a very
general way of facilitating a whole host of functionality to be implemented in
widget wrappers without having to keep and maintain scads of external data in
auxiliary hashes.

One of the biggest challenges we face with Tcl/Tk is keeping it somewhat
object oriented (without having to inherit the whole overhead structure of one
of the multitude of available OOPs). When a new instance of a widget or a
megawidget gets created, it is important to be able to keep track of which
variables are related to instances and which ones apply to a whole class. We
currently solve this by including the instance name in the hash index. While
this works, it does get messy sometimes. And it would be appealing to be able
to make individual instances of widgets responsible for storing their own
data. It would certainly allow for a greater degree of isolation between
instances.

In short, '''cargo''' does not actually implement any specific functionality
in the widget which a megawidget might otherwise handle. But it does
facilitate easier implementation of a broad range of compound and megawidget
functionality.

~ Implementation

A patch exists in SourceForge (FRQ 3023578
[https://sourceforge.net/support/tracker.php?aid=3023578])

----

~ Comments

Twylite 2010/08/10:

   * The performance overhead for doing this in a script rather than in the core
     is minimal.

   * Developer overhead is easily dealt with by means of an appropriate 
     abstraction.

   * Script-level resource management can be achieved by binding to <Destroy>.

   * This proposal fails to address some variables that may need to be 
     associated with a widget, in particular those used with -variable or 
     -textvariable which require the ability to reference the variable by name.  
     These are also instance-related variables that can benefit from automated 
     resource management and a cleaner abstraction.

   * For a pure-Tcl implementation of functionality equivalent to '''cargo'''
     plus direct reference by name, take a look at my tk::wprop module
    (doc [http://dev.crypt.co.za/incubator/doc/tcltm/tk/wprop.wiki], source 
    [http://dev.crypt.co.za/incubator/artifact/d480935465])   

----

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|
|

|

|

|
|

|

|

|
|


|

|
|

|

|

|


|

|
|
|

|

|
|
|

|

|

|

|

|

|
|


|

|

|

|
|

|






|















|


|





|
|








|




|

|
|



|

















|

|
|



|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

# TIP 369: Widget cargo command

	Author:         Russell Davidson <[email protected]>
	Author:         Trevor Davel <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        15-Jul-2010
	Post-History:   
	Keywords:       Tk,user-defined data,dictionary
	Tcl-Version:    8.7
-----

# Abstract

This TIP is to add a **cargo** subcommand to widgets for storing data in a
data dictionary. This TIP is related to [[349]](349.md).

# Specification

It is proposed that a **cargo** subcommand be added to most widgets that
will allow the user to store data related to the widget in a data dictionary.
With the **cargo** command there are three parameters that can go with it:
**set**, **unset**, and **get**.

**Set** adds and alters entries in the cargo dictionary.

 > _pathName_ **cargo set** _name value_ ?_name value ..._?

**Unset**, with the name of an entry, will delete the entry from the cargo
dictionary and free the memory that entry used. **Unset**, without an entry
name, will delete the entire dictionary and free all memory.

 > _pathName_ **cargo unset** ?_name ..._?

**Get** with the name of an entry will return the associated value.
**Get** without an entry will return all entry-value pairs.

 > _pathName_ **cargo get** ?_name_?

# Usage

The following is based on a widget called _.wgt_ that has already been
created:

	.wgt cargo set help "This is a widget" use "Shows a widget"

This puts two entries into the cargo dictionary, one called _help_, with the
value "_This is a widget_", and one called _use_ with the value "_Shows a
widget_".

	.wgt cargo set help "This is a wonderful widget" use2 "Shows a great widget"

This alters the value of the entry _help_ to "_This is a wonderful
widget_", and adds the entry _use2_ with the value "_Shows a great
widget_"

	.wgt cargo unset use

This erases the entry _use_ and frees the memory.

	puts [.wgt cargo get help]

This prints "_This is a wonderful widget_", the value of the entry _help_.

	puts [.wgt cargo get use]

This prints an empty string because the entry _use_ has been deleted. When
an entry that doesn't exist is accessed with **get**, a blank string is
returned.

	puts [.wgt cargo get use2]

This prints "_Shows a great widget_", the value of the entry _use2_.

	 puts [.wgt cargo get]

This prints "_help \{This is a wonderful widget\} use2 \{Shows a great
widget\}_".

	.wgt cargo unset

This deletes all entries and frees the memory

Note that when a widget is destroyed, the cargo dictionary associated with it
is erased and the memory is freed.

# Rationale

It is possible to duplicate this functionality by creating additional
procedures and variables. But doing this in Tcl has the downside of creating
more overhead when running the script. It also makes more things for the coder
to keep track of. By putting the dictionary in the base code, there is less
overhead and less for the developer to keep track of. If no cargo dictionary
at all is wanted there is no additional overhead beyond an unused pointer in
each widget.

Memory management is a big benefit. As widgets are created/destroyed, it is
easy to inadvertently generate memory leaks where structures are created for
new widgets, filled with data, and then inadvertently left around after the
widget is destroyed. When the data is stored with the widget instance, garbage
gets cleaned up much more reliably.

The **cargo** subcommand can also be used to help implement tool-tip
funcionality.  We could suggest that tool tips be supported natively in Tk,
but that request would be easily argued against with the logic that it can be
easily re-created in Tcl. So **cargo** is suggested instead as a very
general way of facilitating a whole host of functionality to be implemented in
widget wrappers without having to keep and maintain scads of external data in
auxiliary hashes.

One of the biggest challenges we face with Tcl/Tk is keeping it somewhat
object oriented \(without having to inherit the whole overhead structure of one
of the multitude of available OOPs\). When a new instance of a widget or a
megawidget gets created, it is important to be able to keep track of which
variables are related to instances and which ones apply to a whole class. We
currently solve this by including the instance name in the hash index. While
this works, it does get messy sometimes. And it would be appealing to be able
to make individual instances of widgets responsible for storing their own
data. It would certainly allow for a greater degree of isolation between
instances.

In short, **cargo** does not actually implement any specific functionality
in the widget which a megawidget might otherwise handle. But it does
facilitate easier implementation of a broad range of compound and megawidget
functionality.

# Implementation

A patch exists in SourceForge \(FRQ 3023578
<https://sourceforge.net/support/tracker.php?aid=3023578> \)

----

# Comments

Twylite 2010/08/10:

   * The performance overhead for doing this in a script rather than in the core
     is minimal.

   * Developer overhead is easily dealt with by means of an appropriate 
     abstraction.

   * Script-level resource management can be achieved by binding to <Destroy>.

   * This proposal fails to address some variables that may need to be 
     associated with a widget, in particular those used with -variable or 
     -textvariable which require the ability to reference the variable by name.  
     These are also instance-related variables that can benefit from automated 
     resource management and a cleaner abstraction.

   * For a pure-Tcl implementation of functionality equivalent to **cargo**
     plus direct reference by name, take a look at my tk::wprop module
    \(doc <http://dev.crypt.co.za/incubator/doc/tcltm/tk/wprop.wiki> , source 
    <http://dev.crypt.co.za/incubator/artifact/d480935465> \)   

----

# Copyright

This document has been placed in the public domain.

Name change from tip/37.tip to tip/37.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149

TIP:            37
Title:          Uniform Rows and Columns in Grid
Version:        $Revision: 1.11 $
Author:         Peter Spjuth <[email protected]>
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        19-Jun-2001
Post-History:   
Tcl-Version:    8.4


~ Abstract

This TIP proposes to add a ''-uniform'' option to ''grid
rowconfigure'' and ''grid columnconfigure'' so as to make it easier to
create layouts where cells are constrained to have identical
dimensions.

~ Introduction

The geometry managers in Tk are very powerful and can do most things
needed to layout a GUI.  One thing that is tricky to do though is to
put widgets in rows or columns of the same width.  This would be
useful for example to layout a row of buttons symmetrically.  This
could easily be done with the grid manager if an additional option is
added.

~ Specification

Anywhere ''column'' is used below, the same applies to ''row'' too.

A new option, ''-uniform'', is added to ''grid columnconfigure''.  The
option takes an arbitrary string, the default value being the empty
string.  Any column with a non-empty value will be grouped with other
columns with the same value.  Each column in a group will get the size
k*''-weight'' (in this aspect a ''-weight'' value of 0 is used as 1)
, where k is set so that no column becomes smaller.  E.g., if all columns
in a group have the same ''-weight'' they will all get the size of the
largest member.

In the grid algorithm ''-uniform'' and ''-weight'' will be used as
specified above in the calculation of the requested size (the first step in
the description of the grid algorithm in grid(n)), but for the distribution
of extra size (second step) only ''-weight'' will be considered.  This
means that the second step is not altered at all by this.

~ Rationale

Getting symmetry in a layout today is possible but even for a simple
case it gets tricky if you want more than a half decent result.  Message
catalogs changing strings and options databases changing appearances
can make a GUI very dynamic and normally you never need to count pixels
since geometry managers do that for you.  For symmetry though you suddenly
have to handle pixel details yourself, details that are handled so much
better by a geometry manager.  With a ''-uniform'' option, grid can do
symmetry for you in a simple way that takes care of all the details.

To only consider ''-weight'' in the extra size distribution is mainly
a matter of simplicity.  It gives a simpler algorithm that is both
easier to explain to the user and to code.

To uphold the uniform property it would be needed to force any zero
''-weight'' value in a group where any non-zero ''-weight'' exists to
be set to one before doing the resize calculations.  A bit complicated
and the only benefit for the user would be to only have to specify
''-weight'' for one column in a group. But in practice this is hardly
no gain at all since a typical usage looks like this:

|grid columnconfigure . {0 1 2} -uniform a -weight 1

I'm not sure if someone would have a use for the effect you would get
by mixing zero and non-zero weights in a group but this leaves you
the freedom to do so.

~ Examples

To clarify how -uniform affects a grid here are some examples.

|button .b1 -text a
|button .b2 -text b
|button .b3 -text example
|button .b4 -text xyzzy
|grid .b1 .b2 .b3 .b4 -sticky news
|grid columnconfigure . {0 1 2 3} -uniform a -weight 1

Initially all columns will be equal and if resized, all columns will
change equally.

|Initial: |[   a   ]|[   b   ]|[example]|[ xyzzy ]|
|Shrunk:  |[  a  ]|[  b  ]|[xampl]|[xyzzy]|

Another example. Instead we do:

|grid columnconfigure . {0 2} -uniform a -weight 1
|grid columnconfigure . {2}   -weight 2
|grid columnconfigure . {1 3} -uniform b -weight 0
|grid columnconfigure . {1}   -weight 1

Initially column 0 will be half the size of column 2, columns 1
and 3 will be equal.
Resizing will affect colums 0 and 1 half of how column 2 is
affected. Column 3 is static.

|Initial:  |[ a ]|[  b  ]|[example]|[xyzzy]|
|Shrunk:   |[a]|[ b ]|[amp]|[xyzzy]|
|Expanded: |[  a  ]|[   b   ]|[  example  ]|[xyzzy]|

~ Implementation

A quick try shows that this is fairly straightforward to implement.
If the option is not used the memory cost is a ''Tk_Uid'' field (or
similar if some other mechanism than ''Tk_Uid'' is used) in the column
slot structure to hold the option, and the CPU overhead is small.

~ Summary of Objections

 * Kevin Kenny raised the issue that the proposed implementation
   uses a Tk_Uid for the "uniform" key, leading to potential resource
   leaks.  Subsequent discussion has convinced him that the potential
   for trouble is small; in any case, it need not block approval.
   The ensuing discussion veered off into a long thread about
   reclaiming the memory used for Tcl_Obj structures; the thread
   is not pertinent to this TIP.

 * George Howlett questioned the need for this feature, citing the
   lack of compelling examples.  The original author replied with
   the example of a dialog holding multiple buttons containing
   text of different widths, and showed how the Tcl code to manage
   such a dialog is clumsy.

 * George Howlett raised the issue of a detailed specification of
   the behavior of -uniform when insufficient space is available to
   satisfy the request.  The original author added clarification in
   the "Examples" section, and supplied additional examples in
   discussions on the mailing list
   [http://www.geocrawler.com/archives/3/7375/2001/7/50/6211900/].

 * George Howlett also asserted that the desired semantics can
   be achieved with Tcl code that either lays out a fixed
   configuration of the widget (with, for example, the ''-minsize''
   option of ''grid columnconfigure'') or responds to the
   ''<Configure>'' event.  Probably the best summary of the ensuing
   discussion is that we need to strike a balance between
   richness of the API and simplicity of the implementation.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|



|








|

|

|



|

|


|
|
|
|


|







|


|




|


|


|





|



|
|
|
|
|
|




|
|



|
|
|
|






|
|
|

|


|
|


|


|



|













|



|
|
|



|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149

# TIP 37: Uniform Rows and Columns in Grid

	Author:         Peter Spjuth <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        19-Jun-2001
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

This TIP proposes to add a _-uniform_ option to _grid
rowconfigure_ and _grid columnconfigure_ so as to make it easier to
create layouts where cells are constrained to have identical
dimensions.

# Introduction

The geometry managers in Tk are very powerful and can do most things
needed to layout a GUI.  One thing that is tricky to do though is to
put widgets in rows or columns of the same width.  This would be
useful for example to layout a row of buttons symmetrically.  This
could easily be done with the grid manager if an additional option is
added.

# Specification

Anywhere _column_ is used below, the same applies to _row_ too.

A new option, _-uniform_, is added to _grid columnconfigure_.  The
option takes an arbitrary string, the default value being the empty
string.  Any column with a non-empty value will be grouped with other
columns with the same value.  Each column in a group will get the size
k\*_-weight_ \(in this aspect a _-weight_ value of 0 is used as 1\)
, where k is set so that no column becomes smaller.  E.g., if all columns
in a group have the same _-weight_ they will all get the size of the
largest member.

In the grid algorithm _-uniform_ and _-weight_ will be used as
specified above in the calculation of the requested size \(the first step in
the description of the grid algorithm in grid\(n\)\), but for the distribution
of extra size \(second step\) only _-weight_ will be considered.  This
means that the second step is not altered at all by this.

# Rationale

Getting symmetry in a layout today is possible but even for a simple
case it gets tricky if you want more than a half decent result.  Message
catalogs changing strings and options databases changing appearances
can make a GUI very dynamic and normally you never need to count pixels
since geometry managers do that for you.  For symmetry though you suddenly
have to handle pixel details yourself, details that are handled so much
better by a geometry manager.  With a _-uniform_ option, grid can do
symmetry for you in a simple way that takes care of all the details.

To only consider _-weight_ in the extra size distribution is mainly
a matter of simplicity.  It gives a simpler algorithm that is both
easier to explain to the user and to code.

To uphold the uniform property it would be needed to force any zero
_-weight_ value in a group where any non-zero _-weight_ exists to
be set to one before doing the resize calculations.  A bit complicated
and the only benefit for the user would be to only have to specify
_-weight_ for one column in a group. But in practice this is hardly
no gain at all since a typical usage looks like this:

	grid columnconfigure . {0 1 2} -uniform a -weight 1

I'm not sure if someone would have a use for the effect you would get
by mixing zero and non-zero weights in a group but this leaves you
the freedom to do so.

# Examples

To clarify how -uniform affects a grid here are some examples.

	button .b1 -text a
	button .b2 -text b
	button .b3 -text example
	button .b4 -text xyzzy
	grid .b1 .b2 .b3 .b4 -sticky news
	grid columnconfigure . {0 1 2 3} -uniform a -weight 1

Initially all columns will be equal and if resized, all columns will
change equally.

	Initial: |[   a   ]|[   b   ]|[example]|[ xyzzy ]|
	Shrunk:  |[  a  ]|[  b  ]|[xampl]|[xyzzy]|

Another example. Instead we do:

	grid columnconfigure . {0 2} -uniform a -weight 1
	grid columnconfigure . {2}   -weight 2
	grid columnconfigure . {1 3} -uniform b -weight 0
	grid columnconfigure . {1}   -weight 1

Initially column 0 will be half the size of column 2, columns 1
and 3 will be equal.
Resizing will affect colums 0 and 1 half of how column 2 is
affected. Column 3 is static.

	Initial:  |[ a ]|[  b  ]|[example]|[xyzzy]|
	Shrunk:   |[a]|[ b ]|[amp]|[xyzzy]|
	Expanded: |[  a  ]|[   b   ]|[  example  ]|[xyzzy]|

# Implementation

A quick try shows that this is fairly straightforward to implement.
If the option is not used the memory cost is a _Tk\_Uid_ field \(or
similar if some other mechanism than _Tk\_Uid_ is used\) in the column
slot structure to hold the option, and the CPU overhead is small.

# Summary of Objections

 * Kevin Kenny raised the issue that the proposed implementation
   uses a Tk\_Uid for the "uniform" key, leading to potential resource
   leaks.  Subsequent discussion has convinced him that the potential
   for trouble is small; in any case, it need not block approval.
   The ensuing discussion veered off into a long thread about
   reclaiming the memory used for Tcl\_Obj structures; the thread
   is not pertinent to this TIP.

 * George Howlett questioned the need for this feature, citing the
   lack of compelling examples.  The original author replied with
   the example of a dialog holding multiple buttons containing
   text of different widths, and showed how the Tcl code to manage
   such a dialog is clumsy.

 * George Howlett raised the issue of a detailed specification of
   the behavior of -uniform when insufficient space is available to
   satisfy the request.  The original author added clarification in
   the "Examples" section, and supplied additional examples in
   discussions on the mailing list
   <http://www.geocrawler.com/archives/3/7375/2001/7/50/6211900/> .

 * George Howlett also asserted that the desired semantics can
   be achieved with Tcl code that either lays out a fixed
   configuration of the widget \(with, for example, the _-minsize_
   option of _grid columnconfigure_\) or responds to the
   _<Configure>_ event.  Probably the best summary of the ensuing
   discussion is that we need to strike a balance between
   richness of the API and simplicity of the implementation.

# Copyright

This document has been placed in the public domain.

Name change from tip/370.tip to tip/370.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

TIP:		370
Title:		Extend Tk's selection with a -time option
Version:	$Revision: 1.3 $
Author:		George Petasis <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Created:	04-Aug-2010
Post-History:


~ Abstract

This TIP proposes the addition of a new argument to the Tk command
'''selection''', for specifying a timestamp that should be used in order to
retrieve a selection.

~ Rationale

TkDND 2.x always used the '''selection''' command to retrieve data from the
clipboard, and worked until recently. The problem seems to be that the
selection Tk command always uses "''CurrentTime''" while retrieving the
selection, while the XDND protocol specifies that a specific timestamp should
be used.

I see that in Tk sources (''unix/tkUnixSelect.c'', line 178, the call to
''XConvertSelection'') there is already some discussion in the comments which
timestamp should be used. The "''CurrentTime''" seems a good choice, but why
not offer the ability to provide a timestamp if needed?

~ Proposed Change

Add a new option to '''selection get'''. Something like this:

 > '''selection get''' ?'''-displayof''' ''window''? ?'''-selection'''
   ''selection''? ?'''-type''' ''type''? ?'''-time''' ''time''?

The ''time'' value will be an integer, the same as in the '''-time''' option
to '''event generate''' and as produced by the '''%t''' substitution in
'''bind'''.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|


|

|

|



|
|
|


|

|

|
|

|
|
|

|


>

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

# TIP 370: Extend Tk's selection with a -time option

	Author:		George Petasis <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Created:	04-Aug-2010
	Post-History:
-----

# Abstract

This TIP proposes the addition of a new argument to the Tk command
**selection**, for specifying a timestamp that should be used in order to
retrieve a selection.

# Rationale

TkDND 2.x always used the **selection** command to retrieve data from the
clipboard, and worked until recently. The problem seems to be that the
selection Tk command always uses "_CurrentTime_" while retrieving the
selection, while the XDND protocol specifies that a specific timestamp should
be used.

I see that in Tk sources \(_unix/tkUnixSelect.c_, line 178, the call to
_XConvertSelection_\) there is already some discussion in the comments which
timestamp should be used. The "_CurrentTime_" seems a good choice, but why
not offer the ability to provide a timestamp if needed?

# Proposed Change

Add a new option to **selection get**. Something like this:

 > **selection get** ?**-displayof** _window_? ?**-selection**
   _selection_? ?**-type** _type_? ?**-time** _time_?

The _time_ value will be an integer, the same as in the **-time** option
to **event generate** and as produced by the **%t** substitution in
**bind**.

# Copyright

This document has been placed in the public domain.

Name change from tip/371.tip to tip/371.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

TIP:            371
Title:          Improvements for the dict command
Version:        $Revision: 1.3 $
Author:         Thomas Perschak <[email protected]>
Author:         Trevor Davel <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        05-Aug-2010
Post-History:   
Tcl-Version:    8.7


~ Abstract

The '''dict''' command is limited by allowing manipulation of only the first
level of key elements.  Not only should the '''dict get''' accept a nested key
list, but also the other commands like '''dict replace'''.

~ Specification And Example

The following line:

|dict get {-range {-values {a b c} -base M} -name myname} \
|        -range -base

Results in:

|M


But how to change the base? I suggest the following '''dict''' syntax
extension:

|dict replace {-range {-values {a b c} -base M} -name myname} \
|        {-range -base} k

Results in:

|-range {-values {a b c} -base k} -name myname

Allowing a nested key list would not break any previous code, but
substantially improve the '''dict''' command.

~ Rationale

The '''dict''' command is the basis for handling database like structures.  By
allowing nested keys this would give more freedom in organizing these
structures like the example above.

----

~ Comments

Twylite 2010/08/17: The specification states that "Allowing a nested key list would not break any previous code".  This is not correct, for example:

|dict replace {"Jane Smith" "11 Foo Road" "John Doe" "Address unknown"} {Jane Smith} new_address
|-> {Jane Smith} new_address {John Doe} {Address unknown}

Existing code that uses '''dict replace''' in conjunction with keys that are valid lists of 2 or more elements would break.

Also, drawing from experience, the nested key approach is a source of subtle bugs.  It is natural to write code such as:

|dict replace $dict $key $value

but that contains a bug that is often missed during testing.  The correct approach would be:

|dict replace $dict [list $key] $value

----

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|
|

|



|
|



<
|
>
|


|
|



|


|

|

|





|



|
|

|



|



|



|


>

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

# TIP 371: Improvements for the dict command

	Author:         Thomas Perschak <[email protected]>
	Author:         Trevor Davel <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        05-Aug-2010
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

The **dict** command is limited by allowing manipulation of only the first
level of key elements.  Not only should the **dict get** accept a nested key
list, but also the other commands like **dict replace**.

# Specification And Example

The following line:

	dict get {-range {-values {a b c} -base M} -name myname} \
	        -range -base

Results in:


	M

But how to change the base? I suggest the following **dict** syntax
extension:

	dict replace {-range {-values {a b c} -base M} -name myname} \
	        {-range -base} k

Results in:

	-range {-values {a b c} -base k} -name myname

Allowing a nested key list would not break any previous code, but
substantially improve the **dict** command.

# Rationale

The **dict** command is the basis for handling database like structures.  By
allowing nested keys this would give more freedom in organizing these
structures like the example above.

----

# Comments

Twylite 2010/08/17: The specification states that "Allowing a nested key list would not break any previous code".  This is not correct, for example:

	dict replace {"Jane Smith" "11 Foo Road" "John Doe" "Address unknown"} {Jane Smith} new_address
	-> {Jane Smith} new_address {John Doe} {Address unknown}

Existing code that uses **dict replace** in conjunction with keys that are valid lists of 2 or more elements would break.

Also, drawing from experience, the nested key approach is a source of subtle bugs.  It is natural to write code such as:

	dict replace $dict $key $value

but that contains a bug that is often missed during testing.  The correct approach would be:

	dict replace $dict [list $key] $value

----

# Copyright

This document has been placed in the public domain.

Name change from tip/372.tip to tip/372.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

TIP:		372
Title:		Multi-argument Yield for Coroutines
Version:	$Revision: 1.3 $
Author:		Colin McCormack <[email protected]>
State:		Draft
Type:		Project
Vote:		Done
Created:	11-Aug-2010
Post-History:
Tcl-Version:	8.6
Discussions-To: http://wiki.tcl.tk/26006
Keywords:	coroutine, yield
Obsoleted-By:	396


~ Abstract

This TIP proposes a command that allows a coroutine to accept multiple
arguments being passed in on return from yield.

~ Rationale

The coroutine mechanism of [328] has given Tcl 8.6 a new primitive which
permits light-weight mulitasking.  The mechanism as specified by [328] lacks
the ability to emulate general-purpose procedural invocation through the
arbitrary limitation of coroutine calls to a single argument (except on the
initial call).

The ability of coroutines to emulate general-purpose procedural invocation is
of great utility, the lack of which leads to stilted verbiage, and diverges
unnecessarily from Tcl's other functionals.

The '''yieldm''' command, as currently implemented by
'''::tcl::unsupported::yieldm''', extends coroutines to permit general
emulation, and it is the proposal of this TIP that yieldm be moved to the
global namespace, or such other namespaces as may be used for coroutine
functionality in the future.

~ Syntax and Semantics of yieldm

 > '''yieldm''' ?''value''?

This is just like '''yield''', except that it causes the coroutine command to
accept arbitrarily many arguments and will return the list of those arguments
(i.e., an empty list if there are no arguments, a single-element list if there
is one, a pair for two, etc.)

~ Detailed Rationale

~~ Utility

Restatement-in-summary of the arguments in http://wiki.tcl.tk/26006:

 1. Coroutines should be able to simulate any command, not just any
    single-arg'd command. [[Argument: generality]]

 2. To implement single-arg's coroutines in multi-arg'd coroutines is trivial
    - nothing needs to be done. The converse (implementing multi-arg'd
    coroutines under coroutine is inefficient and difficult. [[Argument:
    increased expressive power]]

 3. There is no sound reason that the invocation of a coroutine should not
    resemble that of any other command. [[Argument: principle of minimal
    surprise]]

 4. It is impossible to construct forms like '''interp alias''' to address a
    coroutine in the common case that the caller is expecting to pass more
    than one argument.

~~ Consistency

Restatement-in-summary of the arguments in http://wiki.tcl.tk/26056:

The following commands create new commands: '''proc''', '''coroutine''',
'''namespace ensemble''', '''class create''', ''$cls'' '''create''', '''interp
alias''', '''interp create''', '''::thread::create''', '''apply'''.

In each case except '''coroutine''', the created command permits multiple
arguments (arguably this being a key feature of Tcl in practice).  There is no
sound reason for this disparity, and for consistency the disparity should be
removed, which the proposed '''yieldm''' does.

~ Implementation

Simply rename the '''::tcl::unsupported::yieldm''' into the global namespace,
and extend the coroutine documentation to refer to the new command.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|




|

|
|

|
|





|
|




|

|

|

|
|

|

|

|


|


|
|
|


|
|

|



|

|

|
|
|

|
|

|

|

|


|


>

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

# TIP 372: Multi-argument Yield for Coroutines

	Author:		Colin McCormack <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		Done
	Created:	11-Aug-2010
	Post-History:
	Tcl-Version:	8.6
	Discussions-To: http://wiki.tcl.tk/26006
	Keywords:	coroutine, yield
	Obsoleted-By:	396
-----

# Abstract

This TIP proposes a command that allows a coroutine to accept multiple
arguments being passed in on return from yield.

# Rationale

The coroutine mechanism of [[328]](328.md) has given Tcl 8.6 a new primitive which
permits light-weight mulitasking.  The mechanism as specified by [[328]](328.md) lacks
the ability to emulate general-purpose procedural invocation through the
arbitrary limitation of coroutine calls to a single argument \(except on the
initial call\).

The ability of coroutines to emulate general-purpose procedural invocation is
of great utility, the lack of which leads to stilted verbiage, and diverges
unnecessarily from Tcl's other functionals.

The **yieldm** command, as currently implemented by
**::tcl::unsupported::yieldm**, extends coroutines to permit general
emulation, and it is the proposal of this TIP that yieldm be moved to the
global namespace, or such other namespaces as may be used for coroutine
functionality in the future.

# Syntax and Semantics of yieldm

 > **yieldm** ?_value_?

This is just like **yield**, except that it causes the coroutine command to
accept arbitrarily many arguments and will return the list of those arguments
\(i.e., an empty list if there are no arguments, a single-element list if there
is one, a pair for two, etc.\)

# Detailed Rationale

## Utility

Restatement-in-summary of the arguments in <http://wiki.tcl.tk/26006:>

 1. Coroutines should be able to simulate any command, not just any
    single-arg'd command. [Argument: generality]

 2. To implement single-arg's coroutines in multi-arg'd coroutines is trivial
    - nothing needs to be done. The converse \(implementing multi-arg'd
    coroutines under coroutine is inefficient and difficult. [Argument:
    increased expressive power]

 3. There is no sound reason that the invocation of a coroutine should not
    resemble that of any other command. [Argument: principle of minimal
    surprise]

 4. It is impossible to construct forms like **interp alias** to address a
    coroutine in the common case that the caller is expecting to pass more
    than one argument.

## Consistency

Restatement-in-summary of the arguments in <http://wiki.tcl.tk/26056:>

The following commands create new commands: **proc**, **coroutine**,
**namespace ensemble**, **class create**, _$cls_ **create**, **interp
alias**, **interp create**, **::thread::create**, **apply**.

In each case except **coroutine**, the created command permits multiple
arguments \(arguably this being a key feature of Tcl in practice\).  There is no
sound reason for this disparity, and for consistency the disparity should be
removed, which the proposed **yieldm** does.

# Implementation

Simply rename the **::tcl::unsupported::yieldm** into the global namespace,
and extend the coroutine documentation to refer to the new command.

# Copyright

This document has been placed in the public domain.

Name change from tip/373.tip to tip/373.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

TIP:            373
Title:          Improved Yielding Support for Coroutines
Version:        $Revision: 1.7 $
Author:         Miguel Sofer <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        12-Aug-2010
Post-History:   
Keywords:       coroutine,yield
Obsoletes:      372
Obsoleted-By:	375
Tcl-Version:    8.6


~ Abstract

This TIP proposes two new commands that improve control over the yielding 
behaviour of coroutines.

~ Rationale

The new command '''yieldto''' allows a coroutine to suspend its execution
and tailcall into an arbitrary command. It provides support for symmetric
coroutines, simply specifying that the new command be another coroutine's
resume command.

The new command '''yieldset''' specifies the number of arguments that the
coroutine's resume command will accept. Note that '''yieldset''' obsoletes
[372], in the sense that it provides a different way of satisfying the
same needs. 

~~ Detailed Rationale for "yieldto"

The current '''yield''' and proposed '''yieldm''' suspend a coroutine and
return the control to the coroutine's caller: they implement asymmetric
coroutines. 

It is well known that symmetric and asymmetric coroutines have equal power,
in that each can be implemented on top of the other. In Tcl8.6 as of today,
symmetric coroutines can be implemented by coding a scheduler, which may
but doesn't have to use the event loop. The new command '''yieldto'''
implements symmetric coroutines directly. 

The ability of '''yieldto''' to yield to an arbitrary command also provides
new possibilities. For instance, it allows to return a non-ok
code to the caller without terminating the coroutine:

| yieldto return -level 0 -code 1 ERROR

~ Proposal for "yieldto"

The new command

 > '''yieldto''' ''cmd'' ?''arg1 ...''?

causes:

 1. the currently executing coroutine to suspend its execution (yield),

 2. the command built from the arguments to '''yieldto''', as resolved in the
    coroutine's context, is run in the coroutine's caller scope,

 3. from the point of view of the coroutine's caller, the return value and
    options of the new command is what the coroutine returned on yielding.

In other words, '''yieldto''' implements "suspend yourself and '''tailcall'''
the new command"; '''yieldto''' is to '''yield''' as '''tailcall''' is to
'''return'''.

~~ Implementation of "yieldto"

Simply rename the '''::tcl::unsupported::yieldTo''' into the global namespace
while getting rid of the camelCase, and extend the '''coroutine'''
documentation and test-suite to refer to the new command.

~ Rationale and Proposal for "yieldset"

[372] justifies and requests a different interface to a coroutine's resume
command, allowing for an arbitrary number of arguments that shall be returned
to the coroutine's body in a list.

In order to limit the number of additional commands ('''yieldm''' and also
'''yieldmto'''), and increase the flexibility, it is proposed to add a
command:

 > '''yieldset''' ?''arglist''?

that sets the acceptable arguments for the resume command. 

If '''yieldset''' is called with no arguments it returns the current list of
arguments.

If '''yieldset''' is called with a list argument, it specifies the arguments
to the resume command in the manner of '''proc'''. The argument names shall
only be used for the error message if the resume command is called with an
invalid number of arguments.

In this manner, current '''yield''' behaves as if 

| yieldset {{arg {}}}

had been called. This shall remain the default behaviour.

If '''yieldset''' is called outside of a coroutine context, it sets the default behaviour for newly created coroutines. If it is called within a coroutine context it sets the behaviour for the current coroutine only. 

In order to obtain [372]'s '''yieldm''' behaviour for '''yield''', it would be
necessary to call:

| yieldset args

either before creating the coroutine or else within the coroutine body. 

The default arglist shall be '''{{arg {}}}''', so that the current '''yield''' is the default behaviour. The arglist value can
be changed with '''yieldset''' at any time, and remains valid until changed again.

~ Caveat

Some new proposals for better coroutine interfaces are being discussed, based
on ensembles and providing additional functionality.

I do not foresee the discussion to settle in the immediate future. The current
TIP is not meant to preempt any such design, it just attempts to provide a
limited improvement that is easy to implement immediately.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|




|

|




|
|
|


|

|






|


|



|

|



|



|

|





|
|
|

|

|
|


|

|



|
|


|



|


|
|



|

|



|

|


|



|
|

|








|


>

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

# TIP 373: Improved Yielding Support for Coroutines

	Author:         Miguel Sofer <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        12-Aug-2010
	Post-History:   
	Keywords:       coroutine,yield
	Obsoletes:      372
	Obsoleted-By:	375
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes two new commands that improve control over the yielding 
behaviour of coroutines.

# Rationale

The new command **yieldto** allows a coroutine to suspend its execution
and tailcall into an arbitrary command. It provides support for symmetric
coroutines, simply specifying that the new command be another coroutine's
resume command.

The new command **yieldset** specifies the number of arguments that the
coroutine's resume command will accept. Note that **yieldset** obsoletes
[[372]](372.md), in the sense that it provides a different way of satisfying the
same needs. 

## Detailed Rationale for "yieldto"

The current **yield** and proposed **yieldm** suspend a coroutine and
return the control to the coroutine's caller: they implement asymmetric
coroutines. 

It is well known that symmetric and asymmetric coroutines have equal power,
in that each can be implemented on top of the other. In Tcl8.6 as of today,
symmetric coroutines can be implemented by coding a scheduler, which may
but doesn't have to use the event loop. The new command **yieldto**
implements symmetric coroutines directly. 

The ability of **yieldto** to yield to an arbitrary command also provides
new possibilities. For instance, it allows to return a non-ok
code to the caller without terminating the coroutine:

	 yieldto return -level 0 -code 1 ERROR

# Proposal for "yieldto"

The new command

 > **yieldto** _cmd_ ?_arg1 ..._?

causes:

 1. the currently executing coroutine to suspend its execution \(yield\),

 2. the command built from the arguments to **yieldto**, as resolved in the
    coroutine's context, is run in the coroutine's caller scope,

 3. from the point of view of the coroutine's caller, the return value and
    options of the new command is what the coroutine returned on yielding.

In other words, **yieldto** implements "suspend yourself and **tailcall**
the new command"; **yieldto** is to **yield** as **tailcall** is to
**return**.

## Implementation of "yieldto"

Simply rename the **::tcl::unsupported::yieldTo** into the global namespace
while getting rid of the camelCase, and extend the **coroutine**
documentation and test-suite to refer to the new command.

# Rationale and Proposal for "yieldset"

[[372]](372.md) justifies and requests a different interface to a coroutine's resume
command, allowing for an arbitrary number of arguments that shall be returned
to the coroutine's body in a list.

In order to limit the number of additional commands \(**yieldm** and also
**yieldmto**\), and increase the flexibility, it is proposed to add a
command:

 > **yieldset** ?_arglist_?

that sets the acceptable arguments for the resume command. 

If **yieldset** is called with no arguments it returns the current list of
arguments.

If **yieldset** is called with a list argument, it specifies the arguments
to the resume command in the manner of **proc**. The argument names shall
only be used for the error message if the resume command is called with an
invalid number of arguments.

In this manner, current **yield** behaves as if 

	 yieldset {{arg {}}}

had been called. This shall remain the default behaviour.

If **yieldset** is called outside of a coroutine context, it sets the default behaviour for newly created coroutines. If it is called within a coroutine context it sets the behaviour for the current coroutine only. 

In order to obtain [[372]](372.md)'s **yieldm** behaviour for **yield**, it would be
necessary to call:

	 yieldset args

either before creating the coroutine or else within the coroutine body. 

The default arglist shall be **\{\{arg \{\}\}\}**, so that the current **yield** is the default behaviour. The arglist value can
be changed with **yieldset** at any time, and remains valid until changed again.

# Caveat

Some new proposals for better coroutine interfaces are being discussed, based
on ensembles and providing additional functionality.

I do not foresee the discussion to settle in the immediate future. The current
TIP is not meant to preempt any such design, it just attempts to provide a
limited improvement that is easy to implement immediately.

# Copyright

This document has been placed in the public domain.

Name change from tip/374.tip to tip/374.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

TIP:            374
Title:          Stackless Vwait
Version:        $Revision: 1.5 $
Author:         Thomas Perschak <[email protected]>
Author:         Trevor Davel <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        13-Aug-2010
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes a way to have multiple procedures waiting for an event to happen, where the command that gets executed depends on the order of the
events.

~ Rationale

Suppose you have three (or even more) synchronous procedures each of them
waiting for the socket to be readable. This waiting is implemented with
'''vwait''' - it is not possible to call this procedure event-driven - the
socket is opened and closed inside the same procedure. The current
implementation of '''vwait''' would block the procedure which called
'''vwait''' first, till the last procedure has read all data.

The stackless '''vwait''' would allow to group all similar '''vwait''' calls, define them stackless as whoever-comes-first and so unblock the procedure which has first data to read.

Originally I thought this could be solved with coroutines but I'am not so sure any more. Anyhow I think that the problem - explained later below - could be solved with a stackless '''vwait''' in a very elegant way.  Currently the '''vwait''' command is last-in-first-out, on the basis of the stackless 8.6 core there could be an improvement to make the '''vwait''' command configurable as last-in-last-out or even completely stackless event driven.

~ Specification

This is only a first idea, but it could be similar to named-mutex definitions - so one as to define the group of the '''vwait''' waiting for and the three behaviour types: first-in-last-out, first-in-first-out, whoever-comes-first;

The following command creates a new vwait group with a specified stack behaviour:

| vwaitgroup myvwaitgroup whoever-comes-first

Finally comes the waiting for the '''vwait''' which is similar to the existing
one:

| vwaitnew<myvar>  myvwaitgroup

In addition I would allow a timeout value to be specified:

| vwaitnew<myvar>  myvwaitgroup<mytimeout>

~ Example

This is only a very reduced example, but should show the principle of the
problem:

| proc myproc1 {} {
|    open socket
|    fileevent socket {set myvar 1}
|    vwait myvar
|    read data
| }


Having more than one of these procedure above, the '''vwait''' would block
data reading depending on the '''vwait''' stack.

The new stackless '''vwait''' would look like the following example: On a
global level I would do the following:

| vwaitgroup sockreadgroup whoever-comes-first

Then the procedures:

| proc myproc1 {} {
|    open socket
|    fileevent socket {set myvar 1}
|    vwait myvar sockreadgroup
|    read data
| }


| proc myproc2 {} {
|    open socket
|    fileevent socket {set myvar 1}
|    vwait myvar sockreadgroup
|    read data
| }


| proc myproc3 {} {
|    open socket
|    fileevent socket {set myvar 1}
|    vwait myvar sockreadgroup
|    read data
| }


----

~ Comments

Twylite 2010/08/17: "coroutine-enabled event handling" (http://wiki.tcl.tk/21555) presents pure-Tcl implementations of coroutine-enabled '''vwait''' and '''gets''' that do what this TIP describes without attempting to implement a custom scheduler.

----

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|

|

|

|
|

|

|

|

|



|

|


|



|

|




|
|
|
|
|
<
|
>
|
|

|


|



|
|
|
|
|
<
|
>
|
|
|
|
|
<
|
>
|
|
|
|
|
<
|
>


|

|



|


>

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

# TIP 374: Stackless Vwait

	Author:         Thomas Perschak <[email protected]>
	Author:         Trevor Davel <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        13-Aug-2010
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes a way to have multiple procedures waiting for an event to happen, where the command that gets executed depends on the order of the
events.

# Rationale

Suppose you have three \(or even more\) synchronous procedures each of them
waiting for the socket to be readable. This waiting is implemented with
**vwait** - it is not possible to call this procedure event-driven - the
socket is opened and closed inside the same procedure. The current
implementation of **vwait** would block the procedure which called
**vwait** first, till the last procedure has read all data.

The stackless **vwait** would allow to group all similar **vwait** calls, define them stackless as whoever-comes-first and so unblock the procedure which has first data to read.

Originally I thought this could be solved with coroutines but I'am not so sure any more. Anyhow I think that the problem - explained later below - could be solved with a stackless **vwait** in a very elegant way.  Currently the **vwait** command is last-in-first-out, on the basis of the stackless 8.6 core there could be an improvement to make the **vwait** command configurable as last-in-last-out or even completely stackless event driven.

# Specification

This is only a first idea, but it could be similar to named-mutex definitions - so one as to define the group of the **vwait** waiting for and the three behaviour types: first-in-last-out, first-in-first-out, whoever-comes-first;

The following command creates a new vwait group with a specified stack behaviour:

	 vwaitgroup myvwaitgroup whoever-comes-first

Finally comes the waiting for the **vwait** which is similar to the existing
one:

	 vwaitnew<myvar>  myvwaitgroup

In addition I would allow a timeout value to be specified:

	 vwaitnew<myvar>  myvwaitgroup<mytimeout>

# Example

This is only a very reduced example, but should show the principle of the
problem:

	 proc myproc1 {} {
	    open socket
	    fileevent socket {set myvar 1}
	    vwait myvar
	    read data

	 }

Having more than one of these procedure above, the **vwait** would block
data reading depending on the **vwait** stack.

The new stackless **vwait** would look like the following example: On a
global level I would do the following:

	 vwaitgroup sockreadgroup whoever-comes-first

Then the procedures:

	 proc myproc1 {} {
	    open socket
	    fileevent socket {set myvar 1}
	    vwait myvar sockreadgroup
	    read data

	 }

	 proc myproc2 {} {
	    open socket
	    fileevent socket {set myvar 1}
	    vwait myvar sockreadgroup
	    read data

	 }

	 proc myproc3 {} {
	    open socket
	    fileevent socket {set myvar 1}
	    vwait myvar sockreadgroup
	    read data

	 }

----

# Comments

Twylite 2010/08/17: "coroutine-enabled event handling" \(<http://wiki.tcl.tk/21555\)> presents pure-Tcl implementations of coroutine-enabled **vwait** and **gets** that do what this TIP describes without attempting to implement a custom scheduler.

----

# Copyright

This document has been placed in the public domain.

Name change from tip/375.tip to tip/375.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

TIP:            375
Title:          Symmetric Coroutines and Yieldto
Version:        $Revision: 1.3 $
Author:         Miguel Sofer <[email protected]>
State:          Draft
Type:           Project
Vote:           Done
Created:        12-Aug-2010
Post-History:   
Keywords:       coroutine,yield
Obsoletes:      373
Obsoleted-By:	396
Tcl-Version:    8.6


~ Abstract

The new command '''yieldto''' allows a coroutine to suspend its execution and
tailcall into an arbitrary command. If the new command is another coroutine's
resume command we obtain symmetric coroutines.

~~ Rationale

The current '''yield''' and proposed '''yieldm''' commands suspend a coroutine
and return the control to the coroutine's caller: they implement asymmetric
coroutines.

It is well known that symmetric and asymmetric coroutines have equal power, in
that each can be implemented on top of the other. In Tcl8.6 as of today,
symmetric coroutines can be implemented by coding a scheduler, which may but
doesn't have to use the event loop. The new command '''yieldto''' implements
symmetric coroutines directly.

The ability of '''yieldto''' to yield to an arbitrary command also provides
new possibilities. For instance, it allows to return a non-ok code to the
caller without terminating the coroutine:

| yieldto return -level 0 -code 1 ERROR

~ Proposal for "yieldto"

The new command

 > '''yieldto''' ''cmd'' ?''arg1 ...''?

causes:

 1. the currently executing coroutine to suspend its execution (yield),

 2. the command built from the arguments to '''yieldto''', as resolved in the
    coroutine's context, to be run in the coroutine's caller scope,

 3. from the point of view of the coroutine's caller, the return value and
    options of the new command is what the coroutine returned on yielding.

In other words, '''yieldto''' implements "suspend yourself and '''tailcall'''
the new command"; '''yieldto''' is to '''yield''' as '''tailcall''' is to
'''return'''.

~~ Implementation of "yieldto"

Simply rename the '''::tcl::unsupported::yieldTo''' into the global namespace
while getting rid of the camelCase, and extend the '''coroutine'''
documentation and test-suite to refer to the new command.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|



|

|






|


|



|

|



|



|

|





|
|
|

|

|
|


|


>

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

# TIP 375: Symmetric Coroutines and Yieldto

	Author:         Miguel Sofer <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Done
	Created:        12-Aug-2010
	Post-History:   
	Keywords:       coroutine,yield
	Obsoletes:      373
	Obsoleted-By:	396
	Tcl-Version:    8.6
-----

# Abstract

The new command **yieldto** allows a coroutine to suspend its execution and
tailcall into an arbitrary command. If the new command is another coroutine's
resume command we obtain symmetric coroutines.

## Rationale

The current **yield** and proposed **yieldm** commands suspend a coroutine
and return the control to the coroutine's caller: they implement asymmetric
coroutines.

It is well known that symmetric and asymmetric coroutines have equal power, in
that each can be implemented on top of the other. In Tcl8.6 as of today,
symmetric coroutines can be implemented by coding a scheduler, which may but
doesn't have to use the event loop. The new command **yieldto** implements
symmetric coroutines directly.

The ability of **yieldto** to yield to an arbitrary command also provides
new possibilities. For instance, it allows to return a non-ok code to the
caller without terminating the coroutine:

	 yieldto return -level 0 -code 1 ERROR

# Proposal for "yieldto"

The new command

 > **yieldto** _cmd_ ?_arg1 ..._?

causes:

 1. the currently executing coroutine to suspend its execution \(yield\),

 2. the command built from the arguments to **yieldto**, as resolved in the
    coroutine's context, to be run in the coroutine's caller scope,

 3. from the point of view of the coroutine's caller, the return value and
    options of the new command is what the coroutine returned on yielding.

In other words, **yieldto** implements "suspend yourself and **tailcall**
the new command"; **yieldto** is to **yield** as **tailcall** is to
**return**.

## Implementation of "yieldto"

Simply rename the **::tcl::unsupported::yieldTo** into the global namespace
while getting rid of the camelCase, and extend the **coroutine**
documentation and test-suite to refer to the new command.

# Copyright

This document has been placed in the public domain.

Name change from tip/376.tip to tip/376.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

TIP:		376
Title:		Bundle sqlite3 and tdbc::sqlite3 Packages
Version:	$Revision: 1.5 $
Author:		Don Porter <[email protected]>
Author:		D. Richard Hipp <[email protected]>
Author:		Kevin Kenny <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	14-Sep-2010
Tcl-Version:	8.6
Post-History:


~ Abstract

This TIP proposes the packages '''sqlite3''' and '''tdbc::sqlite3''' be
re-distributed as part of the Tcl source code distribution.

~ Background

Starting with the 8.6.* releases of Tcl, a collection of third party packages
are being redistributed as part of the Tcl source code distribution under the
directory ''tcl/pkgs/''.  This is partial fulfillment of the long-awaited
''batteries included'' vision for Tcl releases.  The current collection of
redistributed packages is Itcl [50], Thread [364], and tdbc [308].

The sqlite3 package is perhaps the most striking example of a Tcl extension
that has grown to eclipse Tcl itself.  Created and maintained by TCT emeritus
D. Richard Hipp, it should require little explanation here.

The tdbc::sqlite3 package provides the driver functionality to use the
facilities provided by sqlite3 as the backend of tdbc operations.  Created and
maintained by Kevin Kenny of the TCT, it should also be familiar to Tcl
insiders.

~ Proposal

Adapt release operations as needed so that the latest releases of 
the '''sqlite3''' and '''tdbc::sqlite3''' packages are included in releases
of Tcl 8.6.*.

~ Expected Benefits

Distribution of the '''tdbc''' package without any backend drivers has quite
limited utility.  Adding these two packages to the distributed set provides at
least one fully working backend with no third-party dependencies.  This
permits testing and demonstrating the capabilities of '''tdbc''' everywhere it
goes.

By including '''sqlite3''' in the Tcl source code distribution, Tcl can take a
place alongside PHP and Python on the list of famous users of SQLite
[http://www.sqlite.org/famous.html].  Since SQLite is now easily more broadly
esteemed than Tcl itself, this can only help our public image.

The package '''tdbc::sqlite3''' is itself written entirely in Tcl.  Unlike the
packages so far chosen for redistribution under ''tcl/pkgs/'', it contains no
C code.  The ''tcl/pkgs/'' harness and the TEA or tclconfig systems it
descends from have so far not paid sufficient attention to this case.
Including this package will force those systems over time to better support
that common implementation case.  This can only make package support tools
better for more package authors.  Also, as support for such packages under
''tcl/pkgs/'' matures, the large collection of packages that have been
distributed with Tcl on a more ad hoc basis, including '''tcltest''',
'''msgcat''', '''http''', '''platform''', and '''platform::shell''', may be
able to migrate to new places under the ''tcl/pkgs/'' framework.  This may
eventually lead to the ability to selectively take packages from tcllib for
redistribution with Tcl.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|

|

|
|
|










|


|
|

|

|


|


|

|


|
|
|




|
|
|
|



|


>

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

# TIP 376: Bundle sqlite3 and tdbc::sqlite3 Packages

	Author:		Don Porter <[email protected]>
	Author:		D. Richard Hipp <[email protected]>
	Author:		Kevin Kenny <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	14-Sep-2010
	Tcl-Version:	8.6
	Post-History:
-----

# Abstract

This TIP proposes the packages **sqlite3** and **tdbc::sqlite3** be
re-distributed as part of the Tcl source code distribution.

# Background

Starting with the 8.6.\* releases of Tcl, a collection of third party packages
are being redistributed as part of the Tcl source code distribution under the
directory _tcl/pkgs/_.  This is partial fulfillment of the long-awaited
_batteries included_ vision for Tcl releases.  The current collection of
redistributed packages is Itcl [[50]](50.md), Thread [[364]](364.md), and tdbc [[308]](308.md).

The sqlite3 package is perhaps the most striking example of a Tcl extension
that has grown to eclipse Tcl itself.  Created and maintained by TCT emeritus
D. Richard Hipp, it should require little explanation here.

The tdbc::sqlite3 package provides the driver functionality to use the
facilities provided by sqlite3 as the backend of tdbc operations.  Created and
maintained by Kevin Kenny of the TCT, it should also be familiar to Tcl
insiders.

# Proposal

Adapt release operations as needed so that the latest releases of 
the **sqlite3** and **tdbc::sqlite3** packages are included in releases
of Tcl 8.6.\*.

# Expected Benefits

Distribution of the **tdbc** package without any backend drivers has quite
limited utility.  Adding these two packages to the distributed set provides at
least one fully working backend with no third-party dependencies.  This
permits testing and demonstrating the capabilities of **tdbc** everywhere it
goes.

By including **sqlite3** in the Tcl source code distribution, Tcl can take a
place alongside PHP and Python on the list of famous users of SQLite
<http://www.sqlite.org/famous.html> .  Since SQLite is now easily more broadly
esteemed than Tcl itself, this can only help our public image.

The package **tdbc::sqlite3** is itself written entirely in Tcl.  Unlike the
packages so far chosen for redistribution under _tcl/pkgs/_, it contains no
C code.  The _tcl/pkgs/_ harness and the TEA or tclconfig systems it
descends from have so far not paid sufficient attention to this case.
Including this package will force those systems over time to better support
that common implementation case.  This can only make package support tools
better for more package authors.  Also, as support for such packages under
_tcl/pkgs/_ matures, the large collection of packages that have been
distributed with Tcl on a more ad hoc basis, including **tcltest**,
**msgcat**, **http**, **platform**, and **platform::shell**, may be
able to migrate to new places under the _tcl/pkgs/_ framework.  This may
eventually lead to the ability to selectively take packages from tcllib for
redistribution with Tcl.

# Copyright

This document has been placed in the public domain.

Name change from tip/377.tip to tip/377.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

TIP:            377
Title:          Portably Determining the Number of Processors in the System
Version:        $Revision: 1.2 $
Author:         Andreas Kupries <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        13-Sep-2010
Tcl-Version:	8.6
Post-History:


~ Abstract

A C API and Tcl command are proposed which return the number of CPUs (a.k.a.
Processors a.k.a. Cores) in the system, portably wrapping the OS specific APIs
for doing so.

~ Background and Motivation

With the relentless advance of multi-core chips it becomes sensible, IMVHO, to
have a portable method of determining the number of CPUs (also called
Processors or Cores) in the system.

This information is mostly important for the initialization of thread pools,
in order to have a sensible number of worker threads which provide the maximum
speedup without overloading the system. The general use-case the previous is
an example of is the dynamic reconfiguration of an application or library to
automatically adapt it to the resources available in the environment it finds
itself in. That is, this is useful for multi-process applications as well.

Semi-concrete examples: The CRIMP package is currently single-threaded. For
the best parallelization by threading, it should be possible to query the
number of processors the application can use. A web server like Wub can make
use of this functionality as well. They should not have to implement this on
their own, duplicating the functionality, or, worse, each having slightly
different implementations.

~ C Level API

 > int '''Tcl_GetNumberOfProcessors'''(int ''flags'')

Returns the number of processors for the current system, as provided by the
OS. If the system is unable to provide this information the returned value is
'1', as at least one processors is necessary to run anything at all.

The ''flags'' argument is not used. It is provided as a means of
extensibility. Something which can be used in the future to distinguish
between physical processors, hyperthreaded virtual processors, cores on a
chip, number of processor chips, and the like.  Right now such advanced
queries are out of the scope of the TIP.

The main point of having the 'flags' argument now is that future extensions
using it will not have to change the signature of the function.

~ Script Level API

 > '''info processors'''

Returns the number of processors for the current system, as provided by
'''Tcl_GetNumberProcessors'''(0).

~ Reference Implementation

A reference implementation is provided at SourceForge
[https://sourceforge.net/support/tracker.php?aid=3065485].

~ Discussion

The stackoverflow messaging board has a question on the various OS-specific
APIs. See [http://stackoverflow.com/q/150355/301832] for details.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|


|


|
|















|

|





|








|

|


|

|


|

|


|

|


>

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

# TIP 377: Portably Determining the Number of Processors in the System

	Author:         Andreas Kupries <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        13-Sep-2010
	Tcl-Version:	8.6
	Post-History:
-----

# Abstract

A C API and Tcl command are proposed which return the number of CPUs \(a.k.a.
Processors a.k.a. Cores\) in the system, portably wrapping the OS specific APIs
for doing so.

# Background and Motivation

With the relentless advance of multi-core chips it becomes sensible, IMVHO, to
have a portable method of determining the number of CPUs \(also called
Processors or Cores\) in the system.

This information is mostly important for the initialization of thread pools,
in order to have a sensible number of worker threads which provide the maximum
speedup without overloading the system. The general use-case the previous is
an example of is the dynamic reconfiguration of an application or library to
automatically adapt it to the resources available in the environment it finds
itself in. That is, this is useful for multi-process applications as well.

Semi-concrete examples: The CRIMP package is currently single-threaded. For
the best parallelization by threading, it should be possible to query the
number of processors the application can use. A web server like Wub can make
use of this functionality as well. They should not have to implement this on
their own, duplicating the functionality, or, worse, each having slightly
different implementations.

# C Level API

 > int **Tcl\_GetNumberOfProcessors**\(int _flags_\)

Returns the number of processors for the current system, as provided by the
OS. If the system is unable to provide this information the returned value is
'1', as at least one processors is necessary to run anything at all.

The _flags_ argument is not used. It is provided as a means of
extensibility. Something which can be used in the future to distinguish
between physical processors, hyperthreaded virtual processors, cores on a
chip, number of processor chips, and the like.  Right now such advanced
queries are out of the scope of the TIP.

The main point of having the 'flags' argument now is that future extensions
using it will not have to change the signature of the function.

# Script Level API

 > **info processors**

Returns the number of processors for the current system, as provided by
**Tcl\_GetNumberProcessors**\(0\).

# Reference Implementation

A reference implementation is provided at SourceForge
<https://sourceforge.net/support/tracker.php?aid=3065485> .

# Discussion

The stackoverflow messaging board has a question on the various OS-specific
APIs. See <http://stackoverflow.com/q/150355/301832>  for details.

# Copyright

This document has been placed in the public domain.

Name change from tip/378.tip to tip/378.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

TIP:            378
Title:          Fixing the Performance of TIP 280
Version:        $Revision: 1.3 $
Author:         Andreas Kupries <[email protected]>
Author:         Jeff Hobbs <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        04-Oct-2010
Tcl-Version:	8.6
Post-History:


~ Abstract

A Tcl command is proposed which enable a user of Tcl to disable the most
performance intensive parts of the [280] implementation, at the loss of some
detail.

~ Background and Motivation

[280] extended Tcl's abilities for introspection with the '''info frame'''
command able to determine the location of its call, i.e., the name of the file
the code is in, and the absolute line number in that file.

In the quest for the best possible detail one particular part of the
implementation had a great impact on the performance of bytecode execution,
doing complex stack/hash manipulations for each argument of each
INST_INVOKE_STK instruction to keep track of the location of scripts delivered
to '''uplevel''' commands as arguments of Tcl procedures (i.e.,
implementations of control structures in Tcl).

This TIP now proposes to put the execution of this part of [280]'s
implementation under user control, allowing them to trade '''info
frame'''-exactness for speed, and vice versa.

~ Script Level API

 > '''interp debug''' ''interp-path'' ?'''-frame''' ?''boolean''??

This API was chosen to be potentially extensible for other future interpreter
level control needs.

~~ Default Setting

This behavior will be turned off by default, unless Tcl is compiled with
-DTCL_INTERP_DEBUG_FRAME or $::env(TCL_INTERP_DEBUG_FRAME) is set at
interpreter creation time.

Note that this is a one-way switch because the '''info frame''' tracking is
maintained in a stack that must remain consistent once switched on.  Switching
off when deep in the stack would cause memory loss and possible crashes
without tracing on top of tracing, and it is felt that being an interp-level
switch, one-way switching should be sufficient for user needs.

~ Reference Implementation

A reference implementation is provided at SourceForge
[https://sourceforge.net/support/tracker.php?aid=3081184].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|


|

|






|
|
|

|
|
|

|

|




|


|


|





|


|

|


>

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

# TIP 378: Fixing the Performance of TIP 280

	Author:         Andreas Kupries <[email protected]>
	Author:         Jeff Hobbs <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        04-Oct-2010
	Tcl-Version:	8.6
	Post-History:
-----

# Abstract

A Tcl command is proposed which enable a user of Tcl to disable the most
performance intensive parts of the [[280]](280.md) implementation, at the loss of some
detail.

# Background and Motivation

[[280]](280.md) extended Tcl's abilities for introspection with the **info frame**
command able to determine the location of its call, i.e., the name of the file
the code is in, and the absolute line number in that file.

In the quest for the best possible detail one particular part of the
implementation had a great impact on the performance of bytecode execution,
doing complex stack/hash manipulations for each argument of each
INST\_INVOKE\_STK instruction to keep track of the location of scripts delivered
to **uplevel** commands as arguments of Tcl procedures \(i.e.,
implementations of control structures in Tcl\).

This TIP now proposes to put the execution of this part of [[280]](280.md)'s
implementation under user control, allowing them to trade **info
frame**-exactness for speed, and vice versa.

# Script Level API

 > **interp debug** _interp-path_ ?**-frame** ?_boolean_??

This API was chosen to be potentially extensible for other future interpreter
level control needs.

## Default Setting

This behavior will be turned off by default, unless Tcl is compiled with
-DTCL\_INTERP\_DEBUG\_FRAME or $::env\(TCL\_INTERP\_DEBUG\_FRAME\) is set at
interpreter creation time.

Note that this is a one-way switch because the **info frame** tracking is
maintained in a stack that must remain consistent once switched on.  Switching
off when deep in the stack would cause memory loss and possible crashes
without tracing on top of tracing, and it is felt that being an interp-level
switch, one-way switching should be sufficient for user needs.

# Reference Implementation

A reference implementation is provided at SourceForge
<https://sourceforge.net/support/tracker.php?aid=3081184> .

# Copyright

This document has been placed in the public domain.

Name change from tip/379.tip to tip/379.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327

TIP:		379
Title:		Add a Command for Delivering Events Without Tk
Version:	$Revision: 1.9 $
Author:		Will Duquette <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Created:	17-Oct-2010
Post-History:	
Keywords:	event


~ Abstract

This proposal defines the '''hook''' ensemble command, which implements the
Subject/Observer pattern.  It allows ''subjects'', which may be modules,
objects, widgets, and so forth, to synchronously call ''hooks'' which may be
bound to an arbitrary number of subscribers, called ''observers''.  A subject
may call any number of distinct hooks, and any number of observers can bind
callbacks to a particular hook called by a particular subject. Hook bindings
can be queried and deleted.

~ Rationale

Tcl modules usually send notifications to other modules in two ways: via Tk
events, and via callback options like the text widget's '''-yscrollcommand'''
option.  Tk events are available only in Tk, and callback options require
tight coupling between the modules sending and receiving the notification.

Loose coupling between sender and receiver is often desirable, however.  In
Model/View/Controller terms, a View can send a command (stemming from user
input) to the Controller, which updates the Model.  The Model can then call a
hook ''to which all relevant Views subscribe.''  The Model is decoupled from
the Views, and indeed need not know whether any Views actually exist.

At present, Tcl/Tk has no standard mechanism for implementing loose coupling
of this kind.  This proposal defines a new command, '''hook''', which
implements just such a mechanism.

~ Hook Bindings

The '''hook''' command manages a collection of hook bindings.  A hook binding
has four elements:

   * A
     ''subject'': the name of the entity that will be calling the hook.

   * The ''hook'' itself. A hook usually reflects some occurrence in the life
     of the ''subject'' that other entities might care to know about.  A
     ''hook'' has a name, and may also have arguments.  Hook names are
     arbitrary strings.  Each ''subject'' must document the names and
     arguments of the hooks it can call.

   * The name of the ''observer'' that wishes to receive the ''hook'' from
     the ''subject''.

   * A command prefix to which the ''hook'' arguments will be appended when
     the binding is executed.

~~ Subjects and Observers

For convenience, this TIP collectively refers to subjects and observers as
''objects'', while placing no requirements on how these ''objects'' are
actually implemented.  An object can be a a TclOO or Snit or XOTcl object, a
Tcl command, a namespace, a module, a pseudo-object managed by some other
object (as tags are managed by the Tk text widget) or simply a well-known
name.

Subject and observer names are arbitrary strings; however, as '''hook''' might
be used at the package level, it's necessary to have conventions that avoid
name collisions between packages written by different people.

Therefore, any subject or observer name used in core or package level code
should look like a Tcl command name, and should be defined in a namespace
owned by the package.  Consider, for example, an ensemble command '''::foo'''
that creates a set of pseudo-objects and uses '''hook''' to send
notifications.  The pseudo-objects have names that are not commands and exist
in their own namespace, rather like file handles do.  To avoid name collisions
with subjects defined by other packages, users of '''hook''', these
'''::foo''' handles should have names like '''::foo::1''', '''::foo::2''', and
so on.

Because object names are arbitrary strings, application code can use whatever
additional conventions are dictated by the needs of the application.

~ Specification

The '''hook''' command is an ensemble command with the following subcommands:

~~ Bind Subcommand

This subcommand is used to create, update, delete, and query hook bindings.

 > '''hook bind''' ?''subject''? ?''hook''? ?''observer''? ?''cmdPrefix''?

Called with no arguments, '''hook bind''' returns a list of the subjects with
hooks to which observers are currently bound.

Called with one argument, a ''subject'', '''hook bind''' returns a list of the
subject's hooks to which observers are currently bound.

Called with two arguments, a ''subject'' and a ''hook'', '''hook bind'''
returns a list of the observers which are currently bound to this ''subject''
and ''hook''.

Called with three arguments, a ''subject'', a ''hook'', and an ''observer'',
'''hook bind''' returns the binding proper, the command prefix to be called
when the hook is called, or the empty string if there is no such binding.

Called with four arguments, '''hook bind''' creates, updates, or deletes a
binding.  If ''cmdPrefix'' is the empty string, '''hook bind''' deletes any
existing binding for the ''subject'', ''hook'', and ''observer''; nothing is
returned.  Otherwise, ''cmdPrefix'' must be a command prefix taking as many
additional arguments as are documented for the ''subject'' and ''hook''. The
binding is added or updated, and the observer is returned.

If the ''observer'' is the empty string, "", '''hook''' will create a new
binding using an automatically generated observer name of the form
'''::hook::ob'''<''number''>.  The automatically generated name will be
returned, and can be used to query, update, and delete the binding as usual.
If automated observer names are always used, the observer name effectively
becomes a unique binding ID.

~~~ Binds During Calls

It is possible to call '''hook bind''' to create or delete a binding to a
''subject'' and ''hook'' while in an observer binding for that same
''subject'' and ''hook''.  The following rules determine what happens when
'''hook bind $s $h $o $binding''' is called during the execution of '''hook
call $s $h''':

   * No binding is ever called after it is deleted.

   * When a binding is called, the most recently given command prefix is
     always used.

   * The set of observers whose bindings are to be called is determined when
     '''hook call''' begins to execute, and does not change thereafter, except
     that deleted bindings are not called.

In particular:

   * If $o's binding to $s and $h is deleted, and $o's binding has not yet
     been called during this execution of '''hook call $s $h''', it will not
     be called.  (Note that it might already have been called; and in all
     likelihood, it is probably deleting itself.)

   * If $o changes the command prefix that's bound to $s and $h, and if $o's
     binding has not yet been called during this execution of '''hook call $s
     $h''', the new binding will be called when the time comes.  (But again,
     it is probably $o's binding that is is making the change.)

   * If a new observer is bound to $s and $h, its binding will not be called
     until the next invocation of '''hook call $s $h'''.

~~~ Discussion

'''Optional Observers:''' It has been suggested that the ''observer'' argument
should follow the ''cmdprefix'' argument; if it is omitted, an observer name
would be automatically generated.  However, the ''observer'' name is
frequently used in practice, and is likely to be much shorter than the
''cmdprefix'', which might be quite long.  As a general rule, short arguments
following long ones tend to get lost visually; keeping the ''observer'' before
the ''cmdprefix'' leads to more easily readable code.

~~ Call Subcommand

 > '''hook call''' ''subject hook'' ?''args...''?

This command is called when the named ''subject'' wishes to call the named
''hook''.  All relevant bindings are called with the specified arguments in
the global namespace. Note that the bindings are called synchronously, before
'''hook call''' returns; this allows the ''args'' to include references to
entities that will be cleaned up as soon as the hook has been called.

The order in which the bindings are called is not guaranteed.  If sequence
among observers must be preserved, define one observer and have its bindings
call the other callbacks directly in the proper sequence.

Because the '''hook''' mechanism is intended to support loose coupling, it is
presumed that the ''subject'' has no knowledge of the observers, nor any
expectation regarding return values.  This has a number of implications:

   * '''hook call''' returns the empty string.

   * Normal return values from observer bindings are ignored.

   * Errors and other exceptional returns propagate normally by default.  This
     will rarely be what is wanted, because the subjects usually have no
     knowledge of the observers and will therefore have no particular
     competence at handling their errors.  That makes it an application issue,
     and so applications will usually want to define an '''-errorcommand'''.

If the '''-errorcommand''' configuration option has a non-empty value, its
value will be invoked for all errors and other exceptional returns in observer
bindings.  See '''hook configure''', below, for more information on
configuration options.

Also, see below for possible extensions to '''hook call'''.

~~ Forget Subcommand

 > '''hook forget''' ''object''

This command deletes any existing bindings in which the named object appears
as either the ''subject'' or the ''observer''.

Bindings deleted by '''hook forget''' will never be called again.  In
particular,

  * If an observer is forgotten during a call to '''hook call''', any uncalled
    binding it might have had to the relevant subject and hook will '''not'''
    be called subsequently.

  * If a subject $s is forgotten during a call to '''hook call $s $h''',
    '''hook call''' will return as soon as the current binding returns.  No
    further bindings will be called.

~~ Configuration Subcommands

 > '''hook cget''' ''option''

This command returns the value of one of the '''hook''' command's
configuration options.

 > '''hook configure''' ''option value'' ...

This command sets the value of one or more of the '''hook''' command's
configuration options:

 -errorcommand: If the value of this option is the empty string, "", then
    errors and other exception returns in binding scripts are propagated
    normally.  Otherwise, it must be a command prefix taking three additional
    arguments: a list {''subject hook arglist observer''}, the result string,
    and the return options dictionary.  Given this information, the
    '''-errorcommand''' can choose to log the error, call '''interp
    bgerror''', delete the errant binding (thus preventing the error from
    arising a second time) and so forth.

 -tracecommand: The option's value should be a command prefix taking four
    arguments: a ''subject'', a ''hook'', a list of the hook's ''argument
    values'', and a list of ''objects'' the hook.  The command will be called
    for each hook that is called.  This allows the application to trace hook
    execution for debugging purposes.

~ Example

The ::model module calls the <Update> hook in response to commands that
change the model's data:

|   hook call ::model <Update>

The .view megawidget displays the model state, and needs to know about model
updates.  Consequently, it subscribes to the ::model's <Update> hook.

|   hook bind ::model <Update> .view [list .view ModelUpdate]

When the ::model calls the hook, the .view's ModelUpdate subcommand will be
called.

Later the .view megawidget is destroyed.  In its destructor, it tells the
'''hook''' that it no longer exists:

|   hook forget .view

All bindings involving .view are deleted.

~ Possible Additions

During discussions on the tcl-core mailing list, members suggested a number of
possible additions to the functionality described in the first draft of this
TIP.  Some small capabilities have been added in this draft; however, there
are two significant ones that I have elected to defer, for two reasons:

   * Though reasonable additions, they are somewhat orthogonal to the
     functionality provided here.

   * They are somewhat speculative, as they reflect patterns I've not actually
     used, whereas the functionality described above has been in use in real
     applications for the past five years.

Consequently, I'd rather not delay this TIP until these suggested additions
are mature.  If this TIP is accepted, then these additions can be considered
as TIPs in their own right.

On the other hand, they are genuinely interesting, so I want to mention them
here.

~~ Asynchronous Dispatch

The '''hook call''' command calls bindings synchronously, returning after all
bindings have been called.  An asychronous mode has been proposed, where
bindings would be called in the context of the event loop for even looser
coupling between the subject and the observers.  This is certainly doable;
however, the same effect can be achieved by calling '''hook call''' in an
'''after''' handler.

I've often considered adding a mode like this to our existing implementation,
but have always thought better of it in the end.

~~ Accumulating Binding Return Values

Two members of tcl-core have suggested that '''hook call''' would be useful to
support plug-in architectures if the return values of all bindings called were
properly captured.  This is an interesting notion; but I'm not sure how to get
it right.  In some use cases, it would be enough just to get a list of the
return values.  In other uses cases, the caller might want to know the
observer, the return value, and the complete dictionary of return options.

I don't want to build up all of this return information in the usual case; if
it isn't needed, there's no reason to spend the time accumulating it.
Consequently, what makes sense to me is an option or options that determine
what kind of information should be returned, e.g., '''hook call ?options...?
$s $h ...'''

Given that '''hook call''' currently returns the empty string, this
functionality can easily be added at a later time.

~ Prototype Implementation

A prototype implementation is available at
[http://www.wjduquette.com/notifier/hook-0.1.zip].  It is written in Tcl.  The
prototype implementation should work in both Tcl 8.5 and Tcl 8.6.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|
|
|




|


|




|
|
|



|


|

|



|

|
|
|
|


|
|

|


|


|


|


|





|
|


|
|





|

|

|



|

|


|


|
|
|

|
|


|
|
|
|
|


|

|




|

|
|
|
|
|







|





|
|
|


|
|
|


|

|

|
|
|

|
|
|

|

|

|
|

|






|
|


|







|

|

|


|

|

|


|

|


|
|


|
|


|

|

|


|

|





|

|
|
|


|
|



|




|




|





|

|



|




















|

|



|
|




|

|









|
|

|


|


|


|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327

# TIP 379: Add a Command for Delivering Events Without Tk

	Author:		Will Duquette <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Created:	17-Oct-2010
	Post-History:	
	Keywords:	event
-----

# Abstract

This proposal defines the **hook** ensemble command, which implements the
Subject/Observer pattern.  It allows _subjects_, which may be modules,
objects, widgets, and so forth, to synchronously call _hooks_ which may be
bound to an arbitrary number of subscribers, called _observers_.  A subject
may call any number of distinct hooks, and any number of observers can bind
callbacks to a particular hook called by a particular subject. Hook bindings
can be queried and deleted.

# Rationale

Tcl modules usually send notifications to other modules in two ways: via Tk
events, and via callback options like the text widget's **-yscrollcommand**
option.  Tk events are available only in Tk, and callback options require
tight coupling between the modules sending and receiving the notification.

Loose coupling between sender and receiver is often desirable, however.  In
Model/View/Controller terms, a View can send a command \(stemming from user
input\) to the Controller, which updates the Model.  The Model can then call a
hook _to which all relevant Views subscribe._  The Model is decoupled from
the Views, and indeed need not know whether any Views actually exist.

At present, Tcl/Tk has no standard mechanism for implementing loose coupling
of this kind.  This proposal defines a new command, **hook**, which
implements just such a mechanism.

# Hook Bindings

The **hook** command manages a collection of hook bindings.  A hook binding
has four elements:

   * A
     _subject_: the name of the entity that will be calling the hook.

   * The _hook_ itself. A hook usually reflects some occurrence in the life
     of the _subject_ that other entities might care to know about.  A
     _hook_ has a name, and may also have arguments.  Hook names are
     arbitrary strings.  Each _subject_ must document the names and
     arguments of the hooks it can call.

   * The name of the _observer_ that wishes to receive the _hook_ from
     the _subject_.

   * A command prefix to which the _hook_ arguments will be appended when
     the binding is executed.

## Subjects and Observers

For convenience, this TIP collectively refers to subjects and observers as
_objects_, while placing no requirements on how these _objects_ are
actually implemented.  An object can be a a TclOO or Snit or XOTcl object, a
Tcl command, a namespace, a module, a pseudo-object managed by some other
object \(as tags are managed by the Tk text widget\) or simply a well-known
name.

Subject and observer names are arbitrary strings; however, as **hook** might
be used at the package level, it's necessary to have conventions that avoid
name collisions between packages written by different people.

Therefore, any subject or observer name used in core or package level code
should look like a Tcl command name, and should be defined in a namespace
owned by the package.  Consider, for example, an ensemble command **::foo**
that creates a set of pseudo-objects and uses **hook** to send
notifications.  The pseudo-objects have names that are not commands and exist
in their own namespace, rather like file handles do.  To avoid name collisions
with subjects defined by other packages, users of **hook**, these
**::foo** handles should have names like **::foo::1**, **::foo::2**, and
so on.

Because object names are arbitrary strings, application code can use whatever
additional conventions are dictated by the needs of the application.

# Specification

The **hook** command is an ensemble command with the following subcommands:

## Bind Subcommand

This subcommand is used to create, update, delete, and query hook bindings.

 > **hook bind** ?_subject_? ?_hook_? ?_observer_? ?_cmdPrefix_?

Called with no arguments, **hook bind** returns a list of the subjects with
hooks to which observers are currently bound.

Called with one argument, a _subject_, **hook bind** returns a list of the
subject's hooks to which observers are currently bound.

Called with two arguments, a _subject_ and a _hook_, **hook bind**
returns a list of the observers which are currently bound to this _subject_
and _hook_.

Called with three arguments, a _subject_, a _hook_, and an _observer_,
**hook bind** returns the binding proper, the command prefix to be called
when the hook is called, or the empty string if there is no such binding.

Called with four arguments, **hook bind** creates, updates, or deletes a
binding.  If _cmdPrefix_ is the empty string, **hook bind** deletes any
existing binding for the _subject_, _hook_, and _observer_; nothing is
returned.  Otherwise, _cmdPrefix_ must be a command prefix taking as many
additional arguments as are documented for the _subject_ and _hook_. The
binding is added or updated, and the observer is returned.

If the _observer_ is the empty string, "", **hook** will create a new
binding using an automatically generated observer name of the form
**::hook::ob**<_number_>.  The automatically generated name will be
returned, and can be used to query, update, and delete the binding as usual.
If automated observer names are always used, the observer name effectively
becomes a unique binding ID.

### Binds During Calls

It is possible to call **hook bind** to create or delete a binding to a
_subject_ and _hook_ while in an observer binding for that same
_subject_ and _hook_.  The following rules determine what happens when
**hook bind $s $h $o $binding** is called during the execution of **hook
call $s $h**:

   * No binding is ever called after it is deleted.

   * When a binding is called, the most recently given command prefix is
     always used.

   * The set of observers whose bindings are to be called is determined when
     **hook call** begins to execute, and does not change thereafter, except
     that deleted bindings are not called.

In particular:

   * If $o's binding to $s and $h is deleted, and $o's binding has not yet
     been called during this execution of **hook call $s $h**, it will not
     be called.  \(Note that it might already have been called; and in all
     likelihood, it is probably deleting itself.\)

   * If $o changes the command prefix that's bound to $s and $h, and if $o's
     binding has not yet been called during this execution of **hook call $s
     $h**, the new binding will be called when the time comes.  \(But again,
     it is probably $o's binding that is is making the change.\)

   * If a new observer is bound to $s and $h, its binding will not be called
     until the next invocation of **hook call $s $h**.

### Discussion

**Optional Observers:** It has been suggested that the _observer_ argument
should follow the _cmdprefix_ argument; if it is omitted, an observer name
would be automatically generated.  However, the _observer_ name is
frequently used in practice, and is likely to be much shorter than the
_cmdprefix_, which might be quite long.  As a general rule, short arguments
following long ones tend to get lost visually; keeping the _observer_ before
the _cmdprefix_ leads to more easily readable code.

## Call Subcommand

 > **hook call** _subject hook_ ?_args..._?

This command is called when the named _subject_ wishes to call the named
_hook_.  All relevant bindings are called with the specified arguments in
the global namespace. Note that the bindings are called synchronously, before
**hook call** returns; this allows the _args_ to include references to
entities that will be cleaned up as soon as the hook has been called.

The order in which the bindings are called is not guaranteed.  If sequence
among observers must be preserved, define one observer and have its bindings
call the other callbacks directly in the proper sequence.

Because the **hook** mechanism is intended to support loose coupling, it is
presumed that the _subject_ has no knowledge of the observers, nor any
expectation regarding return values.  This has a number of implications:

   * **hook call** returns the empty string.

   * Normal return values from observer bindings are ignored.

   * Errors and other exceptional returns propagate normally by default.  This
     will rarely be what is wanted, because the subjects usually have no
     knowledge of the observers and will therefore have no particular
     competence at handling their errors.  That makes it an application issue,
     and so applications will usually want to define an **-errorcommand**.

If the **-errorcommand** configuration option has a non-empty value, its
value will be invoked for all errors and other exceptional returns in observer
bindings.  See **hook configure**, below, for more information on
configuration options.

Also, see below for possible extensions to **hook call**.

## Forget Subcommand

 > **hook forget** _object_

This command deletes any existing bindings in which the named object appears
as either the _subject_ or the _observer_.

Bindings deleted by **hook forget** will never be called again.  In
particular,

  * If an observer is forgotten during a call to **hook call**, any uncalled
    binding it might have had to the relevant subject and hook will **not**
    be called subsequently.

  * If a subject $s is forgotten during a call to **hook call $s $h**,
    **hook call** will return as soon as the current binding returns.  No
    further bindings will be called.

## Configuration Subcommands

 > **hook cget** _option_

This command returns the value of one of the **hook** command's
configuration options.

 > **hook configure** _option value_ ...

This command sets the value of one or more of the **hook** command's
configuration options:

 -errorcommand: If the value of this option is the empty string, "", then
    errors and other exception returns in binding scripts are propagated
    normally.  Otherwise, it must be a command prefix taking three additional
    arguments: a list \{_subject hook arglist observer_\}, the result string,
    and the return options dictionary.  Given this information, the
    **-errorcommand** can choose to log the error, call **interp
    bgerror**, delete the errant binding \(thus preventing the error from
    arising a second time\) and so forth.

 -tracecommand: The option's value should be a command prefix taking four
    arguments: a _subject_, a _hook_, a list of the hook's _argument
    values_, and a list of _objects_ the hook.  The command will be called
    for each hook that is called.  This allows the application to trace hook
    execution for debugging purposes.

# Example

The ::model module calls the <Update> hook in response to commands that
change the model's data:

	   hook call ::model <Update>

The .view megawidget displays the model state, and needs to know about model
updates.  Consequently, it subscribes to the ::model's <Update> hook.

	   hook bind ::model <Update> .view [list .view ModelUpdate]

When the ::model calls the hook, the .view's ModelUpdate subcommand will be
called.

Later the .view megawidget is destroyed.  In its destructor, it tells the
**hook** that it no longer exists:

	   hook forget .view

All bindings involving .view are deleted.

# Possible Additions

During discussions on the tcl-core mailing list, members suggested a number of
possible additions to the functionality described in the first draft of this
TIP.  Some small capabilities have been added in this draft; however, there
are two significant ones that I have elected to defer, for two reasons:

   * Though reasonable additions, they are somewhat orthogonal to the
     functionality provided here.

   * They are somewhat speculative, as they reflect patterns I've not actually
     used, whereas the functionality described above has been in use in real
     applications for the past five years.

Consequently, I'd rather not delay this TIP until these suggested additions
are mature.  If this TIP is accepted, then these additions can be considered
as TIPs in their own right.

On the other hand, they are genuinely interesting, so I want to mention them
here.

## Asynchronous Dispatch

The **hook call** command calls bindings synchronously, returning after all
bindings have been called.  An asychronous mode has been proposed, where
bindings would be called in the context of the event loop for even looser
coupling between the subject and the observers.  This is certainly doable;
however, the same effect can be achieved by calling **hook call** in an
**after** handler.

I've often considered adding a mode like this to our existing implementation,
but have always thought better of it in the end.

## Accumulating Binding Return Values

Two members of tcl-core have suggested that **hook call** would be useful to
support plug-in architectures if the return values of all bindings called were
properly captured.  This is an interesting notion; but I'm not sure how to get
it right.  In some use cases, it would be enough just to get a list of the
return values.  In other uses cases, the caller might want to know the
observer, the return value, and the complete dictionary of return options.

I don't want to build up all of this return information in the usual case; if
it isn't needed, there's no reason to spend the time accumulating it.
Consequently, what makes sense to me is an option or options that determine
what kind of information should be returned, e.g., **hook call ?options...?
$s $h ...**

Given that **hook call** currently returns the empty string, this
functionality can easily be added at a later time.

# Prototype Implementation

A prototype implementation is available at
<http://www.wjduquette.com/notifier/hook-0.1.zip> .  It is written in Tcl.  The
prototype implementation should work in both Tcl 8.5 and Tcl 8.6.

# Copyright

This document has been placed in the public domain.

Name change from tip/38.tip to tip/38.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149

TIP:		38
Title:          Add Support for Default Bindtags
Version:	$Revision: 1.5 $
Author:         Bryan Oakley <[email protected]>
State:		Withdrawn
Type:           Project
Vote:		Pending
Created:	27-Jun-2001
Tcl-Version:    8.5
Post-History:	


~ Abstract

This TIP proposes to add support for the ability to change the default
list of bindtags for a class of widgets.

~ Introduction

Bindtags are an extremely useful addition to the Tk toolkit.  By
modifying the bindtags for a given widget, enhanced bindings can be
added, or default behaviors removed, without modifying actual
bindings.

At present, the default bindtags for a widget are fixed.  All widgets
are created with the same default bindtags.  If an application
programmer wants to alter the bindtags for a widget, she must do so on
a case by case basis.

By allowing the programmer to define their own default bindtags, one
can leverage the power of bindtags with fewer lines of code.  In
addition, changing the default bindtags can not only affect all
widgets in a block of code, but widgets that are created at runtime,
even if created by imported packages that are beyond the programmer's
control.

~ Specification

An enhancement to the bindtags command is suggested.  At present, the
only valid use of bindtags is to include a widget name as the first
argument.  Therefore, adding a new parameter that does not begin with
a dot will not break any existing scripts (that is to say, any script
that presently has the command ''bindtags default'' is broken).

This TIP proposes the following enhancement to the bindtags syntax:

| bindtags default class tagList

''default'' is the literal name of a subcommand

''class'' is a widget class (e.g. Listbox, Text, etc) or ''*'' to
signify all classes.  A default for a specific class will override the
default for all.

''tagList'' is a Tcl list of bindtags, with support for the following
meta-characters, ala bind:

 %C: the widget class

 %W: the widget path for a specific instance of a widget

 %%: replaced with a single %

For example:

| bindtags default Text [list Special %W %C . all]
| => Special %W %C . all
| text .t
| => .t
| bindtags .t
| => Special .t Text . all

If ''tagList'' is null (e.g. ''bindtags default Text {}''), the
default bindtag reverts to the existing behavior.  Because of this it
is not possible to associate a null bindtag list to a widget, but it's
doubtful that would ever be an issue.  One could just as easily
associate a bogus bindtag that has no bindings to get the same result.
(As an alternate suggestion, we could allow null bindtag lists, and
use ''bindtags default Text'' without a tagList to specify that the
core defaults be used).

When a widget is created, its default bindtags will be those specified
by the programmer via the enhanced syntax.  If no defaults have been
specified, the current behavior will be used.  For widgets that take a
-class parameter (e.g. frames), it will choose the bindtags based on
its requested class rather than its base class.  For example, ''frame
.foo -class Combobox'' will use the bindtags for the class
''Combobox'' rather than the class ''Frame''.

~ Rationale

Occasionally it is desirable to add a special bindtag to the front or
end of the bindtag list for all widgets in an application.  Or, one
way want to replace the widget class bindtag with their own or remove
it altogether.  Without a way to specify a default, a programmer must
issue a bindtag command for every widget after it is created.  This
has an impact on overall performance.  In addition, it can be a source
of errors over time; if a new programmer begins work on a project, she
may not realize that widgets need this new bindtag and fail to add it
in her code.

In addition, when widgets are created dynamically during the course of
a user's interaction with the system (for example, when a dialog is
created before it is popped up), the bindtags must be added at
runtime.  Often this is impractical if the dialog or widget(s) belong
to an imported package that the programmer can't modify.

~ Alternatives to this TIP

An alternative way to implement this TIP might be to modify each
widget command such that it becomes configurable.  An example might
be:

| button configure -bindtags {Special %W %C . all}
| => Special %W %C . all
| button .foo
| => .foo
| bindtags .foo
| Special .foo Button . all

Given that the widget commands now have no notion of class-level
configuration values, it seems awkward to introduce it at this time.
It would, however, open up the door for adding other features in
future versions of Tk.  I can envision, for example, ''button
configure -renderer myButtonRenderProc'', which would call
myButtonRenderProc to render button widgets instead of using the
default C-based renderer.  This might make it possible to support a
pluggable look and feel some day.

Keeping all of the bindtags interaction with the bindtags command
seems like a better way to go.

~ Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > Perhaps some of the ideas behind these TIPs should be incorporated
   into some new TIP on making megawidget support better, but none of
   these TIPs really stand on their own.  (38 isn't a good idea, since
   alteration of the bindtags for all widgets of a class at once is a
   bad idea, and it is better when rolling your own megawidget classes
   to put the setting up of the bindtags in there.  39 and 42 just
   clash with each other as soon as you have two different codebases
   trying to use a single widget.)

~ Copyright

This document has been placed in the public domain with great vigor.

<
|
<
|
|
|
|
|
|
|
>

|




|


















|




|
|



|

|

|



|










|
|
|
|
|
|

|




|
|
|




|
|
|
|

|












|
|
|


|





|
|
|
|
|
|




|
|







|







|




|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149

# TIP 38: Add Support for Default Bindtags

	Author:         Bryan Oakley <[email protected]>
	State:		Withdrawn
	Type:           Project
	Vote:		Pending
	Created:	27-Jun-2001
	Tcl-Version:    8.5
	Post-History:	
-----

# Abstract

This TIP proposes to add support for the ability to change the default
list of bindtags for a class of widgets.

# Introduction

Bindtags are an extremely useful addition to the Tk toolkit.  By
modifying the bindtags for a given widget, enhanced bindings can be
added, or default behaviors removed, without modifying actual
bindings.

At present, the default bindtags for a widget are fixed.  All widgets
are created with the same default bindtags.  If an application
programmer wants to alter the bindtags for a widget, she must do so on
a case by case basis.

By allowing the programmer to define their own default bindtags, one
can leverage the power of bindtags with fewer lines of code.  In
addition, changing the default bindtags can not only affect all
widgets in a block of code, but widgets that are created at runtime,
even if created by imported packages that are beyond the programmer's
control.

# Specification

An enhancement to the bindtags command is suggested.  At present, the
only valid use of bindtags is to include a widget name as the first
argument.  Therefore, adding a new parameter that does not begin with
a dot will not break any existing scripts \(that is to say, any script
that presently has the command _bindtags default_ is broken\).

This TIP proposes the following enhancement to the bindtags syntax:

	 bindtags default class tagList

_default_ is the literal name of a subcommand

_class_ is a widget class \(e.g. Listbox, Text, etc\) or _\*_ to
signify all classes.  A default for a specific class will override the
default for all.

_tagList_ is a Tcl list of bindtags, with support for the following
meta-characters, ala bind:

 %C: the widget class

 %W: the widget path for a specific instance of a widget

 %%: replaced with a single %

For example:

	 bindtags default Text [list Special %W %C . all]
	 => Special %W %C . all
	 text .t
	 => .t
	 bindtags .t
	 => Special .t Text . all

If _tagList_ is null \(e.g. _bindtags default Text \{\}_\), the
default bindtag reverts to the existing behavior.  Because of this it
is not possible to associate a null bindtag list to a widget, but it's
doubtful that would ever be an issue.  One could just as easily
associate a bogus bindtag that has no bindings to get the same result.
\(As an alternate suggestion, we could allow null bindtag lists, and
use _bindtags default Text_ without a tagList to specify that the
core defaults be used\).

When a widget is created, its default bindtags will be those specified
by the programmer via the enhanced syntax.  If no defaults have been
specified, the current behavior will be used.  For widgets that take a
-class parameter \(e.g. frames\), it will choose the bindtags based on
its requested class rather than its base class.  For example, _frame
.foo -class Combobox_ will use the bindtags for the class
_Combobox_ rather than the class _Frame_.

# Rationale

Occasionally it is desirable to add a special bindtag to the front or
end of the bindtag list for all widgets in an application.  Or, one
way want to replace the widget class bindtag with their own or remove
it altogether.  Without a way to specify a default, a programmer must
issue a bindtag command for every widget after it is created.  This
has an impact on overall performance.  In addition, it can be a source
of errors over time; if a new programmer begins work on a project, she
may not realize that widgets need this new bindtag and fail to add it
in her code.

In addition, when widgets are created dynamically during the course of
a user's interaction with the system \(for example, when a dialog is
created before it is popped up\), the bindtags must be added at
runtime.  Often this is impractical if the dialog or widget\(s\) belong
to an imported package that the programmer can't modify.

# Alternatives to this TIP

An alternative way to implement this TIP might be to modify each
widget command such that it becomes configurable.  An example might
be:

	 button configure -bindtags {Special %W %C . all}
	 => Special %W %C . all
	 button .foo
	 => .foo
	 bindtags .foo
	 Special .foo Button . all

Given that the widget commands now have no notion of class-level
configuration values, it seems awkward to introduce it at this time.
It would, however, open up the door for adding other features in
future versions of Tk.  I can envision, for example, _button
configure -renderer myButtonRenderProc_, which would call
myButtonRenderProc to render button widgets instead of using the
default C-based renderer.  This might make it possible to support a
pluggable look and feel some day.

Keeping all of the bindtags interaction with the bindtags command
seems like a better way to go.

# Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > Perhaps some of the ideas behind these TIPs should be incorporated
   into some new TIP on making megawidget support better, but none of
   these TIPs really stand on their own.  \(38 isn't a good idea, since
   alteration of the bindtags for all widgets of a class at once is a
   bad idea, and it is better when rolling your own megawidget classes
   to put the setting up of the bindtags in there.  39 and 42 just
   clash with each other as soon as you have two different codebases
   trying to use a single widget.\)

# Copyright

This document has been placed in the public domain with great vigor.

Name change from tip/380.tip to tip/380.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

TIP:		380
Title:		TclOO Slots for Flexible Declarations
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Post-History:	
Version:	$Revision: 1.5 $
Author:		Donal K. Fellows <[email protected]>
Created:	20-Oct-2010


~ Abstract

This TIP proposes a system that enables a more flexible system of handling all
declarations relating to classes and objects that resolve to control over a
list of things. This system, which will use TclOO to configure itself, will
enable the scripting of additional mechanisms for manipulating declarations
and will also include a change to the default behavior of the '''filter''' and
'''variable''' declarations, where the standard "replace everything" behavior
was found to be non-obvious in practice. In order to enable this, the exact
behavior of the '''unknown''' method mechanism will be slightly varied.

~ Rationale

Substantial deployment experience with TclOO now exists, and one of the things
that has been consistently found to be surprising has been the way that the
'''variable''' declaration (part of '''oo::define''' and '''oo::objdefine''')
replaces the current list of declared variables. Personal experimentation has
indicated that the '''filter''' declaration is just as surprising, though it
is admittedly less frequently used. Therefore it is desirable to alter the way
such declarations work so that they append to the list of variables (or
filters, depending on what is being declared).

However, if this is being done then there is a need for substantial complexity
to be added; there must be ''some'' way to set the list of things being
declared or clear it as well as appending to it. Moreover, at the base level
both '''superclass''' and '''mixin''' declarations are basically the same
structure; a list of things. For moral consistency, it becomes necessary to
apply the same basic rules there, though with different defaults; in practice
the default "replace" rule is suitable in for both those two cases.

Note that for the declarations not mentioned, their natural model is not that
of a list so there is no underlying unity of declaration system possible at
this level. They will be left unchanged by this TIP.

~ Proposed Change

My proposed solution is the introduction of a new standard class,
'''::oo::Slot''', whose instances will provide configuration services to the
'''oo::define''' and '''oo::objdefine''' commands. The proposed definition of
the class will be this:

|oo::define oo::Slot {
|    method Get {} {error unimplemented}
|    method Set list {error unimplemented}
|    method --default-operation args {error unimplemented}
|    method -set args {
|        tailcall my Set $args
|    }

|    method -append args {
|        tailcall my Set [list \
|                {*}[uplevel 1 [list [namespace which my] Get]] {*}$args]
|    }

|    method -clear {} {
|        tailcall my Set {}
|    }

|    method unknown {args} {
|        if {[llength $args] == 0} {
|            tailcall my --default-operation
|        } elseif {![string match -* [lindex $args 0]]} {
|            tailcall my --default-operation {*}$args
|        }

|        next {*}$args
|    }

|    export -set -append -clear
|    unexport unknown destroy
|}


It will be up to the instances (whose names do ''not'' form part of this
specification) to define appropriate interpretations for the '''Get''',
'''Set''' and '''--default-operation''' methods, with the last being envisaged
as an ideal fit for being done by one of the other methods, with the
connection being made by '''forward'''.

In order to enable this, a small change is required to the '''unknown'''
method mechanism. This change is that in the case that there is no method name
at all passed to a call into an object, that will have to be handled by
passing into the unknown method mechanism. This will only have a significant
impact on declarations of the '''unknown''' method where the formal argument
list was ''args''; in the other cases there is typically a required first
formal argument and that leads under the current implementation of methods to
the same error message as currently defined. Since this is a rare case of a
rarely used mechanism, I judge that this is likely to be an acceptable
semantic change.

The real major change here is that for certain things (i.e., '''variable''',
'''superclass''', '''mixin''' and '''filter''' declarations) it becomes
trickier to use these with named things whose names start with a "-"
character. I believe this to be a reasonable and minimal trade-off, given that
in return we are getting more natural usage for many users while maintaining a
standard mechanism for a whole way of handling declarations.

~ Reference Implementation

See SF Patch #3084339 [https://sourceforge.net/support/tracker.php?aid=3084339]

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
>

|





|
|

|

|



|

|

|
|


|

|








|


|
|


|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
<
>
|
|
|
|
|
<
>
|
<
>
|
|
<
|
>
|
|
|

|

|



|
|





|
|





|

|

|


>

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

# TIP 380: TclOO Slots for Flexible Declarations
	State:		Final
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Done
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	20-Oct-2010
-----

# Abstract

This TIP proposes a system that enables a more flexible system of handling all
declarations relating to classes and objects that resolve to control over a
list of things. This system, which will use TclOO to configure itself, will
enable the scripting of additional mechanisms for manipulating declarations
and will also include a change to the default behavior of the **filter** and
**variable** declarations, where the standard "replace everything" behavior
was found to be non-obvious in practice. In order to enable this, the exact
behavior of the **unknown** method mechanism will be slightly varied.

# Rationale

Substantial deployment experience with TclOO now exists, and one of the things
that has been consistently found to be surprising has been the way that the
**variable** declaration \(part of **oo::define** and **oo::objdefine**\)
replaces the current list of declared variables. Personal experimentation has
indicated that the **filter** declaration is just as surprising, though it
is admittedly less frequently used. Therefore it is desirable to alter the way
such declarations work so that they append to the list of variables \(or
filters, depending on what is being declared\).

However, if this is being done then there is a need for substantial complexity
to be added; there must be _some_ way to set the list of things being
declared or clear it as well as appending to it. Moreover, at the base level
both **superclass** and **mixin** declarations are basically the same
structure; a list of things. For moral consistency, it becomes necessary to
apply the same basic rules there, though with different defaults; in practice
the default "replace" rule is suitable in for both those two cases.

Note that for the declarations not mentioned, their natural model is not that
of a list so there is no underlying unity of declaration system possible at
this level. They will be left unchanged by this TIP.

# Proposed Change

My proposed solution is the introduction of a new standard class,
**::oo::Slot**, whose instances will provide configuration services to the
**oo::define** and **oo::objdefine** commands. The proposed definition of
the class will be this:

	oo::define oo::Slot {
	    method Get {} {error unimplemented}
	    method Set list {error unimplemented}
	    method --default-operation args {error unimplemented}
	    method -set args {
	        tailcall my Set $args

	    }
	    method -append args {
	        tailcall my Set [list \
	                {*}[uplevel 1 [list [namespace which my] Get]] {*}$args]

	    }
	    method -clear {} {
	        tailcall my Set {}

	    }
	    method unknown {args} {
	        if {[llength $args] == 0} {
	            tailcall my --default-operation
	        } elseif {![string match -* [lindex $args 0]]} {
	            tailcall my --default-operation {*}$args

	        }
	        next {*}$args

	    }
	    export -set -append -clear
	    unexport unknown destroy

	}

It will be up to the instances \(whose names do _not_ form part of this
specification\) to define appropriate interpretations for the **Get**,
**Set** and **--default-operation** methods, with the last being envisaged
as an ideal fit for being done by one of the other methods, with the
connection being made by **forward**.

In order to enable this, a small change is required to the **unknown**
method mechanism. This change is that in the case that there is no method name
at all passed to a call into an object, that will have to be handled by
passing into the unknown method mechanism. This will only have a significant
impact on declarations of the **unknown** method where the formal argument
list was _args_; in the other cases there is typically a required first
formal argument and that leads under the current implementation of methods to
the same error message as currently defined. Since this is a rare case of a
rarely used mechanism, I judge that this is likely to be an acceptable
semantic change.

The real major change here is that for certain things \(i.e., **variable**,
**superclass**, **mixin** and **filter** declarations\) it becomes
trickier to use these with named things whose names start with a "-"
character. I believe this to be a reasonable and minimal trade-off, given that
in return we are getting more natural usage for many users while maintaining a
standard mechanism for a whole way of handling declarations.

# Reference Implementation

See SF Patch \#3084339 <https://sourceforge.net/support/tracker.php?aid=3084339> 

# Copyright

This document has been placed in the public domain.

Name change from tip/381.tip to tip/381.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

TIP:		381
Title:		Call Chain Introspection and Control
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Post-History:	
Version:	$Revision: 1.9 $
Author:		Donal K. Fellows <[email protected]>
Created:	20-Oct-2010
Keywords:	TclOO, iTcl


~ Abstract

This TIP proposes mechanisms for inspecting the TclOO call chain for a
particular method, both externally via '''info''' and from within a call to
that method. It also proposes a mechanism that will allow the traversal of the
call chain in a more controlled way than at present with the '''next'''
command.

~ Rationale

Experience with TclOO in deployment has shown that the call chain mechanism
used for identifying method implementations to bind to a particular method
call is not just a powerful system, but also fairly difficult to understand.
In particular, there is currently no way to discover what implementations of a
method will be actually called, which makes debugging more difficult than it
ought to be.

In addition, it has been found that it is quite difficult to manage multiple
inheritance with TclOO. In particular, when a "diamond" inheritance graph is
constructed where the different arms of the graph require different arguments,
it is exceptionally difficult to ensure that the correct arguments get
delivered to the right constructors, this being a requirement for some of the
ways in which people use [[incr Tcl]] and build megawidgets. Arguably, in
these cases it would be perhaps better for code to use delegation as a class
composition mechanism, but it is not the place of TclOO to impose such a
policy. As such, there needs to be a mechanism to allow more precise runtime
control over the traversal of call chain (control over the construction of the
chain would not be so useful; there simply is no right order that can ensure
that immiscible constructor arguments get passed correctly).

~ Proposed Changes

There will be the the following subcommands of '''info''' added:

 > '''info object call''' ''objectName methodName''

This will return a list describing the methods used to implement a call to the
given ''methodName'' on the given ''objectName''. It will be an error to call
it on anything that is not an object, but in the case that ''methodName'' does
not describe a (visible) method, the returned list will describe how things
are handled by '''unknown''' processing.

Each element of the list will be a tuple. The first element of the tuple will
be one of '''filter''', '''method''' and '''unknown''' to indicate whether it
is a filter, a normal method call, or a special method call used to handle
unknown methods (i.e., with the method name as an additional argument); the
remainder of the tuple's interpretation will depend on which it is.  The
second element will be the name of the method implementation (always
'''unknown''' in the case of unknown handling, except where that is
intercepted by a filter).  The third element will be the literal '''object'''
or the fully-qualified name of the class of that provided the implementation
of the method or filter (NB: not necessarily the class that enabled the
filtering through that name). The fourth element will be the type of the
method implementation (i.e., as described by '''info object methodtype''' or
'''info class methodtype''', depending on where the method is declared).

 > '''info class call''' ''className methodName''

This will be similar to '''info object call''', but will instead describe what
would happen with a stereotypical instance of ''className''.

In addition, there will be an extra subcommand of '''self''':

 > '''self call'''

This will return a list of two items, the first being the list that would have
been returned by '''info object call''' for this method call, and the second
being an index into the list of the current method (i.e., '''0''' for the
first implementation on the list).

Finally, there will be another command made available inside method bodies to
provide the advanced chain calling described above:

 > '''nextto''' ''className'' ?''arg ...''?

This command will behave just like '''next''' except that it will scan
''forward'' in the current method chain until the implementation of the method
provided by ''className'' is located, and chain to that (while passing in the
''arg''uments given, of course). It will be an error to attempt to call a
class's implementation of a method that is not on the chain, or that is
preceding the currently executing method implementation, and it will not be
possible to jump to filters applied to the method.

~ Reference Implementation

See https://core.tcl.tk/tcloo/timeline?r=development-next2 for the proposed
implementation (notably commit-f5a2cfd0d4).

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|


|

|


|













|



|

|

|

|

|


|
|
|
|


|

|

|
|
|

|
|
|
|

|

|
|

|

|


|
|
|




|

|
|
|
|




|

|
|

|


>

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

# TIP 381: Call Chain Introspection and Control
	State:		Final
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Done
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	20-Oct-2010
	Keywords:	TclOO, iTcl
-----

# Abstract

This TIP proposes mechanisms for inspecting the TclOO call chain for a
particular method, both externally via **info** and from within a call to
that method. It also proposes a mechanism that will allow the traversal of the
call chain in a more controlled way than at present with the **next**
command.

# Rationale

Experience with TclOO in deployment has shown that the call chain mechanism
used for identifying method implementations to bind to a particular method
call is not just a powerful system, but also fairly difficult to understand.
In particular, there is currently no way to discover what implementations of a
method will be actually called, which makes debugging more difficult than it
ought to be.

In addition, it has been found that it is quite difficult to manage multiple
inheritance with TclOO. In particular, when a "diamond" inheritance graph is
constructed where the different arms of the graph require different arguments,
it is exceptionally difficult to ensure that the correct arguments get
delivered to the right constructors, this being a requirement for some of the
ways in which people use [incr Tcl] and build megawidgets. Arguably, in
these cases it would be perhaps better for code to use delegation as a class
composition mechanism, but it is not the place of TclOO to impose such a
policy. As such, there needs to be a mechanism to allow more precise runtime
control over the traversal of call chain \(control over the construction of the
chain would not be so useful; there simply is no right order that can ensure
that immiscible constructor arguments get passed correctly\).

# Proposed Changes

There will be the the following subcommands of **info** added:

 > **info object call** _objectName methodName_

This will return a list describing the methods used to implement a call to the
given _methodName_ on the given _objectName_. It will be an error to call
it on anything that is not an object, but in the case that _methodName_ does
not describe a \(visible\) method, the returned list will describe how things
are handled by **unknown** processing.

Each element of the list will be a tuple. The first element of the tuple will
be one of **filter**, **method** and **unknown** to indicate whether it
is a filter, a normal method call, or a special method call used to handle
unknown methods \(i.e., with the method name as an additional argument\); the
remainder of the tuple's interpretation will depend on which it is.  The
second element will be the name of the method implementation \(always
**unknown** in the case of unknown handling, except where that is
intercepted by a filter\).  The third element will be the literal **object**
or the fully-qualified name of the class of that provided the implementation
of the method or filter \(NB: not necessarily the class that enabled the
filtering through that name\). The fourth element will be the type of the
method implementation \(i.e., as described by **info object methodtype** or
**info class methodtype**, depending on where the method is declared\).

 > **info class call** _className methodName_

This will be similar to **info object call**, but will instead describe what
would happen with a stereotypical instance of _className_.

In addition, there will be an extra subcommand of **self**:

 > **self call**

This will return a list of two items, the first being the list that would have
been returned by **info object call** for this method call, and the second
being an index into the list of the current method \(i.e., **0** for the
first implementation on the list\).

Finally, there will be another command made available inside method bodies to
provide the advanced chain calling described above:

 > **nextto** _className_ ?_arg ..._?

This command will behave just like **next** except that it will scan
_forward_ in the current method chain until the implementation of the method
provided by _className_ is located, and chain to that \(while passing in the
_arg_uments given, of course\). It will be an error to attempt to call a
class's implementation of a method that is not on the chain, or that is
preceding the currently executing method implementation, and it will not be
possible to jump to filters applied to the method.

# Reference Implementation

See <https://core.tcl.tk/tcloo/timeline?r=development-next2> for the proposed
implementation \(notably commit-f5a2cfd0d4\).

# Copyright

This document has been placed in the public domain.

Name change from tip/382.tip to tip/382.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

TIP:		382
Title:		Let tk_getSaveFile ignore file overwrites
Version:	$Revision: 1.6 $
Author:		Pawel Salawa <[email protected]>
Author:		Don Porter <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.5.11
Vote:		Done
Created:	02-Nov-2010
Post-History:	
Keywords:	Tk, dialog


~ Abstract

This document describes new option for '''tk_getSaveFile''' named
'''-confirmoverwrite''' to control whether a warning dialog is displayed
when selecting an existing file for overwriting.

~ Rationale

There's been numerous requests for support for file dialog that allows to
select a file name with no matter if it exists or not.  One workaround was to
use '''ttk::getAppendFile''' from http://wiki.tcl.tk/15897, but it used its
own file dialog, instead of native one.  This TIP makes use of native file
dialog.

~ Specification

The '''tk_getSaveFile''' will accept a '''-confirmoverwrite''' option with
boolean value as its argument.  Default value for this option is "'''true'''".
If value for this option is "'''false'''", then the dialog won't warn user in
case he selects existing file, that he's about to overwrite the file.  The
option will be supported only for '''tk_getSaveFile''', not
for '''tk_getOpenFile'''.  A non-boolean value for this option will raise
an error.

The new option will be recognized and accepted on all platforms.  For
any platform where the underlying windowing system does not permit
the required configuration, the option will have no effect, and the platform
dialog will just do what it does.

~ Compatibility

Default value matches existing behavior.  

~ Reference Implementation

See the '''tip-382''' branch.  It includes implementations for X,
supported Windows, and OSX Carbon.  The proposed option will not be implemented
for Pre-NT Windows.  An implementation for OSX Cocoa may be possible using
the approach outlined at 
[http://stackoverflow.com/questions/1930352/nssavepanel-squelching-the-confirm-replace-dialog/2390780#2390780],
but no such implementation is yet completed.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|
|


|



|



|

|
|
|

|
|







|



|

|



|


|


>

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

# TIP 382: Let tk_getSaveFile ignore file overwrites

	Author:		Pawel Salawa <[email protected]>
	Author:		Don Porter <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.5.11
	Vote:		Done
	Created:	02-Nov-2010
	Post-History:	
	Keywords:	Tk, dialog
-----

# Abstract

This document describes new option for **tk\_getSaveFile** named
**-confirmoverwrite** to control whether a warning dialog is displayed
when selecting an existing file for overwriting.

# Rationale

There's been numerous requests for support for file dialog that allows to
select a file name with no matter if it exists or not.  One workaround was to
use **ttk::getAppendFile** from <http://wiki.tcl.tk/15897,> but it used its
own file dialog, instead of native one.  This TIP makes use of native file
dialog.

# Specification

The **tk\_getSaveFile** will accept a **-confirmoverwrite** option with
boolean value as its argument.  Default value for this option is "**true**".
If value for this option is "**false**", then the dialog won't warn user in
case he selects existing file, that he's about to overwrite the file.  The
option will be supported only for **tk\_getSaveFile**, not
for **tk\_getOpenFile**.  A non-boolean value for this option will raise
an error.

The new option will be recognized and accepted on all platforms.  For
any platform where the underlying windowing system does not permit
the required configuration, the option will have no effect, and the platform
dialog will just do what it does.

# Compatibility

Default value matches existing behavior.  

# Reference Implementation

See the **tip-382** branch.  It includes implementations for X,
supported Windows, and OSX Carbon.  The proposed option will not be implemented
for Pre-NT Windows.  An implementation for OSX Cocoa may be possible using
the approach outlined at 
<http://stackoverflow.com/questions/1930352/nssavepanel-squelching-the-confirm-replace-dialog/2390780#2390780> ,
but no such implementation is yet completed.

# Copyright

This document has been placed in the public domain.

Name change from tip/383.tip to tip/383.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

TIP:            383
Title:          Injecting Code into Suspended Coroutines
Version:        $Revision: 1.4 $
Author:         Alexandre Ferrieux <[email protected]>
Author:         Miguel Sofer <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        03-Dec-2010
Post-History:   
Keywords:       debugging,coroutine,yielded
Tcl-Version:    8.7


~ Abstract

This proposes a new command, '''coroinject''', that allows a programmer to
inject arbitrary code into a suspended coroutine, for execution on next
resumption.

~ Rationale

When debugging complex coroutines - with many yield points and possibly rich
state in local variables - sometimes one would like to inspect their state
"from the outside", i.e., at a point where they are suspended.

A typical situation is that of a big, single-threaded, event+coro system,
where the coro happily enables/disables fileevents along its life, and the
fileevents are one way to resume the coro. At a given point (bug), things get
stalled, with the fileevents disabled. The obvious questions are:

 1. "where" is the coro (at which yield site)? and

 2. what are the values of its local variables?

Both these questions can be answered with the new '''coroinject''' primitive.
The idea is to force a resumption of the coro along with an "immediate
execution of extra code" directive, where the extra code says "dump the call
stack with '''info level''' and '''info frame'''", or "dump the locals", etc.

Another use would be to inject "'''return -code return'''", as an alternative
to renaming to {} for terminating the coro in a way that respects its
'''catch'''/'''finally''' termination handlers. Alternatively, returning with
an error code will have the effect of gathering call stack information in the
'''-errorstack''' options dictionary entry.

At the other end of the spectrum, the injected code can be completely
transparent: either with a forced resumption and injected code ending with
'''yield''', or merely waiting for normal resumption when the app sees fit,
and injected code falling back to normal coro code.

Note that the feature is similar to a proc-entry trace, but coroutine
resumption is not currently a trace target.  Also, it is an intrinsically
"one-shot" mechanism, which makes it a better fit for its debugging purposes.

~ Definition

The new command

 > '''coroinject''' ''coroname'' ''cmd'' ?''arg1 ...''?

prepends to the code to be executed on resumption of the currently suspended
coroutine, ''coroname'', the following code:

 >  ''cmd'' ''arg1...'' ''resumearg''

where ''resumearg'' is the single argument passed to the resumption command
''coroname''.  In turn, the result from the execution of ''cmd'' will be seen
by the coroutine's code as the result of '''yield'''.

Note that:

 1. Resumption itself must be done separately, by calling ''coroname'' later,

 2. If '''coroinject''' is called several times on the same ''coroname''
    before resuming it, the commands pile up in LIFO order.

 3. In combination, the appending of ''resumearg'' and the use of the result
    of ''cmd'' to provide the result of '''yield''', will allow the following
    style of fully transparent injection:

|    proc probe {x y resumearg} {do things $x $y;return $resumearg}
|    coroinject C probe foo bar

~ Naming

Of course, the proposed '''coroinject''' is a placeholder for a suitable name. Alternatives that also make sense are: '''::tcl::coroinject''' and '''interp coroinject'''. Constructive bikeshedding welcome.

~ Reference Implementation

The current '''::tcl::unsupported::inject''' implements most of the
functionality described here, minus the ''resumearg'' passing.  It will be
updated to include it if consensus gathers on this style.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|



|





|

|


|



|


|

|
|
|

|



|






|



|


|

|

|
|
|



|

|


|
|


|
|

|

|

|

|
|


|


>

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

# TIP 383: Injecting Code into Suspended Coroutines

	Author:         Alexandre Ferrieux <[email protected]>
	Author:         Miguel Sofer <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        03-Dec-2010
	Post-History:   
	Keywords:       debugging,coroutine,yielded
	Tcl-Version:    8.7
-----

# Abstract

This proposes a new command, **coroinject**, that allows a programmer to
inject arbitrary code into a suspended coroutine, for execution on next
resumption.

# Rationale

When debugging complex coroutines - with many yield points and possibly rich
state in local variables - sometimes one would like to inspect their state
"from the outside", i.e., at a point where they are suspended.

A typical situation is that of a big, single-threaded, event\+coro system,
where the coro happily enables/disables fileevents along its life, and the
fileevents are one way to resume the coro. At a given point \(bug\), things get
stalled, with the fileevents disabled. The obvious questions are:

 1. "where" is the coro \(at which yield site\)? and

 2. what are the values of its local variables?

Both these questions can be answered with the new **coroinject** primitive.
The idea is to force a resumption of the coro along with an "immediate
execution of extra code" directive, where the extra code says "dump the call
stack with **info level** and **info frame**", or "dump the locals", etc.

Another use would be to inject "**return -code return**", as an alternative
to renaming to \{\} for terminating the coro in a way that respects its
**catch**/**finally** termination handlers. Alternatively, returning with
an error code will have the effect of gathering call stack information in the
**-errorstack** options dictionary entry.

At the other end of the spectrum, the injected code can be completely
transparent: either with a forced resumption and injected code ending with
**yield**, or merely waiting for normal resumption when the app sees fit,
and injected code falling back to normal coro code.

Note that the feature is similar to a proc-entry trace, but coroutine
resumption is not currently a trace target.  Also, it is an intrinsically
"one-shot" mechanism, which makes it a better fit for its debugging purposes.

# Definition

The new command

 > **coroinject** _coroname_ _cmd_ ?_arg1 ..._?

prepends to the code to be executed on resumption of the currently suspended
coroutine, _coroname_, the following code:

 >  _cmd_ _arg1..._ _resumearg_

where _resumearg_ is the single argument passed to the resumption command
_coroname_.  In turn, the result from the execution of _cmd_ will be seen
by the coroutine's code as the result of **yield**.

Note that:

 1. Resumption itself must be done separately, by calling _coroname_ later,

 2. If **coroinject** is called several times on the same _coroname_
    before resuming it, the commands pile up in LIFO order.

 3. In combination, the appending of _resumearg_ and the use of the result
    of _cmd_ to provide the result of **yield**, will allow the following
    style of fully transparent injection:

		    proc probe {x y resumearg} {do things $x $y;return $resumearg}
		    coroinject C probe foo bar

# Naming

Of course, the proposed **coroinject** is a placeholder for a suitable name. Alternatives that also make sense are: **::tcl::coroinject** and **interp coroinject**. Constructive bikeshedding welcome.

# Reference Implementation

The current **::tcl::unsupported::inject** implements most of the
functionality described here, minus the _resumearg_ passing.  It will be
updated to include it if consensus gathers on this style.

# Copyright

This document has been placed in the public domain.

Name change from tip/384.tip to tip/384.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

TIP:            384
Title:          Add File Alteration Monitoring to the Tcl Core
Version:        $Revision: 1.4 $
Author:         Reinhard Max <[email protected]>
Author:         Gerald W. Lester <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        02-Dec-2010
Post-History:   
Keywords:       kqueue,inotify,dnotify,gamin,FSevents,fam
Tcl-Version:    8.7


~ Abstract

This TIP proposes to add capabilities for monitoring changes in the file
system to the Tcl core.

~ Rationale

Most, if not all, platforms supported by Tcl today allow user space processes
to monitor the file system for certain changes such as the creation, deletion,
alteration or renaming of files.

Unfortunately there is no unique cross-platform API for this, so a Tcl core
feature will have to be backed by a series of platform-dependent
implementations and possibly a fallback for platforms that don't have these
monitoring capabilities or instances on which they have been disabled.

Platform-specific APIs which should be supported by the final implementation
(list to be extended):

 * inotify[http://en.wikipedia.org/wiki/Inotify] (Linux)

 * kqueue[http://en.wikipedia.org/wiki/Kqueue] (BSD)

 * FSEvents[http://en.wikipedia.org/wiki/FSEvents] (Mac OS X)

 * TWAPI [http://twapi.magicsplat.com/disk.html#begin_filesystem_monitor] (Windows)

~ Proposal

A new subcommand should get added to the '''file''' command with the following
syntax:

 > '''file monitor''' ''path'' ''callback'' ?''filter''?

This will register ''callback'' to be called from the event loop when one of
the events specified by ''filter'' occurs to the file or directory specified
by ''path''.  Calling '''file monitor''' with an empty callback argument
removes an existing callback from the given path.

The calling conventions for ''callback'' and the syntax of ''filter'' are yet
to be determined.

~ Rejected Alternatives

The '''file''' command was chosen over '''fileevent''' and '''chan event''',
because the object to be monitored is passed by name and not as an open
channel.

As an API, FAM[http://en.wikipedia.org/wiki/File_alteration_monitor] would
have been a more portable alternative, but it requres a daemon to be running
on the local machine and it requires linking against a lib that is licensed
under the LGPL. It might be possible to support FAM as a compile time
alternative to the system's native notification method. There exists a
serverless implementation of a subset of the FAM API, called
Gamin[http://people.gnome.org/~veillard/gamin/index.html], but that's also
licensed under the LGPL.

There exists a Tcl extension for
inotify[https://sourceforge.net/projects/tcl-inotify/], but it is licensed
under the GPL and it's script level API is too close to the inotify primitives
to serve as the basis of a cross-platform abstraction for such
notifications. But it might be a good base for a scripted prototype to sort
out the remaining details of the proposed script level API.

~ Further Ideas

It might be an option to release the C code that unifies the various OS
speciffic mechanisms under a single API as a separate library, so that
projects other than Tcl can use it as well.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|




|











|

|

|

|

|

|

|


|

|
|
|


|


|

|



|





|



|





|





|


>

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

# TIP 384: Add File Alteration Monitoring to the Tcl Core

	Author:         Reinhard Max <[email protected]>
	Author:         Gerald W. Lester <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        02-Dec-2010
	Post-History:   
	Keywords:       kqueue,inotify,dnotify,gamin,FSevents,fam
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to add capabilities for monitoring changes in the file
system to the Tcl core.

# Rationale

Most, if not all, platforms supported by Tcl today allow user space processes
to monitor the file system for certain changes such as the creation, deletion,
alteration or renaming of files.

Unfortunately there is no unique cross-platform API for this, so a Tcl core
feature will have to be backed by a series of platform-dependent
implementations and possibly a fallback for platforms that don't have these
monitoring capabilities or instances on which they have been disabled.

Platform-specific APIs which should be supported by the final implementation
\(list to be extended\):

 * inotify<http://en.wikipedia.org/wiki/Inotify>  \(Linux\)

 * kqueue<http://en.wikipedia.org/wiki/Kqueue>  \(BSD\)

 * FSEvents<http://en.wikipedia.org/wiki/FSEvents>  \(Mac OS X\)

 * TWAPI <http://twapi.magicsplat.com/disk.html#begin_filesystem_monitor>  \(Windows\)

# Proposal

A new subcommand should get added to the **file** command with the following
syntax:

 > **file monitor** _path_ _callback_ ?_filter_?

This will register _callback_ to be called from the event loop when one of
the events specified by _filter_ occurs to the file or directory specified
by _path_.  Calling **file monitor** with an empty callback argument
removes an existing callback from the given path.

The calling conventions for _callback_ and the syntax of _filter_ are yet
to be determined.

# Rejected Alternatives

The **file** command was chosen over **fileevent** and **chan event**,
because the object to be monitored is passed by name and not as an open
channel.

As an API, FAM<http://en.wikipedia.org/wiki/File_alteration_monitor>  would
have been a more portable alternative, but it requres a daemon to be running
on the local machine and it requires linking against a lib that is licensed
under the LGPL. It might be possible to support FAM as a compile time
alternative to the system's native notification method. There exists a
serverless implementation of a subset of the FAM API, called
Gamin<http://people.gnome.org/~veillard/gamin/index.html> , but that's also
licensed under the LGPL.

There exists a Tcl extension for
inotify<https://sourceforge.net/projects/tcl-inotify/> , but it is licensed
under the GPL and it's script level API is too close to the inotify primitives
to serve as the basis of a cross-platform abstraction for such
notifications. But it might be a good base for a scripted prototype to sort
out the remaining details of the proposed script level API.

# Further Ideas

It might be an option to release the C code that unifies the various OS
speciffic mechanisms under a single API as a separate library, so that
projects other than Tcl can use it as well.

# Copyright

This document has been placed in the public domain.

Name change from tip/385.tip to tip/385.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

TIP:            385
Title:          Functional Traces On Variables 
Version:        $Revision: 1.6 $
Author:         Alexandre Ferrieux <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        13-Feb-2011
Post-History:   
Keywords:       Tcl, traces
Tcl-Version:    9.0


~ Abstract

Functional traces are new variants of variable traces, that rely
purely on value passing rather than variable updating. Applied to array
traces, they allow a much more efficient implementation of various storage backends.

~ Rationale

The current variable trace API does not focus on the read or written value;
instead, only the variable (and array key) name is made available to the
callback.  Actual manipulation of the value thus involves updating the
variable within the trace callback: the new, "synthetic" value must be written
for real.

While this approach is acceptable for a scalar variable, in the case of arrays
it forces the "memoize" pattern: whenever reads are done on an array with a
read trace, the read value is actually stored in the array, with no obvious
spot to unset it afterwards. Hence, although we are backing the array with a
function which is called on every read, the memory usage is that of a memoized
function; this does not scale up at all.

A typical situation where this matters, is the use of traces to wrap the
convenient array syntax around another kind of storage (like a pre-existing
dictionary or database): what is intended is that '''$a($x)''' becomes
syntactic sugar for '''[[dict get $d $x]]''', but without duplicating the
storage in the array. This is currently impossible.

The proposed extension to the trace API allows for "functional" traces, in the
usual computing sense of "no side effect": here the value of interest is
passed as an argument to a write trace callback, and taken from the return
value of a read trace callback. This way, no access to the underlying variable
is needed.  The array syntax can become a frontend to just about anything,
without any memory consumption, and with adequate preformance since values are
passed as ''Tcl_Obj''s. Thus functional traces could also be named "virtual variables".

As an extra bonus, "read-only variables" can be implemented efficiently, which
is notably impossible with the current API (since the write trace is called
after the fact, it must rely on another mechanism to retrieve the pre-write
value).

~ Definition

The new subcommands

 > '''trace add variable''' ''name'' '''readf''' ''cmdprefix''

 > '''trace add variable''' ''name'' '''writef''' ''cmdprefix''

 > '''trace add variable''' ''name'' '''unsetf''' ''cmdprefix''

 > '''trace add variable''' ''name'' '''existsf''' ''cmdprefix''

are the functional variants of the existing '''read''', '''write''', and '''unset'''
variable traces. The new '''existsf''' is made possible by the functional style. The ''cmdprefix'' callback API is close to that of current traces, with two variations:

  1. For a '''readf''' or '''existsf''' trace, the callback's returned value is used as the result of the read/exists operation.

  2. For a '''writef''' trace, the value to be written is passed as an extra
     argument to the callback:

 >    ''cmdprefix'' ''name1'' ''name2'' '''writef''' ''value''

In both cases, the value is passed efficiently as a '''Tcl_Obj'''.

~ Demos

Here is the full code exposing a dict as an array:

|     trace add variable a readf [list trdictget ::d]
|     trace add variable a writef [list trdictset ::d]
|     proc trdictget {vv n1 n2 op} {
|         upvar $vv v
|         return [dict get $v $n2]
|     }

|     proc trdictset {vv n1 n2 op x} {
|         upvar $vv v
|         dict set v $n2 $x
|     }


Another example with Pascal-like 1-based numeric indices into a list, with
bound checking, disguised as array keys:

|     trace add variable a readf [list trplistget ::l]
|     trace add variable a writef [list trplistset ::l]
|     proc trplistget {vv n1 n2 op} {
|         upvar $vv v
|         if {($n2<1) || ($n2>[llength $v])} {
|             error "Index $n2 out of range for list $vv"
|         } 

|         return [lindex $v [expr {$n2-1}]]
|     }

|     proc trplistset {vv n1 n2 op x} {
|         upvar $vv v
|         if {($n2<1) || ($n2>[llength $v])} {
|             error "Index $n2 out of range for list $vv"
|         } 

|	 lset v [expr {$n2-1}] $x
|     }


Obviously, the same principle can be applied to an SQLite or TDBC database;
the net result is an instant-loadable "array".

~ Possible Extensions

A natural generalization would be to hook into array-level operations like '''size''', '''names''', '''get''', '''unset''', '''startSearch''', etc. But then, maybe an ensemble/oo API would be preferred (hook one single command prefix for all operations concerning array ''a''). To be discussed.

~ Reference Implementation

Coming soon.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|


|












|
|
|








|


|

|

|



|

|

|

|

|
|

|

|


|

|

|



|
|
|
|
|
<
>
|
|
|
<
|
>



|
|
|
|
|
|
<
>
|
<
>
|
|
|
|
<
>
|
<
|
>



|

|

|



|


>

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

# TIP 385: Functional Traces On Variables

	Author:         Alexandre Ferrieux <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        13-Feb-2011
	Post-History:   
	Keywords:       Tcl, traces
	Tcl-Version:    9.0
-----

# Abstract

Functional traces are new variants of variable traces, that rely
purely on value passing rather than variable updating. Applied to array
traces, they allow a much more efficient implementation of various storage backends.

# Rationale

The current variable trace API does not focus on the read or written value;
instead, only the variable \(and array key\) name is made available to the
callback.  Actual manipulation of the value thus involves updating the
variable within the trace callback: the new, "synthetic" value must be written
for real.

While this approach is acceptable for a scalar variable, in the case of arrays
it forces the "memoize" pattern: whenever reads are done on an array with a
read trace, the read value is actually stored in the array, with no obvious
spot to unset it afterwards. Hence, although we are backing the array with a
function which is called on every read, the memory usage is that of a memoized
function; this does not scale up at all.

A typical situation where this matters, is the use of traces to wrap the
convenient array syntax around another kind of storage \(like a pre-existing
dictionary or database\): what is intended is that **$a\($x\)** becomes
syntactic sugar for **[dict get $d $x]**, but without duplicating the
storage in the array. This is currently impossible.

The proposed extension to the trace API allows for "functional" traces, in the
usual computing sense of "no side effect": here the value of interest is
passed as an argument to a write trace callback, and taken from the return
value of a read trace callback. This way, no access to the underlying variable
is needed.  The array syntax can become a frontend to just about anything,
without any memory consumption, and with adequate preformance since values are
passed as _Tcl\_Obj_s. Thus functional traces could also be named "virtual variables".

As an extra bonus, "read-only variables" can be implemented efficiently, which
is notably impossible with the current API \(since the write trace is called
after the fact, it must rely on another mechanism to retrieve the pre-write
value\).

# Definition

The new subcommands

 > **trace add variable** _name_ **readf** _cmdprefix_

 > **trace add variable** _name_ **writef** _cmdprefix_

 > **trace add variable** _name_ **unsetf** _cmdprefix_

 > **trace add variable** _name_ **existsf** _cmdprefix_

are the functional variants of the existing **read**, **write**, and **unset**
variable traces. The new **existsf** is made possible by the functional style. The _cmdprefix_ callback API is close to that of current traces, with two variations:

  1. For a **readf** or **existsf** trace, the callback's returned value is used as the result of the read/exists operation.

  2. For a **writef** trace, the value to be written is passed as an extra
     argument to the callback:

	 >    _cmdprefix_ _name1_ _name2_ **writef** _value_

In both cases, the value is passed efficiently as a **Tcl\_Obj**.

# Demos

Here is the full code exposing a dict as an array:

	     trace add variable a readf [list trdictget ::d]
	     trace add variable a writef [list trdictset ::d]
	     proc trdictget {vv n1 n2 op} {
	         upvar $vv v
	         return [dict get $v $n2]

	     }
	     proc trdictset {vv n1 n2 op x} {
	         upvar $vv v
	         dict set v $n2 $x

	     }

Another example with Pascal-like 1-based numeric indices into a list, with
bound checking, disguised as array keys:

	     trace add variable a readf [list trplistget ::l]
	     trace add variable a writef [list trplistset ::l]
	     proc trplistget {vv n1 n2 op} {
	         upvar $vv v
	         if {($n2<1) || ($n2>[llength $v])} {
	             error "Index $n2 out of range for list $vv"

	         } 
	         return [lindex $v [expr {$n2-1}]]

	     }
	     proc trplistset {vv n1 n2 op x} {
	         upvar $vv v
	         if {($n2<1) || ($n2>[llength $v])} {
	             error "Index $n2 out of range for list $vv"

	         } 
		 lset v [expr {$n2-1}] $x

	     }

Obviously, the same principle can be applied to an SQLite or TDBC database;
the net result is an instant-loadable "array".

# Possible Extensions

A natural generalization would be to hook into array-level operations like **size**, **names**, **get**, **unset**, **startSearch**, etc. But then, maybe an ensemble/oo API would be preferred \(hook one single command prefix for all operations concerning array _a_\). To be discussed.

# Reference Implementation

Coming soon.

# Copyright

This document has been placed in the public domain.

Name change from tip/386.tip to tip/386.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

TIP:            386
Title:          Relocation of Tcl/Tk Source Control Repositories
Version:        $Revision: 1.4 $
Author:         Kevin B. Kenny <[email protected]>
Author:         Kevin Kenny <[email protected]>
State:          Draft
Type:           Informative
Vote:           Pending
Created:        01-Mar-2011
Post-History:   
Keywords:       Fossil,DVCS


~ Abstract

This TIP describes the changed locations and procedures for source control
for Tcl/Tk.

~ Background

Earlier this year, SourceForge's CVS repositories were attacked by parties
unknown, resulting in an outage of several weeks' duration. Although all data
were eventually recovered, the aftermath of the attack and outage was that
SourceForge staff have formally designated CVS hosting to be a legacy product
and offered assistance with migration to Subversion.

Since for some time the Tcl/Tk maintainers have wanted to transfer the version
control repository to a distributed version control system (DVCS), the
decision has been made to abandon SourceForge and adopt a Fossil repository. A
donor who wishes to remain anonymous has given a reasonably powerful machine,
'''core.tcl.tk''' to the Tcl Community Association and is providing rack space
and bandwidth. The donor has also generously offered to make free shell
accounts to qualified Tcl/Tk developers for CPU- and bandwidth-intensive tasks
such as performance analysis and memory management audits. Interested
developers should contact one of the TCT members listed at the end of this
document.

Needless to say, given the distributed nature of Fossil, we expect several
mirrors to emerge; Richard Hipp of SQLite.org has provided the first one,
appropriately named '''mirror1.tcl.tk'''.

~ Repository Locations

The code base for Tcl itself now resides in a Fossil repository at
[http://core.tcl.tk/tcl/].  The Fossil repository is available for anonymous
cloning and for examination of version control history.  At present, the bug
tracker is disabled.  Similarly, the code base for Tk resides at
[http://core.tcl.tk/tk].  Tcl and Tk developers shall be granted 'push' rights
to the respective repositories.

Developers who are unfamiliar with Fossil are strongly encouraged to consult
the documentation at [http://fossil-scm.org/], in particular, the 'Fossil
Concepts' paper at
[http://fossil-scm.org/index.html/doc/trunk/www/concepts.wiki].  Novices to
Fossil may want to work at least temporarily in 'autosync mode', which allows
a CVS-like workflow.

At present, the bug, feature request and patch trackers will remain on
SourceForge. Any developer hosting a mirror is expected to disable the bug
tracker (it suffices to remove 't' permission from the 'anonymous' user). At
some point we may use a SourceForge-to-Fossil converter for the existing
trackers, and we do not wish to worry about trying to keep SourceForge and
Fossil in sync.

'''mirror1.tcl.tk''' shall be kept up to date by a periodic automatic
synchronization with '''core.tcl.tk'''.  In order to avoid inadvertent
forking, developers are requested not to push to mirrors unless
'''core.tcl.tk''' suffers an extended outage.

Before using a clone from a mirror, developers should verify that it copies
the correct version of the repository at '''core.tcl.tk'''.  This can be
determined by examining the 'project ID', reported by the 'clone'
operation. For Tcl, the ID should be

|    1ec9da4c469c29f4717e2a967fe6b916d9c8c06e

and for Tk, it should be

|    b5a34cc57b6712927bc5fd34ae98433a14c9fdea 

'''UPDATE, June 2013''' The ticket trackers have now also been migrated
from SourceForge to '''core.tcl.tk'''.

~ Workflow

Generally speaking, workflow will follow the description in 
[http://fossil-scm.org/index.html/doc/trunk/www/concepts.wiki#workflow]. 

It is expected that large projects will be conducted on named branches in the
Fossil repository; in fact, such a project should most likely be commenced by
committing to a branch in your local clone. If you do not wish to share your
work with others, you may use a private branch, and Fossil will refrain from
synchronizing it when you synchronize your clone.

Simple bug fixes should be developed on the branch of the ''earliest'' stable
release that you intend to fix, and then merged forward onto the later
releases' branches. It is expected that such "dovetail merges" will be
frequent, so as to control the number of nuisance conflicts that will have to
be resolved when merging.

Questions about Fossil on the Tcl'ers Chat or in comp.lang.tcl are encouraged;
it's essential that all Tcl/Tk developers develop at least some familiarity
with the technology, and it's somewhat new to all of us!

~ Requesting access

Tcl and Tk maintainers may request repository access by emailing one of the
Tcl Core Team members on the following list:

   Joe English, Donal Fellows, Jeff Hobbs, Kevin Kenny, Andreas Kupries, Don
   Porter

all of whom have the required access to add new users to core.tcl.tk.

~ Acknowledgments

Major thanks are due to Roy Keene, for leading the migration effort, to J�rg
Sonnenberger (author of cvs2fossil) and D. Richard Hipp (author of fossil
itself) for many hours of unpaid support in getting the conversion to go, to
Mark Janssen for developing scripts to audit the Fossil content against
historical Tcl/Tk distributions, and to the many Tcl/Tk developers who tested
and debugged the conversion process.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|




|








|


|








|

|


|


|



|

|





|




|
|

|


|



|



|

|
|

|


|







|









|









|

|
|
|




|


>

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

# TIP 386: Relocation of Tcl/Tk Source Control Repositories

	Author:         Kevin B. Kenny <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        01-Mar-2011
	Post-History:   
	Keywords:       Fossil,DVCS
-----

# Abstract

This TIP describes the changed locations and procedures for source control
for Tcl/Tk.

# Background

Earlier this year, SourceForge's CVS repositories were attacked by parties
unknown, resulting in an outage of several weeks' duration. Although all data
were eventually recovered, the aftermath of the attack and outage was that
SourceForge staff have formally designated CVS hosting to be a legacy product
and offered assistance with migration to Subversion.

Since for some time the Tcl/Tk maintainers have wanted to transfer the version
control repository to a distributed version control system \(DVCS\), the
decision has been made to abandon SourceForge and adopt a Fossil repository. A
donor who wishes to remain anonymous has given a reasonably powerful machine,
**core.tcl.tk** to the Tcl Community Association and is providing rack space
and bandwidth. The donor has also generously offered to make free shell
accounts to qualified Tcl/Tk developers for CPU- and bandwidth-intensive tasks
such as performance analysis and memory management audits. Interested
developers should contact one of the TCT members listed at the end of this
document.

Needless to say, given the distributed nature of Fossil, we expect several
mirrors to emerge; Richard Hipp of SQLite.org has provided the first one,
appropriately named **mirror1.tcl.tk**.

# Repository Locations

The code base for Tcl itself now resides in a Fossil repository at
<http://core.tcl.tk/tcl/> .  The Fossil repository is available for anonymous
cloning and for examination of version control history.  At present, the bug
tracker is disabled.  Similarly, the code base for Tk resides at
<http://core.tcl.tk/tk> .  Tcl and Tk developers shall be granted 'push' rights
to the respective repositories.

Developers who are unfamiliar with Fossil are strongly encouraged to consult
the documentation at <http://fossil-scm.org/> , in particular, the 'Fossil
Concepts' paper at
<http://fossil-scm.org/index.html/doc/trunk/www/concepts.wiki> .  Novices to
Fossil may want to work at least temporarily in 'autosync mode', which allows
a CVS-like workflow.

At present, the bug, feature request and patch trackers will remain on
SourceForge. Any developer hosting a mirror is expected to disable the bug
tracker \(it suffices to remove 't' permission from the 'anonymous' user\). At
some point we may use a SourceForge-to-Fossil converter for the existing
trackers, and we do not wish to worry about trying to keep SourceForge and
Fossil in sync.

**mirror1.tcl.tk** shall be kept up to date by a periodic automatic
synchronization with **core.tcl.tk**.  In order to avoid inadvertent
forking, developers are requested not to push to mirrors unless
**core.tcl.tk** suffers an extended outage.

Before using a clone from a mirror, developers should verify that it copies
the correct version of the repository at **core.tcl.tk**.  This can be
determined by examining the 'project ID', reported by the 'clone'
operation. For Tcl, the ID should be

	    1ec9da4c469c29f4717e2a967fe6b916d9c8c06e

and for Tk, it should be

	    b5a34cc57b6712927bc5fd34ae98433a14c9fdea 

**UPDATE, June 2013** The ticket trackers have now also been migrated
from SourceForge to **core.tcl.tk**.

# Workflow

Generally speaking, workflow will follow the description in 
<http://fossil-scm.org/index.html/doc/trunk/www/concepts.wiki#workflow> . 

It is expected that large projects will be conducted on named branches in the
Fossil repository; in fact, such a project should most likely be commenced by
committing to a branch in your local clone. If you do not wish to share your
work with others, you may use a private branch, and Fossil will refrain from
synchronizing it when you synchronize your clone.

Simple bug fixes should be developed on the branch of the _earliest_ stable
release that you intend to fix, and then merged forward onto the later
releases' branches. It is expected that such "dovetail merges" will be
frequent, so as to control the number of nuisance conflicts that will have to
be resolved when merging.

Questions about Fossil on the Tcl'ers Chat or in comp.lang.tcl are encouraged;
it's essential that all Tcl/Tk developers develop at least some familiarity
with the technology, and it's somewhat new to all of us!

# Requesting access

Tcl and Tk maintainers may request repository access by emailing one of the
Tcl Core Team members on the following list:

   Joe English, Donal Fellows, Jeff Hobbs, Kevin Kenny, Andreas Kupries, Don
   Porter

all of whom have the required access to add new users to core.tcl.tk.

# Acknowledgments

Major thanks are due to Roy Keene, for leading the migration effort, to Jörg
Sonnenberger \(author of cvs2fossil\) and D. Richard Hipp \(author of fossil
itself\) for many hours of unpaid support in getting the conversion to go, to
Mark Janssen for developing scripts to audit the Fossil content against
historical Tcl/Tk distributions, and to the many Tcl/Tk developers who tested
and debugged the conversion process.

# Copyright

This document has been placed in the public domain.

Name change from tip/387.tip to tip/387.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
136
137
138
139
140
141
142

143
144
145

146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275

TIP:		387
Title:		Unified Yield Command Syntax
Author:		Lars Hellstr�m <[email protected]>
State:		Withdrawn
Type:		Project
Vote:		Pending
Created:	30-May-2011
Tcl-Version:	8.6
Keywords:	Tcl, coroutine
Obsoleted-By:	396
Version:	$Revision: 1.7 $
Post-History:	


~ Abstract

This document describes the ''syntax'' of a unified '''yield''' command, 
which is designed so that it can combine all features of the various 
yield-related commands proposed during 2010.

~~ Note

This should not be taken as a proposal to necessarily provide all the
mentioned features right now, but rather as a roadmap to make a command into
which they ''could'' all be fitted. The purpose is to avoid choosing a
direction that would get really awkward in the future.

~ General Considerations

It is accepted as given that the present syntax of the '''yield''' command,
namely

 > '''yield''' ?''value''?
 
should continue to be valid. It is also desirable to control all additional
features through options placed before the ''value'', since that makes it
possible to let an '''interp alias''' supply them.

What is important given those constraints is that one must be able to
determine whether the final argument is a ''value'' or not solely from looking
at the previous arguments, since any option name is also a perfectly valid
''value'' for '''yield''' to return to the coroutine-caller. This can be
accomplished through the rule that every option must consist of at least two
words (typically -name and value); a word after an option is then known to be
the ''value'' if it is the very last word of the command, and known to be the
first word of another option if it not the very last word of the command. (By
contrast, an attempt to get by with a '''--''' end-of-options option would
become very complicated and error-prone.)

The overall command syntax would thus be similar to that of '''return'''
(options before an optional value), although there is no need to reproduce any
of return's options in '''yield''', as all such functionality can be attained
by yielding to '''return'''.

~ Possible Options

We identify the following options: '''-arguments''', '''-delivery''' and
'''-to'''. These are described below:

~~ Argument Specifiers

The option

 > '''-arguments''' ''argspec''

would be used to specify a '''proc'''-style list of arguments for the
coroutine-command. As mentioned in [372], '''yieldm''' can then be defined as:

|   interp alias {} yieldm {} yield -arguments args

whereas the default for '''-arguments''' is '''{arg ""}''', as:

|   yield -arguments {{arg ""}}

explicitly says the coroutine-command should have one optional argument
''arg'' with default value the empty string.

The idea is that if the arguments supplied to the coroutine-command do not
match the ''argspec'', then the coroutine-command should throw an appropriate
error rather than resuming the coroutine. In that case, the coroutine state
does not change, and in particular the coroutine-command continues to use the
same ''argspec''.

For the purpose of further discussion below, the elements in the ''argspec''
list will be called '''formal parameters''' of the coroutine-command.

~~ Yielding To

The '''-to''' option provides the functionality of the '''yieldto''' command,
and has the syntax:

 > '''-to''' ''cmdname'' ?''arg ...''?

always absorbing all remaining arguments of the '''yield''' command; a
precedent for this may be found in for example the '''-join''' option of the
'''glob''' command. In order to meet the "at least two words" requirement for
'''yield''' options, the ''cmdname'' argument is mandatory, but this is quite
natural since it is anyway to be resolved already by '''yield'''.

Note that behavior like yielding and throwing an error can be performed by
yielding to '''return''':

|   yield -to return -code error -errorcode DEMO "Just an example"

'''-code''' and '''-errorcode''' here are not options of '''yield''', but of
'''return''', although the impression is probably close to that of having them
options of '''yield''' directly.

~~ Argument Delivery

An issue where no obvious solution presented itself was that of how arguments
supplied to the coroutine-command should be made available in the coroutine.
This proposal suggest that a '''-delivery''' option could be used to control
this, and that the word after '''-delivery''' is a ''mode'' keyword which
selects whether the arguments should be provided as a list, a dictionary, in
variables, or whatever. The following is a list of possible forms of this
option.

The supported modes will be one of: '''dict''', '''first''', '''flat''',
'''same''' and '''vars'''. These are described below. (Note that different
modes need not have the same number of argument words.)

~~~ Dictionary Delivery

 > '''-delivery dict'''

The return value of '''yield''' is a dictionary, with one entry for each
formal parameter, the entries appearing in the same order as in the
'''-arguments''' ''argspec'', and the values filled in as they would be for a
'''proc''' call. The latter implies that ''default values are filled in for
missing optional arguments''; this preserves the invariant for the caller that
specifying the default value for an optional argument is the same as omitting
that argument.

Thus, for the demonstration code:

| proc demo {delivery} {
|    set last ""
|    foreach argspec {
|       foo {{arg ""}} {{arg ""}} args {foo args}
|    } {
|       set last [yield -arguments $argspec -delivery $delivery $last]
|    }

|    return $last
| }


one can get this interactive session:

| % coroutine C demo dict
| % C "a b"
| foo {a b}
| % C "a b"
| arg {a b}
| % C
| arg {}
| % C "a b"
| args {{a b}}
| % C "a b"
| foo {a b} args {}

~~~ Flat Delivery

It is not unreasonable to also expect a mode that delivers just the list of
formal parameter values, e.g.

 > '''-delivery list'''

but this can be obtained from

|   dict values [yield -delivery dict ...]

since the '''dict''' mode is specified as putting the entries in the right
order.

Instead there is another take on returning a list of arguments that 
provides extra functionality:

 > '''-delivery flat'''

The return value of '''yield''' is the list of arguments of the
coroutine-command, regardless of '''-arguments''' ''argspec''. This is the
'''yield''' counterpart of '''info level 0''', providing full introspection
into the arguments, but also leaving parsing entirely up to the programmer.

With the same sequence of calls as above, one gets

| % coroutine C demo flat
| % C "a b"
| {a b}
| % C "a b"
| {a b}
| % C
| % C "a b"
| {a b}
| % C "a b"
| {a b}

~~~ Delivery to Local Variables

 > '''-delivery vars''' ''varlist''

The ''varlist'' must be a list with one element for each formal parameter. The
values of the formal parameters are assigned, in sequence, to the variables
named in the ''varlist''. The return value is an empty string.

Of course, most of the time one would use the same names as in the
''argspec'', so it is reasonable to have a shorthand for this:

 > '''-delivery same'''

The main reason to do otherwise is if both the procedure '''yield'''ing and
the coroutine-command has an '''args''' argument, since that is a magical
name. Hiding implementation details from users can also be a reason to specify
a different ''varlist''.

A further possibility that has been suggested would be:

 > '''-delivery array''' ''arrname''

for dumping the arguments as entries in an array. This can however be
accomplished through

| array set $arrname [yield -delivery dict ...]

which is probably easy enough.

~~~ Simple Delivery

Finally, there is:

 > '''-delivery first'''

The return value is the value of the first formal parameter, or an empty
string if there are no formal parameters; values of additional formal
parameters are discarded. ''This is the default.''

This may seem a strange mode of delivery, and an even stranger thing to have
as default, but it is what one must have if the [372] examples of varying the
''argspec'' should work as claimed there. With the same demo as before, one
gets:

| % coroutine C demo first
| % C "a b" ; # -arguments foo
| a b
| % C "a b" ; # -arguments {{arg ""}}
| a b
| % C       ; # -arguments {{arg ""}}
| % C "a b" ; # -arguments args
| {a b}
| % C "a b" ; # -arguments {foo args}
| a b

An alternative which is perhaps more convenient, but also more complicated, is
to have the default '''-delivery''' depend on the number of formal parameters.
It is then likely that one for the case of more than one formal parameter
would want Yet Another delivery mode...

~ Reference Implementation

None yet.

~ Other Commands

If coroutines are going to have '''proc'''-style argspecs, then it will
probably make sense for '''info args''' and '''info default''' to operate on
coroutine-commands as well as procedures.

~ Acknowledgements

This TIP is dedicated to Alexandre Ferrieux, who's known to have written that
I should prioritize TIPping things over participating in tcl-core
discussions. ;-)

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
|
|
|
<
|
>

|

|



|



|


|

|


|


|
|


|

|

|
|
|
|
|

|
|
|
|

|

|
|

|



|

|
|

|

|

|


|


|


|

|
|

|

|


|

|
|
|
|
|


|

|

|
|
|

|



|
|




|
|
|

|

|

|

|
|
|





|
|
|
|
|
|
<
>
|
<
|
>


|
|
|
|
|
|
|
|
|
|
|

|




|



|

|





|

|
|
|




|
|
|
|
|
|
|
|
|
|

|

|

|

|


|

|

|
|

|



|




|



|



|



|


|
|


|
|
|
|
|
|
|
|
|
|


|



|



|

|
|


|



|

|


>

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
136
137
138
139
140

141
142

143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275

# TIP 387: Unified Yield Command Syntax
	Author:		Lars Hellström <[email protected]>
	State:		Withdrawn
	Type:		Project
	Vote:		Pending
	Created:	30-May-2011
	Tcl-Version:	8.6
	Keywords:	Tcl, coroutine
	Obsoleted-By:	396

	Post-History:	
-----

# Abstract

This document describes the _syntax_ of a unified **yield** command, 
which is designed so that it can combine all features of the various 
yield-related commands proposed during 2010.

## Note

This should not be taken as a proposal to necessarily provide all the
mentioned features right now, but rather as a roadmap to make a command into
which they _could_ all be fitted. The purpose is to avoid choosing a
direction that would get really awkward in the future.

# General Considerations

It is accepted as given that the present syntax of the **yield** command,
namely

 > **yield** ?_value_?
 
should continue to be valid. It is also desirable to control all additional
features through options placed before the _value_, since that makes it
possible to let an **interp alias** supply them.

What is important given those constraints is that one must be able to
determine whether the final argument is a _value_ or not solely from looking
at the previous arguments, since any option name is also a perfectly valid
_value_ for **yield** to return to the coroutine-caller. This can be
accomplished through the rule that every option must consist of at least two
words \(typically -name and value\); a word after an option is then known to be
the _value_ if it is the very last word of the command, and known to be the
first word of another option if it not the very last word of the command. \(By
contrast, an attempt to get by with a **--** end-of-options option would
become very complicated and error-prone.\)

The overall command syntax would thus be similar to that of **return**
\(options before an optional value\), although there is no need to reproduce any
of return's options in **yield**, as all such functionality can be attained
by yielding to **return**.

# Possible Options

We identify the following options: **-arguments**, **-delivery** and
**-to**. These are described below:

## Argument Specifiers

The option

 > **-arguments** _argspec_

would be used to specify a **proc**-style list of arguments for the
coroutine-command. As mentioned in [[372]](372.md), **yieldm** can then be defined as:

	   interp alias {} yieldm {} yield -arguments args

whereas the default for **-arguments** is **\{arg ""\}**, as:

	   yield -arguments {{arg ""}}

explicitly says the coroutine-command should have one optional argument
_arg_ with default value the empty string.

The idea is that if the arguments supplied to the coroutine-command do not
match the _argspec_, then the coroutine-command should throw an appropriate
error rather than resuming the coroutine. In that case, the coroutine state
does not change, and in particular the coroutine-command continues to use the
same _argspec_.

For the purpose of further discussion below, the elements in the _argspec_
list will be called **formal parameters** of the coroutine-command.

## Yielding To

The **-to** option provides the functionality of the **yieldto** command,
and has the syntax:

 > **-to** _cmdname_ ?_arg ..._?

always absorbing all remaining arguments of the **yield** command; a
precedent for this may be found in for example the **-join** option of the
**glob** command. In order to meet the "at least two words" requirement for
**yield** options, the _cmdname_ argument is mandatory, but this is quite
natural since it is anyway to be resolved already by **yield**.

Note that behavior like yielding and throwing an error can be performed by
yielding to **return**:

	   yield -to return -code error -errorcode DEMO "Just an example"

**-code** and **-errorcode** here are not options of **yield**, but of
**return**, although the impression is probably close to that of having them
options of **yield** directly.

## Argument Delivery

An issue where no obvious solution presented itself was that of how arguments
supplied to the coroutine-command should be made available in the coroutine.
This proposal suggest that a **-delivery** option could be used to control
this, and that the word after **-delivery** is a _mode_ keyword which
selects whether the arguments should be provided as a list, a dictionary, in
variables, or whatever. The following is a list of possible forms of this
option.

The supported modes will be one of: **dict**, **first**, **flat**,
**same** and **vars**. These are described below. \(Note that different
modes need not have the same number of argument words.\)

### Dictionary Delivery

 > **-delivery dict**

The return value of **yield** is a dictionary, with one entry for each
formal parameter, the entries appearing in the same order as in the
**-arguments** _argspec_, and the values filled in as they would be for a
**proc** call. The latter implies that _default values are filled in for
missing optional arguments_; this preserves the invariant for the caller that
specifying the default value for an optional argument is the same as omitting
that argument.

Thus, for the demonstration code:

	 proc demo {delivery} {
	    set last ""
	    foreach argspec {
	       foo {{arg ""}} {{arg ""}} args {foo args}
	    } {
	       set last [yield -arguments $argspec -delivery $delivery $last]

	    }
	    return $last

	 }

one can get this interactive session:

	 % coroutine C demo dict
	 % C "a b"
	 foo {a b}
	 % C "a b"
	 arg {a b}
	 % C
	 arg {}
	 % C "a b"
	 args {{a b}}
	 % C "a b"
	 foo {a b} args {}

### Flat Delivery

It is not unreasonable to also expect a mode that delivers just the list of
formal parameter values, e.g.

 > **-delivery list**

but this can be obtained from

	   dict values [yield -delivery dict ...]

since the **dict** mode is specified as putting the entries in the right
order.

Instead there is another take on returning a list of arguments that 
provides extra functionality:

 > **-delivery flat**

The return value of **yield** is the list of arguments of the
coroutine-command, regardless of **-arguments** _argspec_. This is the
**yield** counterpart of **info level 0**, providing full introspection
into the arguments, but also leaving parsing entirely up to the programmer.

With the same sequence of calls as above, one gets

	 % coroutine C demo flat
	 % C "a b"
	 {a b}
	 % C "a b"
	 {a b}
	 % C
	 % C "a b"
	 {a b}
	 % C "a b"
	 {a b}

### Delivery to Local Variables

 > **-delivery vars** _varlist_

The _varlist_ must be a list with one element for each formal parameter. The
values of the formal parameters are assigned, in sequence, to the variables
named in the _varlist_. The return value is an empty string.

Of course, most of the time one would use the same names as in the
_argspec_, so it is reasonable to have a shorthand for this:

 > **-delivery same**

The main reason to do otherwise is if both the procedure **yield**ing and
the coroutine-command has an **args** argument, since that is a magical
name. Hiding implementation details from users can also be a reason to specify
a different _varlist_.

A further possibility that has been suggested would be:

 > **-delivery array** _arrname_

for dumping the arguments as entries in an array. This can however be
accomplished through

	 array set $arrname [yield -delivery dict ...]

which is probably easy enough.

### Simple Delivery

Finally, there is:

 > **-delivery first**

The return value is the value of the first formal parameter, or an empty
string if there are no formal parameters; values of additional formal
parameters are discarded. _This is the default._

This may seem a strange mode of delivery, and an even stranger thing to have
as default, but it is what one must have if the [[372]](372.md) examples of varying the
_argspec_ should work as claimed there. With the same demo as before, one
gets:

	 % coroutine C demo first
	 % C "a b" ; # -arguments foo
	 a b
	 % C "a b" ; # -arguments {{arg ""}}
	 a b
	 % C       ; # -arguments {{arg ""}}
	 % C "a b" ; # -arguments args
	 {a b}
	 % C "a b" ; # -arguments {foo args}
	 a b

An alternative which is perhaps more convenient, but also more complicated, is
to have the default **-delivery** depend on the number of formal parameters.
It is then likely that one for the case of more than one formal parameter
would want Yet Another delivery mode...

# Reference Implementation

None yet.

# Other Commands

If coroutines are going to have **proc**-style argspecs, then it will
probably make sense for **info args** and **info default** to operate on
coroutine-commands as well as procedures.

# Acknowledgements

This TIP is dedicated to Alexandre Ferrieux, who's known to have written that
I should prioritize TIPping things over participating in tcl-core
discussions. ;-\)

# Copyright

This document has been placed in the public domain.

Name change from tip/388.tip to tip/388.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

TIP:            388
Title:          Extending Unicode literals past the BMP
Version:        $Revision: 1.7 $
Author:         Jan Nijtmans <[email protected]>
Author:         Jan Nijtmans <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        10-Aug-2011
Post-History:   
Discussions-To: Tcl Core list
Keywords:       Tcl
Tcl-Version:    8.6


~ Abstract

This TIP proposes to extend Tcl's syntax in order to be able to cope with
quoted forms of Unicode characters outside the Basic Multilingual Plane.

~ Summary

Tcl provides backslash substitutions of the form '''\uhhhh''' for unicode
characters, but this form is not sufficient to model unicode literals past the
BMP. The outcome of the discussion on Tcl-Core was to add the form
'''\Uhhhhhhhh''' (one up to 8 hexadecimal digits), but still it is
ambiguous how characters > 0x10ffff are to be handled. This TIP is meant to
sort that out, it is not meant to specify how characters outside the BMP are
handled. The reference implementation just replaces any character in the range
'''\U010000''' - '''\U10ffff''' with '''\ufffd''', but as soon as Tcl has
support for characters outside the BMP this range is reserved for exactly that.

Currently, the form '''\U''' is parsed by Tcl as a literal '''U''', so -
however small - this change results in a non-trivial potential incompatibility
which therefore requires a TIP.

Considering backslash sequences, there are two other forms which are currently
not consistent: '''\xhh''' accepts an unlimited number of hex digits, unlike
other modern languages, and the form '''\ooo''', where the first octal digit
is in the range 4..7 is currently not handled consistently in Tcl. Now is an
opportunity to reconsider this.

In tcl.h there is a remark regarding the possible values of TCL_UTF_MAX:

 * 3 Currently the only supported value, defining Tcl_UniChar as unsigned
   short

 * 6 Not supported, but reserved for a hypothetical 32-bit Unicode

 * 1 Not supported, possibly for a ASCII-only variant of Tcl.

This document proposes to add another value:

 * 4 Not supported. The same as 3, but allowing the use of Unicode surrogate
   pairs to represent the range '''\U010000''' - '''\U10ffff'''

~ Rationale

Consider the string '''\701''', how is that supposed to be interpreted?  Tcl
specifies octal sequences as 8 bits, and silently strips the 9th bit, the same
as gcc does. In Tcl's regular expression engine, the 9th bit is not stripped,
there it is equivalent to '''\u01c1'''.  Java - for example - parses it as
'''\70''' - a valid 8-bit octal value - followed by '''1''', so it's a string
of length 2.

Then the string '''\x1234'''. Tcl specifies this as 8 bits as well, and
silently strips all higher bits, so it is equivalent to '''\u0034'''.  This is
the same as gcc does, but Java  - for example - considers it as '''\x12'''
followed by '''34''', so it's a string of lenght 3.

Consider the string '''\U00123456''', which would result in an invalid Unicode
character. In the Tcl parser we don't have the possibility to flag invalid
backslash sequences, in Tcl's regexp engine we have.  Unicode characters
higher than '''\U0010ffff''' cannot appear in an UTF-8 stream.

In tcl.h, we find Tcl_UniChar to be defined as unsigned int when TCL_UTF_MAX >
3 and as unsigned short otherwise. It would be useful to reserve the value 4
and still define Tcl_UniChar as unsigned short. That would allow the path to
a full support for out-of BMP Unicode characters shorter, because Unicode
Surrogate pairs can be used for that.

~ Specification

This document proposes:

 * Change the parsers in Tcl to handle octal sequences higher than '''\377'''
   differently, splitting it in a two-digit valid octal secuence and handling
   the additional character separately. So '''\701''' is handled as the valid
   sequence '''\70''' followed by '''1'''.
   This is a '''potential incompatibility'''.

 * Change the parsers in Tcl to handle the '''\xhh''' sequence to parse just 2
   digits, and not silently strip all higher hex digits any more.  This is a
   '''potential incompatibility'''.

 * Add the '''\Uhhhhhhhh''' handling, similar to the '''\uhhhh''' handling,
   only accepting up to 8 characters. The parser will stop parsing earlier
   when a code point '''\U00011000''' or higher is reached, as shifting it 4
   bits more will lead to a code point outside the Unicode range.  The regexp
   engine already handles '''\Uhhhhhhhh''', but currently it always generates
   a character in the BMP and strips all higher bits.  This is a '''potential
   incompatibility'''.

~ Compatibility

Tcl scripts using the form '''\ooo''' where the first digit is in the range
4-7, will now interpred the string as '''\oo''' followed by '''o'''. There is
currently no test case in the Tcl test suite affected by that.

Tcl scripts using the form '''\xhhh''', which used to strip off the higher
digits, will now end the sequence when two digits are handled.

Tcl scripts using '''\U''' as a literal '''U''' will no longer work when it is
followed with at least one hexadecimal digit.  There is currently no test case
in the Tcl test suite affected by that.

~ Alternatives

Unicode Noncharacters or Surrogages are not supposed to be in an UTF-8
stream, the Unicode standard recommends to replace those with '''\ufffd'''.
This TIP does not propose that, because they may be used internally e.g. as
part of a character range in a regular expression. A better place to do
that is in the Utf8-To-Utf8 conversion, but that's outside the scope of
this TIP.

~ Reference Implementation

A reference implementation is available at http://core.tcl.tk/tcl in branch
tip-388-impl

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|




|

|


|



|


|




|
|



|

|









|

|

|


|
|


|
|
|
|

|


|

|

|



|



|

|
|
|

|

|

|

|

|
|
|

|

|
|


|


|



|


|





|

|


|


>

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

# TIP 388: Extending Unicode literals past the BMP

	Author:         Jan Nijtmans <[email protected]>
	Author:         Jan Nijtmans <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        10-Aug-2011
	Post-History:   
	Discussions-To: Tcl Core list
	Keywords:       Tcl
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes to extend Tcl's syntax in order to be able to cope with
quoted forms of Unicode characters outside the Basic Multilingual Plane.

# Summary

Tcl provides backslash substitutions of the form **\\uhhhh** for unicode
characters, but this form is not sufficient to model unicode literals past the
BMP. The outcome of the discussion on Tcl-Core was to add the form
**\\Uhhhhhhhh** \(one up to 8 hexadecimal digits\), but still it is
ambiguous how characters > 0x10ffff are to be handled. This TIP is meant to
sort that out, it is not meant to specify how characters outside the BMP are
handled. The reference implementation just replaces any character in the range
**\\U010000** - **\\U10ffff** with **\\ufffd**, but as soon as Tcl has
support for characters outside the BMP this range is reserved for exactly that.

Currently, the form **\\U** is parsed by Tcl as a literal **U**, so -
however small - this change results in a non-trivial potential incompatibility
which therefore requires a TIP.

Considering backslash sequences, there are two other forms which are currently
not consistent: **\\xhh** accepts an unlimited number of hex digits, unlike
other modern languages, and the form **\\ooo**, where the first octal digit
is in the range 4..7 is currently not handled consistently in Tcl. Now is an
opportunity to reconsider this.

In tcl.h there is a remark regarding the possible values of TCL\_UTF\_MAX:

 * 3 Currently the only supported value, defining Tcl\_UniChar as unsigned
   short

 * 6 Not supported, but reserved for a hypothetical 32-bit Unicode

 * 1 Not supported, possibly for a ASCII-only variant of Tcl.

This document proposes to add another value:

 * 4 Not supported. The same as 3, but allowing the use of Unicode surrogate
   pairs to represent the range **\\U010000** - **\\U10ffff**

# Rationale

Consider the string **\\701**, how is that supposed to be interpreted?  Tcl
specifies octal sequences as 8 bits, and silently strips the 9th bit, the same
as gcc does. In Tcl's regular expression engine, the 9th bit is not stripped,
there it is equivalent to **\\u01c1**.  Java - for example - parses it as
**\\70** - a valid 8-bit octal value - followed by **1**, so it's a string
of length 2.

Then the string **\\x1234**. Tcl specifies this as 8 bits as well, and
silently strips all higher bits, so it is equivalent to **\\u0034**.  This is
the same as gcc does, but Java  - for example - considers it as **\\x12**
followed by **34**, so it's a string of lenght 3.

Consider the string **\\U00123456**, which would result in an invalid Unicode
character. In the Tcl parser we don't have the possibility to flag invalid
backslash sequences, in Tcl's regexp engine we have.  Unicode characters
higher than **\\U0010ffff** cannot appear in an UTF-8 stream.

In tcl.h, we find Tcl\_UniChar to be defined as unsigned int when TCL\_UTF\_MAX >
3 and as unsigned short otherwise. It would be useful to reserve the value 4
and still define Tcl\_UniChar as unsigned short. That would allow the path to
a full support for out-of BMP Unicode characters shorter, because Unicode
Surrogate pairs can be used for that.

# Specification

This document proposes:

 * Change the parsers in Tcl to handle octal sequences higher than **\\377**
   differently, splitting it in a two-digit valid octal secuence and handling
   the additional character separately. So **\\701** is handled as the valid
   sequence **\\70** followed by **1**.
   This is a **potential incompatibility**.

 * Change the parsers in Tcl to handle the **\\xhh** sequence to parse just 2
   digits, and not silently strip all higher hex digits any more.  This is a
   **potential incompatibility**.

 * Add the **\\Uhhhhhhhh** handling, similar to the **\\uhhhh** handling,
   only accepting up to 8 characters. The parser will stop parsing earlier
   when a code point **\\U00011000** or higher is reached, as shifting it 4
   bits more will lead to a code point outside the Unicode range.  The regexp
   engine already handles **\\Uhhhhhhhh**, but currently it always generates
   a character in the BMP and strips all higher bits.  This is a **potential
   incompatibility**.

# Compatibility

Tcl scripts using the form **\\ooo** where the first digit is in the range
4-7, will now interpred the string as **\\oo** followed by **o**. There is
currently no test case in the Tcl test suite affected by that.

Tcl scripts using the form **\\xhhh**, which used to strip off the higher
digits, will now end the sequence when two digits are handled.

Tcl scripts using **\\U** as a literal **U** will no longer work when it is
followed with at least one hexadecimal digit.  There is currently no test case
in the Tcl test suite affected by that.

# Alternatives

Unicode Noncharacters or Surrogages are not supposed to be in an UTF-8
stream, the Unicode standard recommends to replace those with **\\ufffd**.
This TIP does not propose that, because they may be used internally e.g. as
part of a character range in a regular expression. A better place to do
that is in the Utf8-To-Utf8 conversion, but that's outside the scope of
this TIP.

# Reference Implementation

A reference implementation is available at <http://core.tcl.tk/tcl> in branch
tip-388-impl

# Copyright

This document has been placed in the public domain.

Name change from tip/389.tip to tip/389.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

TIP:            389
Title:          Full support for Unicode 8.0 and later
Version:        $Revision: 1.4 $
Author:         Jan Nijtmans <[email protected]>
Author:         Jan Nijtmans <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        23-Aug-2011
Post-History:   
Discussions-To: Tcl Core list
Keywords:       Tcl
Tcl-Version:    8.7


~ Abstract

This TIP proposes to add full support for all characters in Unicode 8.0+,
inclusive the characters >= '''U+010000'''.

~ Summary

In order to extend the range of the characters to more than 16 bits, the type
''Tcl_UniChar'' is not big enough any more to hold all possible characters.
Changing the type of ''Tcl_UniChar'' to a 32-bit quantity is not an option, as
it will result in a binary API incompatibility.

The solution proposed in this TIP is to keep ''Tcl_UniChar'' a 16-bit
quantity, but to increase the value of TCL_UTF_MAX to 4 (from 3). Any
conversions from UTF-8 to ''Tcl_UniChar'' will convert any valid 4-byte UTF-8
sequence to a sequence of two Surrogate characters. All conversions from
UTF-16 to UTF-8 will make sure that any High Surrogate immediately followed by
a Low Surrogate will result in a single 4-byte UTF-8 character.

This can be done in a binary compatible way: No source code of existing
extensions need to be modified. As long as no characters >= '''U+010000''' or
Surrogates are used, all functions provided by the Tcl library will function
as before. There are few functions which currently return a value of type
''Tcl_UniChar'', those will be modified to return an int in stead.

~ Rationale

As Unicode 8.0, and future Unicode versions, will supply more and more
characters outside the 16-bit range, it would be useful if Tcl supports
that as well.

~ Specification

This document proposes:

 * Change the functions ''Tcl_UniCharToUtf'' and ''UnicodeToUtfProc'' such
   that when they are fed with a valid High Surrogate followed by a Low
   Surrogate, the result will be a single 4-byte UTF-8 character.

 * Change the functions ''Tcl_UtfToUniChar'' and ''UtfToUnicodeProc'' such
   that when they are fed with a valid 4-byte UTF-8 character, the first call
   will return a High Surrogate character, and the next call will return a Low
   Surrogate character.

 * The following functions, which currently return a Tcl_UniChar, will be
   changed to return an int instead:

 > * ''Tcl_UniCharAtIndex''

 > * ''Tcl_UniCharToLower''

 > * ''Tcl_UniCharToTitle''

 > * ''Tcl_UniCharToUpper''

 > * ''Tcl_GetUniChar''

 * Extend tclUniData.c to include all Unicode 8.0 characters up to
   '''U+02FA20'''.  A special case will be made for the functions
   ''Tcl_UniCharIsGraph'' and ''Tcl_UniCharIsPrint'' for the characters in the
   range '''U+0E0100''' - '''U+0E01EF''', otherwise it would almost double the
   Unicode table size.

~ Compatibility

As long as no Surrogates or characters >= '''U+010000''' are used, all
functions behave exactly the same as before. The only way that
''Tcl_UniCharToUtf'' can produce a 4-byte output is when Surrogates or
characters >= '''U+010000''' are used.

Extension that want to be compatible with any Tcl version, can include tcl.h
as follows:

|#define TCL_UTF_MAX 4
|#include <tcl.h>

or they can call the C compiler with the additional argument -DTCL_UTF_MAX=4,
in order to be sure that UTF-8 representations of length 4 can be
handled. This way, the extension can be used with any Tcl version, whether it
supports Surrogates or not.

Apart from this, it is advisable to initialize the variable where the chPtr
argument from ''Tcl_UtfToUniChar'' points to, as this location is used to
remember whether the High Surrogate is already produced or not. Not doing so
when the first character of a string is a character > '''U+010000''' might
result in a Low Surrogate character only. This danger, however unlikely, only
exists for the first character in a string, and it only occurs when the
(random) value is exactly equal to the expected High Surrogate.

~ Reference Implementation

A reference implementation is available at http://core.tcl.tk/tcl in branch
tip-389-impl

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|
|

|


|
|


|
|
|





|


|

|





|



|



|




|


|

|

|

|

|


|
|
|


|

|

|
|




|
|

|





|

|


|

|

|


|


>

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

# TIP 389: Full support for Unicode 8.0 and later

	Author:         Jan Nijtmans <[email protected]>
	Author:         Jan Nijtmans <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        23-Aug-2011
	Post-History:   
	Discussions-To: Tcl Core list
	Keywords:       Tcl
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to add full support for all characters in Unicode 8.0\+,
inclusive the characters >= **U\+010000**.

# Summary

In order to extend the range of the characters to more than 16 bits, the type
_Tcl\_UniChar_ is not big enough any more to hold all possible characters.
Changing the type of _Tcl\_UniChar_ to a 32-bit quantity is not an option, as
it will result in a binary API incompatibility.

The solution proposed in this TIP is to keep _Tcl\_UniChar_ a 16-bit
quantity, but to increase the value of TCL\_UTF\_MAX to 4 \(from 3\). Any
conversions from UTF-8 to _Tcl\_UniChar_ will convert any valid 4-byte UTF-8
sequence to a sequence of two Surrogate characters. All conversions from
UTF-16 to UTF-8 will make sure that any High Surrogate immediately followed by
a Low Surrogate will result in a single 4-byte UTF-8 character.

This can be done in a binary compatible way: No source code of existing
extensions need to be modified. As long as no characters >= **U\+010000** or
Surrogates are used, all functions provided by the Tcl library will function
as before. There are few functions which currently return a value of type
_Tcl\_UniChar_, those will be modified to return an int in stead.

# Rationale

As Unicode 8.0, and future Unicode versions, will supply more and more
characters outside the 16-bit range, it would be useful if Tcl supports
that as well.

# Specification

This document proposes:

 * Change the functions _Tcl\_UniCharToUtf_ and _UnicodeToUtfProc_ such
   that when they are fed with a valid High Surrogate followed by a Low
   Surrogate, the result will be a single 4-byte UTF-8 character.

 * Change the functions _Tcl\_UtfToUniChar_ and _UtfToUnicodeProc_ such
   that when they are fed with a valid 4-byte UTF-8 character, the first call
   will return a High Surrogate character, and the next call will return a Low
   Surrogate character.

 * The following functions, which currently return a Tcl\_UniChar, will be
   changed to return an int instead:

	 > \* _Tcl\_UniCharAtIndex_

	 > \* _Tcl\_UniCharToLower_

	 > \* _Tcl\_UniCharToTitle_

	 > \* _Tcl\_UniCharToUpper_

	 > \* _Tcl\_GetUniChar_

 * Extend tclUniData.c to include all Unicode 8.0 characters up to
   **U\+02FA20**.  A special case will be made for the functions
   _Tcl\_UniCharIsGraph_ and _Tcl\_UniCharIsPrint_ for the characters in the
   range **U\+0E0100** - **U\+0E01EF**, otherwise it would almost double the
   Unicode table size.

# Compatibility

As long as no Surrogates or characters >= **U\+010000** are used, all
functions behave exactly the same as before. The only way that
_Tcl\_UniCharToUtf_ can produce a 4-byte output is when Surrogates or
characters >= **U\+010000** are used.

Extension that want to be compatible with any Tcl version, can include tcl.h
as follows:

	#define TCL_UTF_MAX 4
	#include <tcl.h>

or they can call the C compiler with the additional argument -DTCL\_UTF\_MAX=4,
in order to be sure that UTF-8 representations of length 4 can be
handled. This way, the extension can be used with any Tcl version, whether it
supports Surrogates or not.

Apart from this, it is advisable to initialize the variable where the chPtr
argument from _Tcl\_UtfToUniChar_ points to, as this location is used to
remember whether the High Surrogate is already produced or not. Not doing so
when the first character of a string is a character > **U\+010000** might
result in a Low Surrogate character only. This danger, however unlikely, only
exists for the first character in a string, and it only occurs when the
\(random\) value is exactly equal to the expected High Surrogate.

# Reference Implementation

A reference implementation is available at <http://core.tcl.tk/tcl> in branch
tip-389-impl

# Copyright

This document has been placed in the public domain.

Name change from tip/39.tip to tip/39.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

TIP:            39
Title:          Add New Standard Tk Option: -component
Version:        $Revision: 1.5 $
Author:         Bryan Oakley <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        04-Jul-2001
Post-History:   
Keywords:       compound,megawidget
Tcl-Version:    8.5


~ Abstract

This TIP proposes to add a new standard option, ''-component'', for
all Tk widgets.

~ Introduction

One of the problems with creating compound widgets (or "megawidgets")
in Tk is library code that doesn't know whether a widget is a widget
or whether it is merely a component of a larger compound widget.

This TIP suggests a new common option for all widgets that defines
whether a widget is merely a component of a larger compound object.
The value of this option would normally be the empty string, but could
be set to the name of a widget that is the "root" of a compound widget
(typically a component window's parent).

For example, consider a prototypical labelled entry widget that is
made up of a frame (.f), and entry widget (.f.e) and a label (.f.l).
These might be defined as follows:

| frame .f -class LabelledEntry 
| entry .f.e -component .f
| label .f.l -component .f

Internal commands that act upon widgets could use this information to
alter their behavior for component widgets.  For example,
''tk_focusNext'' and ''tk_focusPrev'' could ignore components when
figuring out where to send focus, typically as a result of the user
pressing <Tab> or <Shift-Tab>.  This would help sole a nagging problem
with many compound widgets.

We might want to modify [[winfo children]] to ignore component windows
as well (unless, for example, ''-showcomponents'' is set to true),
only reporting those children added by external entities.  For
example, consider a compound widget that implements a scrollable
container.  This widget might be built with a frame (.f), a vertical
scrollbar (.f.v) and a horizontal scrollbar (.f.h).  After a user adds
their own widgets to this window they would expect [[winfo children
.f]] to return only the windows they created, and might be confused
(or at least annoyed) by the presence of these internal windows.

~ Specification

Suggested wording for the ''options'' man page:

| Command-Line Name: -component
| Database Name: component
| Database Class: Component

 > ''Designates that this widget is a component of a larger widget.
   This option is normally the empty string.  If it is not the empty
   string, it should be set to the "root" of the compound widget.  For
   example, if a compound widget is made up of frame ".f" and an entry
   widget ".f.e", the latter will have as it's component value ".f"
   designating that it is a component of the compound widget rooted at
   ".f"''

In addition, ''tk_focusPrev'' and ''tk_focusNext'' should take the
value of this flag into consideration when determining where focus
should next be given (i.e. it should not give focus to components;
focus should be given to root widgets, which shall be responsible for
redirecting focus as required).

Once this TIP gets implemented, subsequent TIPs can be produced to
define how additional Tk library functions and commands can be
modified to take advantage of this new information.

~ Rationale

We need a standardized way of determining whether a widget is an
atomic object or part of a larger compound object.  This has several
uses, the most obvious (to me, anyway) being focus management.

~ Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > Perhaps some of the ideas behind these TIPs should be incorporated
   into some new TIP on making megawidget support better, but none of
   these TIPs really stand on their own.  (38 isn't a good idea, since
   alteration of the bindtags for all widgets of a class at once is a
   bad idea, and it is better when rolling your own megawidget classes
   to put the setting up of the bindtags in there.  39 and 42 just
   clash with each other as soon as you have two different codebases
   trying to use a single widget.)

~ Copyright

This document has been placed in the public domain with unabashed hope 
for a brighter future.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|







|


|


|
|
|



|




|
|


|
|
|
|
|

|

|

|
|
|

|





|

|

|

|





|



|

|







|




|

|



>

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

# TIP 39: Add New Standard Tk Option: -component

	Author:         Bryan Oakley <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        04-Jul-2001
	Post-History:   
	Keywords:       compound,megawidget
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to add a new standard option, _-component_, for
all Tk widgets.

# Introduction

One of the problems with creating compound widgets \(or "megawidgets"\)
in Tk is library code that doesn't know whether a widget is a widget
or whether it is merely a component of a larger compound widget.

This TIP suggests a new common option for all widgets that defines
whether a widget is merely a component of a larger compound object.
The value of this option would normally be the empty string, but could
be set to the name of a widget that is the "root" of a compound widget
\(typically a component window's parent\).

For example, consider a prototypical labelled entry widget that is
made up of a frame \(.f\), and entry widget \(.f.e\) and a label \(.f.l\).
These might be defined as follows:

	 frame .f -class LabelledEntry 
	 entry .f.e -component .f
	 label .f.l -component .f

Internal commands that act upon widgets could use this information to
alter their behavior for component widgets.  For example,
_tk\_focusNext_ and _tk\_focusPrev_ could ignore components when
figuring out where to send focus, typically as a result of the user
pressing <Tab> or <Shift-Tab>.  This would help sole a nagging problem
with many compound widgets.

We might want to modify [winfo children] to ignore component windows
as well \(unless, for example, _-showcomponents_ is set to true\),
only reporting those children added by external entities.  For
example, consider a compound widget that implements a scrollable
container.  This widget might be built with a frame \(.f\), a vertical
scrollbar \(.f.v\) and a horizontal scrollbar \(.f.h\).  After a user adds
their own widgets to this window they would expect [winfo children
.f] to return only the windows they created, and might be confused
\(or at least annoyed\) by the presence of these internal windows.

# Specification

Suggested wording for the _options_ man page:

	 Command-Line Name: -component
	 Database Name: component
	 Database Class: Component

 > _Designates that this widget is a component of a larger widget.
   This option is normally the empty string.  If it is not the empty
   string, it should be set to the "root" of the compound widget.  For
   example, if a compound widget is made up of frame ".f" and an entry
   widget ".f.e", the latter will have as it's component value ".f"
   designating that it is a component of the compound widget rooted at
   ".f"_

In addition, _tk\_focusPrev_ and _tk\_focusNext_ should take the
value of this flag into consideration when determining where focus
should next be given \(i.e. it should not give focus to components;
focus should be given to root widgets, which shall be responsible for
redirecting focus as required\).

Once this TIP gets implemented, subsequent TIPs can be produced to
define how additional Tk library functions and commands can be
modified to take advantage of this new information.

# Rationale

We need a standardized way of determining whether a widget is an
atomic object or part of a larger compound object.  This has several
uses, the most obvious \(to me, anyway\) being focus management.

# Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > Perhaps some of the ideas behind these TIPs should be incorporated
   into some new TIP on making megawidget support better, but none of
   these TIPs really stand on their own.  \(38 isn't a good idea, since
   alteration of the bindtags for all widgets of a class at once is a
   bad idea, and it is better when rolling your own megawidget classes
   to put the setting up of the bindtags in there.  39 and 42 just
   clash with each other as soon as you have two different codebases
   trying to use a single widget.\)

# Copyright

This document has been placed in the public domain with unabashed hope 
for a brighter future.

Name change from tip/390.tip to tip/390.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

TIP:		390
Title:		A Logging API for Tcl
Author:		Jeff Rogers <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	8.7
Created:	27-Oct-2011
Version:	$Revision: 1.1 $
Vote:		Pending
Post-History:	


~ Abstract

This TIP proposes a standard API for logging in Tcl applications, both at the
Tcl and C level.

~ Rationale

Logging is needed in most applications.  There is no standard, documented
logging API in Tcl, for either Tcl or C code, leading most people to roll
their own. The TIP proposes a standard Tcl and C API that handles the most
common logging functions.

The default implementation of the logger should just print the message (with
substitutions performed as if with '''format''') to the standard error
channel.

~ Specification

 1. '''Tcl_Log'''(''interp'', ''level'', ''message'', ...)

 > This is the main C api call; it logs the formatted message at the specified
   loglevel. If interp is specified, it operates within the context of that
   interp; if NULL then it logs in a maner not associated with any interp.

 2. '''Tcl_SetLogLevel'''(''interp'', ''level'')

 > Instructs the logging system to set the loglevel to the given value.  Legal
   levels are TCL_LOG_DEV, TCL_LOG_DEBUG, TCL_LOG_INFO, TCL_LOG_NOTICE,
   TCL_LOG_WARNING, TCL_LOG_ERROR, TCL_LOG_FATAL, TCL_LOG_BUG

 3. '''Tcl_SetLogHandler'''(''interp'', ''logHandler'')

|    struct Tcl_LogHandler {
|        Tcl_LogHandlerProc(interp, level, message, ...)
|        Tcl_SetLogLevelProc(interp, level)
|    }


 > Installs a new loghandler for a specified interp or globally.  If no log
   handler is installed, the default action is to print the formatted message
   on standard error if the message level is equal to or greater than the
   loglevel; in the context of an interp the default action is to call the
   configured log handler (which does the same thing by default)

 4. '''interp logger''' ?''loggerCommandFragment''?

 > Gets or sets the log handler for an interp.  The log handler will have
   these arguments appended on invoke: ''level message args''

 5. '''log''' ''level message''

 > Tcl equivalent of '''Tcl_Log'''.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
>

|




|






|
|


|

|

|



|

|
|
|

|

|
|
|
<
|
>
|



|

|

|
|

|

|

|


>

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

# TIP 390: A Logging API for Tcl
	Author:		Jeff Rogers <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Created:	27-Oct-2011

	Vote:		Pending
	Post-History:	
-----

# Abstract

This TIP proposes a standard API for logging in Tcl applications, both at the
Tcl and C level.

# Rationale

Logging is needed in most applications.  There is no standard, documented
logging API in Tcl, for either Tcl or C code, leading most people to roll
their own. The TIP proposes a standard Tcl and C API that handles the most
common logging functions.

The default implementation of the logger should just print the message \(with
substitutions performed as if with **format**\) to the standard error
channel.

# Specification

 1. **Tcl\_Log**\(_interp_, _level_, _message_, ...\)

	 > This is the main C api call; it logs the formatted message at the specified
   loglevel. If interp is specified, it operates within the context of that
   interp; if NULL then it logs in a maner not associated with any interp.

 2. **Tcl\_SetLogLevel**\(_interp_, _level_\)

	 > Instructs the logging system to set the loglevel to the given value.  Legal
   levels are TCL\_LOG\_DEV, TCL\_LOG\_DEBUG, TCL\_LOG\_INFO, TCL\_LOG\_NOTICE,
   TCL\_LOG\_WARNING, TCL\_LOG\_ERROR, TCL\_LOG\_FATAL, TCL\_LOG\_BUG

 3. **Tcl\_SetLogHandler**\(_interp_, _logHandler_\)

		    struct Tcl_LogHandler {
		        Tcl_LogHandlerProc(interp, level, message, ...)
		        Tcl_SetLogLevelProc(interp, level)

		    }

	 > Installs a new loghandler for a specified interp or globally.  If no log
   handler is installed, the default action is to print the formatted message
   on standard error if the message level is equal to or greater than the
   loglevel; in the context of an interp the default action is to call the
   configured log handler \(which does the same thing by default\)

 4. **interp logger** ?_loggerCommandFragment_?

	 > Gets or sets the log handler for an interp.  The log handler will have
   these arguments appended on invoke: _level message args_

 5. **log** _level message_

	 > Tcl equivalent of **Tcl\_Log**.

# Copyright

This document has been placed in the public domain.

Name change from tip/391.tip to tip/391.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

TIP:		391
Title:		Support for UDP Sockets in Tcl
Author:		Jeff Rogers <[email protected]>
State:		Withdrawn
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Created:	26-Oct-2011
Version:	$Revision: 1.3 $
Post-History:
Obsoleted-By:	409


~ Abstract

This proposal is to add UDP socket support to the core in a clean and
unobtrusive way.

~ Rationale

UDP is used for sending datagrams over the internet, which is an integral part
of a number of protocols, notably including direct DNS queries in the majority
of deployment. Thus, it is useful to be able have Tcl able to send and receive
messages via UDP sockets, filling out a signficant missing feature.

UDP sockets have the same basic needs as tcp sockets - creating, reading,
writing.  So it follows that they could be handled by the same basic commands.

~ Specification

The '''socket''' command should have a flag, '''-udp''', added.  This should
work for both client and server sockets.

 > '''socket -udp''' ?'''-myaddr''' ''addr''? ?'''-myport''' ''port''? ''host
   port''

 > '''socket -udp -server''' ''command'' ?'''-myaddr''' ''addr''? ''port''

To complement this, the sockets created by the above commands will have an
additional configuration option, '''-peeraddr'''.  This is a read/write
option.  It is used to set the peer address before a write, and to retrieve
the peer address after a read.  The peer address should persist until it is
changed by a read or fconfigure.

When used on a UDP socket, '''puts''' sends a single message (sendmsg).  If
the data is too large to fit in a single message then an error is raised.

When reading from a udp socket, the data retuend will only ever be the
contents of a single message in a single operation.  Thus, '''read''' will
return one entire message, and '''read''' with a bytecount or '''gets''' will
read a new message into their buffer iff it is completely empty, and will
return the requested data from that buffer.

Readable and writable fileevents should work naturally.  

~ Example Usage

|set udpsock [socket -udp 8.8.8.8 53]
|
|fconfigure $udpsock -peeraddr {8.8.8.8 53}
|puts $udpsock $packet
|
|set packet [read $udpsock]
|set peer [fconfigure $udpsock -peeraddr]

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
|
<
|
|
>

|




|









|

|


|
|

|


|




|



|
|





|

|
|
|
|
|
|
|

|


>

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

# TIP 391: Support for UDP Sockets in Tcl
	Author:		Jeff Rogers <[email protected]>
	State:		Withdrawn
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Created:	26-Oct-2011

	Post-History:
	Obsoleted-By:	409
-----

# Abstract

This proposal is to add UDP socket support to the core in a clean and
unobtrusive way.

# Rationale

UDP is used for sending datagrams over the internet, which is an integral part
of a number of protocols, notably including direct DNS queries in the majority
of deployment. Thus, it is useful to be able have Tcl able to send and receive
messages via UDP sockets, filling out a signficant missing feature.

UDP sockets have the same basic needs as tcp sockets - creating, reading,
writing.  So it follows that they could be handled by the same basic commands.

# Specification

The **socket** command should have a flag, **-udp**, added.  This should
work for both client and server sockets.

 > **socket -udp** ?**-myaddr** _addr_? ?**-myport** _port_? _host
   port_

 > **socket -udp -server** _command_ ?**-myaddr** _addr_? _port_

To complement this, the sockets created by the above commands will have an
additional configuration option, **-peeraddr**.  This is a read/write
option.  It is used to set the peer address before a write, and to retrieve
the peer address after a read.  The peer address should persist until it is
changed by a read or fconfigure.

When used on a UDP socket, **puts** sends a single message \(sendmsg\).  If
the data is too large to fit in a single message then an error is raised.

When reading from a udp socket, the data retuend will only ever be the
contents of a single message in a single operation.  Thus, **read** will
return one entire message, and **read** with a bytecount or **gets** will
read a new message into their buffer iff it is completely empty, and will
return the requested data from that buffer.

Readable and writable fileevents should work naturally.  

# Example Usage

	set udpsock [socket -udp 8.8.8.8 53]
	
	fconfigure $udpsock -peeraddr {8.8.8.8 53}
	puts $udpsock $packet
	
	set packet [read $udpsock]
	set peer [fconfigure $udpsock -peeraddr]

# Copyright

This document has been placed in the public domain.

Name change from tip/392.tip to tip/392.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

TIP:		392
Title:		Allow Bignums to be Disabled at Runtime on a Per-Interp Basis
Version:	$Revision: 1.1 $
Author:		Joe Mistachkin <[email protected]>
State:		Draft
Type:		Project
Vote:		Pending
Created:	30-Oct-2011
Keywords:	bignum,runaway,safe,math,precision,integer,tcl
Tcl-Version:	8.5
Post-History:	


~ Abstract

This TIP proposes the ability to enable or disable all use of bignums at
runtime on a per-interpreter basis.  The mechanism being presented to
accomplish this goal has been designed to be generic enough so that it can be
used for other per-interpreter configuration parameters in the future.

~ Rationale

As of Tcl version 8.5, almost any integer math calculation can result in
bignums being used.  Normally, this does not pose a serious problem; however,
there are circumstances in which this can exhaust key system resources, such
as memory or CPU time.  Unlike other similar resource exhaustion problems,
this one cannot be prevented by use of '''interp create -safe''', '''interp
limit''', '''interp cancel''', or similar mechanisms.  If Tcl is being used in
an embedding scenario, this has the potential to negatively impact the entire
application or system.  If Tcl is being used to evaluate marginally trusted or
untrusted scripts in a safe interpreter, this can result in a
denial-of-service (DoS) attack.

~ Specification

A new '''interp configure''' script command will be added, as follows:

 > '''interp configure''' ''path'' ?''name''? ?''value''?

This command instructs Tcl to modify or query the value of the named
configuration parameter ''name'' in the interpreter identified by ''path''.

~~ Arguments

 > ''path''

This argument is required and specifies the interpreter to be reconfigured. An
empty string may be used to indicate the current interpreter.

 > ''name''

This argument is optional.  If this argument is not supplied, the current list
of configuration parameter names for the interpreter identified by ''path''
will be returned.

 > ''value''

This argument is optional.  If this argument is not supplied, the current
value of the named configuration parameter for the interpreter identified by
''path'' will be returned; otherwise, the current value of the configuration
parameter will be changed to the specified value.

~~ C API

 > Tcl_Obj* '''Tcl_InterpConfigure'''(Tcl_Interp* ''interp'',
   Tcl_Obj* ''nameObjPtr'', Tcl_Obj* ''valueObjPtr'')

The '''Tcl_InterpConfigure''' function gets or sets the named configuration
parameter for the specified interpreter.  The ''nameObjPtr'', if not NULL,
must be a string containing the name of a known configuration parameter;
otherwise, NULL will be returned and the interpreter result will be modified
to contain an appropriate error message.  The ''valueObjPtr'', if not NULL,
must have a value convertible to the type required by the configuration
parameter being set; otherwise, NULL will be returned and the interpreter
result will be modified to contain an appropriate error message.  If
''valueObjPtr'' is NULL, the current value of the named configuration
parameter will be returned instead of being changed.  If ''nameObjPtr'' is
NULL, the complete list of known configuration parameter names will be
returned.  The caller is responsible for managing the reference count of the
returned value.

~ Configuration Parameters

Upon interpreter creation, all configuration parameters start with a default
value.  The default value for a configuration parameter is considered to be
part of the formal interface.

Initially, the only supported configuration parameter will be '''bignums'''.

When setting the '''bignums''' configuration parameter, the value must be
convertible to a boolean.  When the value of this configuration parameter is
false, any math operation that would require using bignums to calculate will
instead be limited to the precision available in the '''Tcl_WideInt''' type.
The default value of this configuration parameter will be true (i.e. use of
bignums will be enabled by default, preserving backward compatibility).

~ Reference Implementation

Not yet complete; however, it will eventually be available on the
'''tip-392''' branch of the Tcl source code repository.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|






|





|
|



|

|

|

|


|

|

|




|


|


|



|


|

|
|

|
|


|



|
|




|





|

|


|
|
|

|


|

|


>

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

# TIP 392: Allow Bignums to be Disabled at Runtime on a Per-Interp Basis

	Author:		Joe Mistachkin <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		Pending
	Created:	30-Oct-2011
	Keywords:	bignum,runaway,safe,math,precision,integer,tcl
	Tcl-Version:	8.5
	Post-History:	
-----

# Abstract

This TIP proposes the ability to enable or disable all use of bignums at
runtime on a per-interpreter basis.  The mechanism being presented to
accomplish this goal has been designed to be generic enough so that it can be
used for other per-interpreter configuration parameters in the future.

# Rationale

As of Tcl version 8.5, almost any integer math calculation can result in
bignums being used.  Normally, this does not pose a serious problem; however,
there are circumstances in which this can exhaust key system resources, such
as memory or CPU time.  Unlike other similar resource exhaustion problems,
this one cannot be prevented by use of **interp create -safe**, **interp
limit**, **interp cancel**, or similar mechanisms.  If Tcl is being used in
an embedding scenario, this has the potential to negatively impact the entire
application or system.  If Tcl is being used to evaluate marginally trusted or
untrusted scripts in a safe interpreter, this can result in a
denial-of-service \(DoS\) attack.

# Specification

A new **interp configure** script command will be added, as follows:

 > **interp configure** _path_ ?_name_? ?_value_?

This command instructs Tcl to modify or query the value of the named
configuration parameter _name_ in the interpreter identified by _path_.

## Arguments

 > _path_

This argument is required and specifies the interpreter to be reconfigured. An
empty string may be used to indicate the current interpreter.

 > _name_

This argument is optional.  If this argument is not supplied, the current list
of configuration parameter names for the interpreter identified by _path_
will be returned.

 > _value_

This argument is optional.  If this argument is not supplied, the current
value of the named configuration parameter for the interpreter identified by
_path_ will be returned; otherwise, the current value of the configuration
parameter will be changed to the specified value.

## C API

 > Tcl\_Obj\* **Tcl\_InterpConfigure**\(Tcl\_Interp\* _interp_,
   Tcl\_Obj\* _nameObjPtr_, Tcl\_Obj\* _valueObjPtr_\)

The **Tcl\_InterpConfigure** function gets or sets the named configuration
parameter for the specified interpreter.  The _nameObjPtr_, if not NULL,
must be a string containing the name of a known configuration parameter;
otherwise, NULL will be returned and the interpreter result will be modified
to contain an appropriate error message.  The _valueObjPtr_, if not NULL,
must have a value convertible to the type required by the configuration
parameter being set; otherwise, NULL will be returned and the interpreter
result will be modified to contain an appropriate error message.  If
_valueObjPtr_ is NULL, the current value of the named configuration
parameter will be returned instead of being changed.  If _nameObjPtr_ is
NULL, the complete list of known configuration parameter names will be
returned.  The caller is responsible for managing the reference count of the
returned value.

# Configuration Parameters

Upon interpreter creation, all configuration parameters start with a default
value.  The default value for a configuration parameter is considered to be
part of the formal interface.

Initially, the only supported configuration parameter will be **bignums**.

When setting the **bignums** configuration parameter, the value must be
convertible to a boolean.  When the value of this configuration parameter is
false, any math operation that would require using bignums to calculate will
instead be limited to the precision available in the **Tcl\_WideInt** type.
The default value of this configuration parameter will be true \(i.e. use of
bignums will be enabled by default, preserving backward compatibility\).

# Reference Implementation

Not yet complete; however, it will eventually be available on the
**tip-392** branch of the Tcl source code repository.

# Copyright

This document has been placed in the public domain.

Name change from tip/393.tip to tip/393.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

TIP:            393
Title:          Add -command Option to lsearch
Version:        $Revision: 1.2 $
Author:         Pawel Salawa <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        25-Apr-2011
Post-History:   
Tcl-Version:    8.7


~ Abstract

This document describes new option for '''lsearch''' named '''-command''' that
lets the developer define a custom comparision algorithm for searching for an
element of a list.

~ Rationale

The '''-command''' option would be very useful when someone wants to look for
element on list, that contains objects (TclOO, Itcl, etc), or simply Tcl
dicts. Specifying a command lets a developer to decide what data from objects
in a list is important for the comparison.

This is effectively introducing the '''-command''' option from '''lsort''' to
'''lsearch'''.

~ Specification

The option '''-command''' takes additional argument, which is a name of a
command prefix that implements the comparison. The command prefix will have
two extra arguments added during evaluation, being (1) the element of the list
and (2) the pattern that is being sought. Thus, a suitable command might be
defined like:

|    proc searchCommand {listElement pattern} {...}

And used like:

|    lsearch -command searchCommand $list $pattern

The command must return a boolean value, where true means that the element
matches the pattern.  Since the '''-command''' option specifies a comparision
method, therefor it's treated the same way as '''-exact''', '''-glob''',
'''-regexp''' and '''-sorted''' options are. It also causes some options
(e.g., '''-integer''', '''-nocase''') to be ignored.

~ Reference Implementation

http://sqlitestudio.pl/tcl/patches/tip-393-lsearch-command.patch

Patch made against 8.6.0 beta.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|



|

|
|



|
|

|

|

|
|


|



|


|
|
|
|

|

|



|


>

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

# TIP 393: Add -command Option to lsearch

	Author:         Pawel Salawa <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        25-Apr-2011
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This document describes new option for **lsearch** named **-command** that
lets the developer define a custom comparision algorithm for searching for an
element of a list.

# Rationale

The **-command** option would be very useful when someone wants to look for
element on list, that contains objects \(TclOO, Itcl, etc\), or simply Tcl
dicts. Specifying a command lets a developer to decide what data from objects
in a list is important for the comparison.

This is effectively introducing the **-command** option from **lsort** to
**lsearch**.

# Specification

The option **-command** takes additional argument, which is a name of a
command prefix that implements the comparison. The command prefix will have
two extra arguments added during evaluation, being \(1\) the element of the list
and \(2\) the pattern that is being sought. Thus, a suitable command might be
defined like:

	    proc searchCommand {listElement pattern} {...}

And used like:

	    lsearch -command searchCommand $list $pattern

The command must return a boolean value, where true means that the element
matches the pattern.  Since the **-command** option specifies a comparision
method, therefor it's treated the same way as **-exact**, **-glob**,
**-regexp** and **-sorted** options are. It also causes some options
\(e.g., **-integer**, **-nocase**\) to be ignored.

# Reference Implementation

<http://sqlitestudio.pl/tcl/patches/tip-393-lsearch-command.patch>

Patch made against 8.6.0 beta.

# Copyright

This document has been placed in the public domain.

Name change from tip/394.tip to tip/394.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

TIP:		394
Title:		Platform-Independent Handling of Contemporary Mice
Version:	$Revision: 1.1 $
Author:		Andreas Leitgeb <[email protected]>
Type:		Project
Tcl-Version:	8.7
State:		Draft
Vote:		Pending
Created:	30-Nov-2011
Post-History:	


~ Abstract

This TIP proposes a change to Tk's Events such as to support new features of
modern pointer devices (mice) in a platform-independent way.

~ Rationale

Modern pointing devices (mice) do have more controls beyond the standard three
buttons and one-dimensional scrolling gadget.  They often have any of these as
well:

 * Tilt-able scroll wheel

 * A second wheel for horizontal scrolling

 * A scroll-ball rather than a scroll wheel (see Apple's "mightymouse")

 * Additional "forward" and "backward" buttons

 * even more buttons...

On Linux platform, bind'ing on <Button> will catch all(?) or these (and "%b"
gives an ordinal number which allows for some heuristic recognition). But even
on Linux, it is not possible to bind specifically to e.g. <Button-8>, or to
<B8-Motion> kind of events.

On Windows platform, the system offers different types of events for certain
different controls. An app would e.g. register extra to receive horizontal
scroll events and those extra buttons. (This is gathered from hearsay.)

~ Proposal

Just like the MouseWheel event that was added to Tk in response to wheel-mice
filling the market, we'd have to define new events for each new control.

For legacy-reasons, the dichotomy between vertical scroll wheel and buttons 4
and 5 will need to be preserved, maybe as well as the buttons 6 and 7 for
horizontal scrolling.

Any extra buttons could then be either named "X1", "X2", "X3", ...  or
numbered 8, 9, 10, ...  which would reflect as bind events <Button-8> or
<Button-X1>, but also <B8-Motion> or <BX1-Motion>

For horizontal scrolling, <MouseWheelHoriz> would be the preferred way for
cross-platform apps, but depending on whether "4 and 5" button events are
already emulated for scrolling on windows, it would be worthwhile to also
emulate "6 and 7" button events for horizontal wheel-activity.

At this stage of this TIP the decision isn't yet made.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|

|

|







|





|
|





|

|



















|


>

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

# TIP 394: Platform-Independent Handling of Contemporary Mice

	Author:		Andreas Leitgeb <[email protected]>
	Type:		Project
	Tcl-Version:	8.7
	State:		Draft
	Vote:		Pending
	Created:	30-Nov-2011
	Post-History:	
-----

# Abstract

This TIP proposes a change to Tk's Events such as to support new features of
modern pointer devices \(mice\) in a platform-independent way.

# Rationale

Modern pointing devices \(mice\) do have more controls beyond the standard three
buttons and one-dimensional scrolling gadget.  They often have any of these as
well:

 * Tilt-able scroll wheel

 * A second wheel for horizontal scrolling

 * A scroll-ball rather than a scroll wheel \(see Apple's "mightymouse"\)

 * Additional "forward" and "backward" buttons

 * even more buttons...

On Linux platform, bind'ing on <Button> will catch all\(?\) or these \(and "%b"
gives an ordinal number which allows for some heuristic recognition\). But even
on Linux, it is not possible to bind specifically to e.g. <Button-8>, or to
<B8-Motion> kind of events.

On Windows platform, the system offers different types of events for certain
different controls. An app would e.g. register extra to receive horizontal
scroll events and those extra buttons. \(This is gathered from hearsay.\)

# Proposal

Just like the MouseWheel event that was added to Tk in response to wheel-mice
filling the market, we'd have to define new events for each new control.

For legacy-reasons, the dichotomy between vertical scroll wheel and buttons 4
and 5 will need to be preserved, maybe as well as the buttons 6 and 7 for
horizontal scrolling.

Any extra buttons could then be either named "X1", "X2", "X3", ...  or
numbered 8, 9, 10, ...  which would reflect as bind events <Button-8> or
<Button-X1>, but also <B8-Motion> or <BX1-Motion>

For horizontal scrolling, <MouseWheelHoriz> would be the preferred way for
cross-platform apps, but depending on whether "4 and 5" button events are
already emulated for scrolling on windows, it would be worthwhile to also
emulate "6 and 7" button events for horizontal wheel-activity.

At this stage of this TIP the decision isn't yet made.

# Copyright

This document has been placed in the public domain.

Name change from tip/395.tip to tip/395.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

TIP:            395
Title:          New 'string is entier' Command
Version:        $Revision: 1.5 $
Author:         Jos Decoster <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        13-Dec-2011
Post-History:   
Discussions-To: news:comp.lang.tcl
Keywords:       Tcl
Tcl-Version:    8.6
Obsoletes:	347


~ Abstract

The '''string is''' command supports tests for a number of Tcl's basic types,
for example, integers, doubles, and booleans. One common case is missing:
checking if a value is an integer number without particular storage width,
unlike '''string is integer''' and '''string is wideinteger'''. This document
proposes to augment the '''string is''' command with a '''string is entier'''.

~ Rationale

Tcl makes it easy to work with integers larger than 64 bit (big nums). The
'''expr''' command supports operations on unlimited bit widths. Checking if a
string contains a valid integer value is possible with the '''string is
integer''' and '''string is wideinteger''' commands for integers of particular
storage widths (e.g. 32 bit for integers and 64 bit for wide integers). But
checking if a string contains a valid integer wider than a '''wideinteger'''
is not possible with a '''string is''' command. Checking if a string contains
a valid big num can now be done with a regular expression or by
'''catch'''-ing the '''::tcl::mathfunc::entier''' function.

~ Specification

This document proposes to augment the '''string is''' command with a '''string
is entier''' which functions the same as '''string is integer''' in every
respect except for the fact that it accepts any string containing a substring
that is valid as a bignum integer (that is, acceptable to
''Tcl_GetBignumFromObj'') possibly surrounded by whitespace.

~ Compatibility

No incompatibilities are introduced.

~ Alternatives

The '''bignum''' was rejected in favor of '''entier''' because '''entier''' is
already used in '''::tcl::mathfunc::entier'''.

~ Reference Implementation

A reference implementation is available here:

    http://sites.google.com/site/josdecoster/Home/tip_string_is_entier.diff

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|


|
|

|

|
|
|
|
|
|
|

|

|

|
|

|
|

|



|

|
|

|



|

|


>

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

# TIP 395: New 'string is entier' Command

	Author:         Jos Decoster <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        13-Dec-2011
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Keywords:       Tcl
	Tcl-Version:    8.6
	Obsoletes:	347
-----

# Abstract

The **string is** command supports tests for a number of Tcl's basic types,
for example, integers, doubles, and booleans. One common case is missing:
checking if a value is an integer number without particular storage width,
unlike **string is integer** and **string is wideinteger**. This document
proposes to augment the **string is** command with a **string is entier**.

# Rationale

Tcl makes it easy to work with integers larger than 64 bit \(big nums\). The
**expr** command supports operations on unlimited bit widths. Checking if a
string contains a valid integer value is possible with the **string is
integer** and **string is wideinteger** commands for integers of particular
storage widths \(e.g. 32 bit for integers and 64 bit for wide integers\). But
checking if a string contains a valid integer wider than a **wideinteger**
is not possible with a **string is** command. Checking if a string contains
a valid big num can now be done with a regular expression or by
**catch**-ing the **::tcl::mathfunc::entier** function.

# Specification

This document proposes to augment the **string is** command with a **string
is entier** which functions the same as **string is integer** in every
respect except for the fact that it accepts any string containing a substring
that is valid as a bignum integer \(that is, acceptable to
_Tcl\_GetBignumFromObj_\) possibly surrounded by whitespace.

# Compatibility

No incompatibilities are introduced.

# Alternatives

The **bignum** was rejected in favor of **entier** because **entier** is
already used in **::tcl::mathfunc::entier**.

# Reference Implementation

A reference implementation is available here:

    <http://sites.google.com/site/josdecoster/Home/tip\_string\_is\_entier.diff>

# Copyright

This document has been placed in the public domain.

Name change from tip/396.tip to tip/396.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

190
191
192
193
194
195

196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

TIP:            396
Title:          Symmetric Coroutines, Multiple Args, and yieldto
Version:        $Revision: 1.8 $
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        11-Feb-2012
Post-History:   
Keywords:       coroutine,yield,yieldto
Obsoletes:      372
Tcl-Version:    8.6


~ Abstract

A new command, '''yieldto''', is proposed that allows a corouting to suspend
its execution and tailcall into an arbitrary command.  If the new command is
another coroutine's resume command, we obtain symmetric coroutines.  If the
new command is the '''return''' command, we obtain the ability for a coroutine
to present an unusual status (e.g., ''error'', ''break'', ''continue'' or
''return'') to its caller. The '''yieldto''' command also marshals the
arguments as a list when the yielding coroutine is next invoked, allowing for
the transmission of multiple arguments.

~ Rationale

Several TIPS (at least [372], [373], [375], and [383]) have been advanced to
propose various improvements to the coroutine control transfer provided by the
'''yield''' command. This TIP attempts to distill the requirements of these
TIPs into an irreducible minimum for implementation in 8.6 (resolving a
blocking issue for an 8.6 release).

This TIP intentionally leaves out of scope some of the more complex or
controversial issues, such as enhancements to '''info args''' and '''info
default''', unusual return from a `yield` operation. and code injection into
coroutines.  It is believed that all of these can be added later, without
introducing needless incompatibilities into the basic mechanisms of coroutine
construction, invocation, and yielding.

Requirements that are thought to be essential for this TIP include:

'''The ability for a coroutine invocation to implement any argument
signature that an Tcl command can implement.''' A coroutine invocation
must be able to accept multiple arguments, and to allow for
call-by-name (or rather, call-by-quasi-value-result, see below) parameter
transmission.

'''The ability to return an unusual status.''' A coroutine invocation
must be able to return an error status or another unusual status
(e.g., ''break'', ''continue'' or ''return'') to its caller, and to
perform a tailcall.

'''Support for symmetric coroutines.''' Although it is well known that
asymmetric coroutines (such as Tcl 8.6 implements today) and symmetric
coroutines have equivalent power, the implementation of symmetric coroutines
in a system that supports only asymmetric ones is possible only by coding a
separate scheduler that allows an active coroutine to detach with a request to
resume another. If symmetric coroutines are not implemented directly, it is
likely that multiple incompatible schedulers will spring up in user code,
greatly impeding a later unification.

~ Proposal

The new command:

 > '''yieldto''' ''cmd'' ?''arg1...''?

shall accept one or more arguments:

 > ''cmd'' - The name of a command to invoke in place of the current coroutine
   invocation.

 > ''arg1...'' - The arguments to pass to the given command.

It shall have the following effects:

 1. The ''cmd'' argument shall be resolved in the current coroutine's context,
    resulting in a command to invoke.  If resolution fails, the error is
    presented in the coroutine's context.

 2. The current coroutine shall suspend its execution in the same way as with
    the '''yield''' command.

 3. The command that invokes the coroutine shall be placed into a state such
    that it will accept multiple arguments when it is next invoked, rather
    than the single argument demanded by '''yield'''. 

 4. The command and arguments shall be invoked in just the same way as if they
    had been called directly from the coroutine's caller. The given command
    replaces the coroutine invocation on the runtime stack. Data and status
    returned from the given command are returned to the context that invoked
    the coroutine.

 5. When the coroutine is resumed, any arguments passed into the coroutine
    command are assembled into a list and returned as the value of the
    '''yieldto''' command.

In other words, '''yieldto''' means "suspend the current coroutine and
'''tailcall''' the given command: '''yieldto''' is to '''yield''' as
'''tailcall''' is to '''return'''." In addition, '''yieldto''' causes the
current coroutine to accept multiple arguments on its next invocation.

~ Relationship with the Earlier Proposals

[372] proposes a '''yieldm''' command that allows a coroutine to yield and
subsequently accept multiple arguments when resumed.  The requested
functionality of [372] can be layered trivially atop this proposal: a one-line
implementation of the '''yieldm''' command would be:

 > interp alias {} yieldm {} yieldto return -level 0

[373] proposed '''yieldto''' together with a separate '''yieldset''' command.
The latter allowed a coroutine to designate a set of arguments and defaults.
The advantage over simply passing the arguments as a list was that error
messages for incorrect numbers of arguments could be generated automatically,
and that '''info args''' and '''info body''' could introspect into the desired
argument list.  Since the error message generation can be done readily by
auxiliary procedures, and the introspection is something of a nicety, this
proposal defers the implementation of '''yieldset'''.

[375], which replaced [373], proposed a '''yieldto''' command that is the same
as the current proposal's, except that it could transmit only a single
argument when the coroutine was resumed. As such, it was incomplete as it
stands.

[387] proposed a unified syntax for all of the above TIPs. The proposed syntax
was quite complex, and its only advantage over the current proposal is that is
allowed for introspection using '''info args''' and '''info body''' and for
automatic generation of error messages for incorrect arguments. Since these
are regarded as something of a nicety, the author of the current proposal
believes that their consideration can be deferred in favour of the current
proposal.

The related [383] addresses a different set of issues: injecting code into a
suspended coroutine for the purpose of debugging.  Its implementation can be
decided on independently of this TIP.

~ Examples:

~~ 1. Multiple arguments and error returns.

Let us assume that there is a coroutine '''foo''' that wishes to accept at
each invocation two arguments '''bar''' and '''grill'''. It therefore needs to
accept multiple arguments, and to check the number of arguments, returning an
error to its caller if they are incorrect. Code structured like the following
can serve both purposes:

| # presume that $value is the value to return to the last invocation
| for {set args [yieldto return -level 0 $value]} \
|     {[llength $args] != 2} \
|     {set args [yieldto return -level 0 -code error \
|                    -errorCode {MYCORO WRONGNUMARGS} \
|                    "wrong # args, should be \"foo bar grill\""]} {
|         # do nothing
| }

| lassign $args bar grill

~~ 2. Symmetric coroutines.

It may not be obvious from the foregoing discussion that the original purpose
of '''yieldto''' was imagined to be passing of control between peer
coroutines.  For instance, if we assume that there are two coroutines,
'''producer''' and '''consumer''', and that calling '''producer''' returns a
string while calling '''consumer''' accepts a string and returns nothing, then
each coroutine may yield to the other:

''Code in'' '''producer''':

| yieldto consumer $string

''Code in'' '''consumer''':

| lassign [yieldto producer] string

~~ 3. Call by name.

It turns out that '''yieldto''' allows for a rough simulation of Tcl's
call by name, although it requires explicit transmission of values
between coroutines, rather than a simple '''uplevel''' operation. Let
us assume that a caller invokes a coroutine with the name of an
array, and that the coroutine wishes to set elements of that array.
A procedure like the following will give approximately the desired
result.

| proc remote-set {varName value} {
|     lassign [yieldto remote-set-worker $varName $value [info coroutine]] \
|         status result
|     return -code $status $result
| }

| proc remote-set-worker {varName value coro} {
|     tailcall $coro \
|         [catch {uplevel 1 [list set $varName $value]} result] \
|         $result
| }


(Proper transmission of the options dictionary from '''catch''' is omitted
for the sake of simplicity.)

Let's look at what happens when code in the coroutine ''mycoro'' does

| remote-set array(key) value

 1. The '''remote-set''' procedure yields to the command

|         remote-set-worker array(key) value mycoro

 2. The '''remote-set-worker''', executing in the calling coroutine,
    invokes

|         set array(key) value

 >  in its caller's scope, capturing the status and return value.  Presuming
    that the variable was set successfully, It then invokes

|         mycoro 0 value

 >  as a tailcall, re-entering the ''mycoro'' coroutine. The two-element
 >  list, {0 value}, becomes the return value of '''yieldto'''

 3. The '''remote-set''' procedure returns the same status and result
    that the '''set''' command returned.

This technique actually shows how arbitrary commands may be executed
in a calling coroutine.  The way this is done opens some interesting
possibilities for tools such as debugging interactors. For instance, a
'''trace''' callback might invoke a debugging coroutine to interact with
the user, allow the user to execute arbitrary commands to probe the state 
of the code being debugged, and then transparently resume at the place
that the code left off, without otherwise disturbing its stack.

~ Implementation notes

The '''yieldto return''' idiom is expected to be used widely, since it is the
way to present unusual status codes, and internally is used in the
implementation of '''yieldm'''.  For this reason, the implementation may
contain code to optimize it specially.

~ Acknowledgments

The implementation of this TIP, and most of the details of its specification,
are actually the brainchild of Miguel Sofer, who expresses a continued
interest in seeing it implemented while being unwilling at the present time to
shepherd it through the sometimes acrimonious discussions on tcl-core. To him
belongs all the credit for the ideas: any errors in the specification as
presented here are the author's.

Thanks are due to Donal Fellows, Joe English, Andreas Leitgeb, and
Lars Hellstr�m for making needed corrections to the initial version of
this TIP.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|
|
|



|

|

|
|
|


|
|






|
|

|


|

|


|
|







|



|



|


|



|




|



|









|

|
|
|


|

|

|
|

|

|



|


|

|




|

|





|



|

|

|
|




|
|
|
|
|
|
|
<
>
|

|


|

|
|


|

|

|

|

|

|

|





|
|
|
|
<
>
|
|
|
|
<
|
>
|
|

|

|

|

|

|


|

|


|

|
|

|
|




|




|

|

|


|









|


|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

188
189
190
191
192

193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

# TIP 396: Symmetric Coroutines, Multiple Args, and yieldto

	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        11-Feb-2012
	Post-History:   
	Keywords:       coroutine,yield,yieldto
	Obsoletes:      372
	Tcl-Version:    8.6
-----

# Abstract

A new command, **yieldto**, is proposed that allows a corouting to suspend
its execution and tailcall into an arbitrary command.  If the new command is
another coroutine's resume command, we obtain symmetric coroutines.  If the
new command is the **return** command, we obtain the ability for a coroutine
to present an unusual status \(e.g., _error_, _break_, _continue_ or
_return_\) to its caller. The **yieldto** command also marshals the
arguments as a list when the yielding coroutine is next invoked, allowing for
the transmission of multiple arguments.

# Rationale

Several TIPS \(at least [[372]](372.md), [[373]](373.md), [[375]](375.md), and [[383]](383.md)\) have been advanced to
propose various improvements to the coroutine control transfer provided by the
**yield** command. This TIP attempts to distill the requirements of these
TIPs into an irreducible minimum for implementation in 8.6 \(resolving a
blocking issue for an 8.6 release\).

This TIP intentionally leaves out of scope some of the more complex or
controversial issues, such as enhancements to **info args** and **info
default**, unusual return from a \`yield\` operation. and code injection into
coroutines.  It is believed that all of these can be added later, without
introducing needless incompatibilities into the basic mechanisms of coroutine
construction, invocation, and yielding.

Requirements that are thought to be essential for this TIP include:

**The ability for a coroutine invocation to implement any argument
signature that an Tcl command can implement.** A coroutine invocation
must be able to accept multiple arguments, and to allow for
call-by-name \(or rather, call-by-quasi-value-result, see below\) parameter
transmission.

**The ability to return an unusual status.** A coroutine invocation
must be able to return an error status or another unusual status
\(e.g., _break_, _continue_ or _return_\) to its caller, and to
perform a tailcall.

**Support for symmetric coroutines.** Although it is well known that
asymmetric coroutines \(such as Tcl 8.6 implements today\) and symmetric
coroutines have equivalent power, the implementation of symmetric coroutines
in a system that supports only asymmetric ones is possible only by coding a
separate scheduler that allows an active coroutine to detach with a request to
resume another. If symmetric coroutines are not implemented directly, it is
likely that multiple incompatible schedulers will spring up in user code,
greatly impeding a later unification.

# Proposal

The new command:

 > **yieldto** _cmd_ ?_arg1..._?

shall accept one or more arguments:

 > _cmd_ - The name of a command to invoke in place of the current coroutine
   invocation.

 > _arg1..._ - The arguments to pass to the given command.

It shall have the following effects:

 1. The _cmd_ argument shall be resolved in the current coroutine's context,
    resulting in a command to invoke.  If resolution fails, the error is
    presented in the coroutine's context.

 2. The current coroutine shall suspend its execution in the same way as with
    the **yield** command.

 3. The command that invokes the coroutine shall be placed into a state such
    that it will accept multiple arguments when it is next invoked, rather
    than the single argument demanded by **yield**. 

 4. The command and arguments shall be invoked in just the same way as if they
    had been called directly from the coroutine's caller. The given command
    replaces the coroutine invocation on the runtime stack. Data and status
    returned from the given command are returned to the context that invoked
    the coroutine.

 5. When the coroutine is resumed, any arguments passed into the coroutine
    command are assembled into a list and returned as the value of the
    **yieldto** command.

In other words, **yieldto** means "suspend the current coroutine and
**tailcall** the given command: **yieldto** is to **yield** as
**tailcall** is to **return**." In addition, **yieldto** causes the
current coroutine to accept multiple arguments on its next invocation.

# Relationship with the Earlier Proposals

[[372]](372.md) proposes a **yieldm** command that allows a coroutine to yield and
subsequently accept multiple arguments when resumed.  The requested
functionality of [[372]](372.md) can be layered trivially atop this proposal: a one-line
implementation of the **yieldm** command would be:

 > interp alias \{\} yieldm \{\} yieldto return -level 0

[[373]](373.md) proposed **yieldto** together with a separate **yieldset** command.
The latter allowed a coroutine to designate a set of arguments and defaults.
The advantage over simply passing the arguments as a list was that error
messages for incorrect numbers of arguments could be generated automatically,
and that **info args** and **info body** could introspect into the desired
argument list.  Since the error message generation can be done readily by
auxiliary procedures, and the introspection is something of a nicety, this
proposal defers the implementation of **yieldset**.

[[375]](375.md), which replaced [[373]](373.md), proposed a **yieldto** command that is the same
as the current proposal's, except that it could transmit only a single
argument when the coroutine was resumed. As such, it was incomplete as it
stands.

[[387]](387.md) proposed a unified syntax for all of the above TIPs. The proposed syntax
was quite complex, and its only advantage over the current proposal is that is
allowed for introspection using **info args** and **info body** and for
automatic generation of error messages for incorrect arguments. Since these
are regarded as something of a nicety, the author of the current proposal
believes that their consideration can be deferred in favour of the current
proposal.

The related [[383]](383.md) addresses a different set of issues: injecting code into a
suspended coroutine for the purpose of debugging.  Its implementation can be
decided on independently of this TIP.

# Examples:

## 1. Multiple arguments and error returns.

Let us assume that there is a coroutine **foo** that wishes to accept at
each invocation two arguments **bar** and **grill**. It therefore needs to
accept multiple arguments, and to check the number of arguments, returning an
error to its caller if they are incorrect. Code structured like the following
can serve both purposes:

	 # presume that $value is the value to return to the last invocation
	 for {set args [yieldto return -level 0 $value]} \
	     {[llength $args] != 2} \
	     {set args [yieldto return -level 0 -code error \
	                    -errorCode {MYCORO WRONGNUMARGS} \
	                    "wrong # args, should be \"foo bar grill\""]} {
	         # do nothing

	 }
	 lassign $args bar grill

## 2. Symmetric coroutines.

It may not be obvious from the foregoing discussion that the original purpose
of **yieldto** was imagined to be passing of control between peer
coroutines.  For instance, if we assume that there are two coroutines,
**producer** and **consumer**, and that calling **producer** returns a
string while calling **consumer** accepts a string and returns nothing, then
each coroutine may yield to the other:

_Code in_ **producer**:

	 yieldto consumer $string

_Code in_ **consumer**:

	 lassign [yieldto producer] string

## 3. Call by name.

It turns out that **yieldto** allows for a rough simulation of Tcl's
call by name, although it requires explicit transmission of values
between coroutines, rather than a simple **uplevel** operation. Let
us assume that a caller invokes a coroutine with the name of an
array, and that the coroutine wishes to set elements of that array.
A procedure like the following will give approximately the desired
result.

	 proc remote-set {varName value} {
	     lassign [yieldto remote-set-worker $varName $value [info coroutine]] \
	         status result
	     return -code $status $result

	 }
	 proc remote-set-worker {varName value coro} {
	     tailcall $coro \
	         [catch {uplevel 1 [list set $varName $value]} result] \
	         $result

	 }

\(Proper transmission of the options dictionary from **catch** is omitted
for the sake of simplicity.\)

Let's look at what happens when code in the coroutine _mycoro_ does

	 remote-set array(key) value

 1. The **remote-set** procedure yields to the command

		         remote-set-worker array(key) value mycoro

 2. The **remote-set-worker**, executing in the calling coroutine,
    invokes

		         set array(key) value

	 >  in its caller's scope, capturing the status and return value.  Presuming
    that the variable was set successfully, It then invokes

		         mycoro 0 value

	 >  as a tailcall, re-entering the _mycoro_ coroutine. The two-element
	 >  list, \{0 value\}, becomes the return value of **yieldto**

 3. The **remote-set** procedure returns the same status and result
    that the **set** command returned.

This technique actually shows how arbitrary commands may be executed
in a calling coroutine.  The way this is done opens some interesting
possibilities for tools such as debugging interactors. For instance, a
**trace** callback might invoke a debugging coroutine to interact with
the user, allow the user to execute arbitrary commands to probe the state 
of the code being debugged, and then transparently resume at the place
that the code left off, without otherwise disturbing its stack.

# Implementation notes

The **yieldto return** idiom is expected to be used widely, since it is the
way to present unusual status codes, and internally is used in the
implementation of **yieldm**.  For this reason, the implementation may
contain code to optimize it specially.

# Acknowledgments

The implementation of this TIP, and most of the details of its specification,
are actually the brainchild of Miguel Sofer, who expresses a continued
interest in seeing it implemented while being unwilling at the present time to
shepherd it through the sometimes acrimonious discussions on tcl-core. To him
belongs all the credit for the ideas: any errors in the specification as
presented here are the author's.

Thanks are due to Donal Fellows, Joe English, Andreas Leitgeb, and
Lars Hellström for making needed corrections to the initial version of
this TIP.

# Copyright

This document has been placed in the public domain.

Name change from tip/397.tip to tip/397.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

TIP:		397
Title:		Extensible Object Copying
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Post-History:	
Version:	$Revision: 1.4 $
Author:		Donal K. Fellows <[email protected]>
Created:	13-Feb-2012
Keywords:	Tcl, TclOO, copy, clone


~ Abstract

This TIP proposes a mechanism whereby an object or class can provide
additional control over how it gets copied to a new one by the '''oo::copy'''
command.

~ Rationale

I always knew that TclOO's '''oo::copy''' command was not particularly
complete, in that only the C-level state was copied. The vast majority of
state associated with an object (notably including its variables) was not
copied on the grounds that the caller of '''oo::copy''' could do that for
themselves. However, this has not proved particularly workable in practice
once someone actually started to use the mechanism. It turns out that the
callers of '''oo::copy''' expect a full copy of the object to be created.

This is quite challenging because some things associated with an object are
tricky to copy correctly. For example, if an object has a number of Tk widgets
under its control, or has timer callbacks set up, these are very challenging
for a generic object copying scheme to detect (and generic copying of Tcl
commands is difficult anyway). Fortunately, we already have a mechanism for
handling such per-object variation: methods.

~ Proposed Change

I propose that the '''oo::copy''' command will internally call the newly
created object's '''<cloned>''' method (passing in the name of the source
object as the only argument) to allow for the customization of the copy. If
the method fails (throws an exception), the copy will be destroyed and the
error propagated.

 > ''copiedObject'' '''<cloned>''' ''sourceObject''

Furthermore, a default implementation of the '''<cloned>''' method will be
created in '''oo::object''' which will duplicate the variables and procedures
(note, not other commands) of the source to the copy. This method will not be
exported by default (nor should it be; the method is not intended to be called
directly).

~ Reference Implementation

See the "development-rfe3485060" branch of the tcloo repository:
https://core.tcl.tk/tcloo/timeline?r=development-rfe3485060

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|


|


|

|

|
|


|




|
|


|

|
|
|
|


|

|
|
|
|
|

|


|

|


>

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

# TIP 397: Extensible Object Copying
	State:		Final
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Done
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	13-Feb-2012
	Keywords:	Tcl, TclOO, copy, clone
-----

# Abstract

This TIP proposes a mechanism whereby an object or class can provide
additional control over how it gets copied to a new one by the **oo::copy**
command.

# Rationale

I always knew that TclOO's **oo::copy** command was not particularly
complete, in that only the C-level state was copied. The vast majority of
state associated with an object \(notably including its variables\) was not
copied on the grounds that the caller of **oo::copy** could do that for
themselves. However, this has not proved particularly workable in practice
once someone actually started to use the mechanism. It turns out that the
callers of **oo::copy** expect a full copy of the object to be created.

This is quite challenging because some things associated with an object are
tricky to copy correctly. For example, if an object has a number of Tk widgets
under its control, or has timer callbacks set up, these are very challenging
for a generic object copying scheme to detect \(and generic copying of Tcl
commands is difficult anyway\). Fortunately, we already have a mechanism for
handling such per-object variation: methods.

# Proposed Change

I propose that the **oo::copy** command will internally call the newly
created object's **<cloned>** method \(passing in the name of the source
object as the only argument\) to allow for the customization of the copy. If
the method fails \(throws an exception\), the copy will be destroyed and the
error propagated.

 > _copiedObject_ **<cloned>** _sourceObject_

Furthermore, a default implementation of the **<cloned>** method will be
created in **oo::object** which will duplicate the variables and procedures
\(note, not other commands\) of the source to the copy. This method will not be
exported by default \(nor should it be; the method is not intended to be called
directly\).

# Reference Implementation

See the "development-rfe3485060" branch of the tcloo repository:
<https://core.tcl.tk/tcloo/timeline?r=development-rfe3485060>

# Copyright

This document has been placed in the public domain.

Name change from tip/398.tip to tip/398.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

TIP:            398
Title:          Quickly Exit with Non-Blocking Blocked Channels
Version:        $Revision: 1.7 $
Author:         Alexandre Ferrieux <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        24-Feb-2012
Post-History:   
Keywords:       close,exit,flush,blocking,nonblocking
Tcl-Version:    8.6


~ Abstract

This TIP reverts an age-old documented behavior that is useless, and the ill
effects of which cannot be circumvented: Tcl's insistence on flushing even
non-blocking channels on exit.

~ Rationale

The close.n manpage says:

 > Channels are automatically closed when an interpreter is destroyed and when
   the process exits.  Channels are switched to blocking mode, to ensure that
   all output is correctly flushed before the process exits.

So, assuming the application has been using nonblocking IO all the time to
stay responsive even with blocked sockets (network failures) or pipes (stalled
consumer), if it decides to give up and exit, it ''cannot'' do so today: Tcl
will switch those channels back to blocking mode, and sit forever trying to
flush them, until a kind hand hits ^C.

No combination of '''close'''/'''fconfigure'''/'''exit''' will do, thanks to
the above clarification.

Note that the intent of this behavior is to automagically prevent careless
applications from truncating their output. The flaw of this logic is that such
careless applications typically don't use nonblocking channels. Hence the
generalization is abusive.

Hence, the proposal of this TIP is simply to revert this deleterious choice.
This way:

 * simple apps continue to autoflush their blocking channels,

 * smart nonblocking contraptions enjoy a timely exit, and

 * generic code can even guarantee quick death by switching all channels to
   nonblocking mode, like this:

|   proc instantdeath {{status 0}} {
|       foreach ch [chan names] {fconfigure $ch -blocking 0}
|       exit $status
|   }


~ Specification

Nonblocking channels shall no longer be switched to blocking mode
when the process calls '''exit''' or ''Tcl_Exit()''.  Any buffered data
for nonblocking channels will be discarded.

~ Notes

Blocking channels are unaffected by this TIP;  blocking channels shall
still be flushed and closed at '''exit'''-time

~ Related Bugs

Bug 2946474 noted the accidental, non-TIP-warranted suppression of this
strange behavior.  Fixing this bug simply meant to comply with Day One
documentation.  This TIP now judges the substance.

~ Reference Implementation

Branch tip-398-impl holds the code.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|








|
|



|

















|
|
|
<
|
>
|


|


|


|

|





|



|


>

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

# TIP 398: Quickly Exit with Non-Blocking Blocked Channels

	Author:         Alexandre Ferrieux <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        24-Feb-2012
	Post-History:   
	Keywords:       close,exit,flush,blocking,nonblocking
	Tcl-Version:    8.6
-----

# Abstract

This TIP reverts an age-old documented behavior that is useless, and the ill
effects of which cannot be circumvented: Tcl's insistence on flushing even
non-blocking channels on exit.

# Rationale

The close.n manpage says:

 > Channels are automatically closed when an interpreter is destroyed and when
   the process exits.  Channels are switched to blocking mode, to ensure that
   all output is correctly flushed before the process exits.

So, assuming the application has been using nonblocking IO all the time to
stay responsive even with blocked sockets \(network failures\) or pipes \(stalled
consumer\), if it decides to give up and exit, it _cannot_ do so today: Tcl
will switch those channels back to blocking mode, and sit forever trying to
flush them, until a kind hand hits ^C.

No combination of **close**/**fconfigure**/**exit** will do, thanks to
the above clarification.

Note that the intent of this behavior is to automagically prevent careless
applications from truncating their output. The flaw of this logic is that such
careless applications typically don't use nonblocking channels. Hence the
generalization is abusive.

Hence, the proposal of this TIP is simply to revert this deleterious choice.
This way:

 * simple apps continue to autoflush their blocking channels,

 * smart nonblocking contraptions enjoy a timely exit, and

 * generic code can even guarantee quick death by switching all channels to
   nonblocking mode, like this:

		   proc instantdeath {{status 0}} {
		       foreach ch [chan names] {fconfigure $ch -blocking 0}
		       exit $status

		   }

# Specification

Nonblocking channels shall no longer be switched to blocking mode
when the process calls **exit** or _Tcl\_Exit\(\)_.  Any buffered data
for nonblocking channels will be discarded.

# Notes

Blocking channels are unaffected by this TIP;  blocking channels shall
still be flushed and closed at **exit**-time

# Related Bugs

Bug 2946474 noted the accidental, non-TIP-warranted suppression of this
strange behavior.  Fixing this bug simply meant to comply with Day One
documentation.  This TIP now judges the substance.

# Reference Implementation

Branch tip-398-impl holds the code.

# Copyright

This document has been placed in the public domain.

Name change from tip/399.tip to tip/399.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
136
137

TIP:            399
Title:          Dynamic Locale Changing for msgcat
Version:        $Revision: 1.18 $
Author:         Harald Oehlmann <[email protected]>
State:          Accepted
Type:           Project
Vote:           Done
Created:        27-Mar-2012
Post-History:   
Keywords:       Tcl,localization,msgcat
Tcl-Version:    8.6
Obsoleted-By:	412


~ Abstract

This TIP adds dynamic locale switching capabilities to the '''msgcat'''
package.

~ Rationale

Within a multi-language application like a web-server, one may change the
locale quite frequently, for example if users with different locales are
requesting pages. Unfortunately, this does not fit well with the model adopted
by the '''msgcat''' package, which assumes that all code follows this
sequence:

 1.
 Set locale list: '''mclocale''' ''locale''

 2.
 Load language files with other package load: '''mcload''' ''msg-folder''

 3.
 Translate strings: '''mc''' ''key args...''

Note that if the locale should be changed after other packages are loaded, one
must restart at step 2.  This requires reloading all packages which is mostly
not practical.
The key issue is that '''mcload''' only loads language files included in the
current locale ('''mcpreferences''') and does not load any others.

The aim of this TIP is to extend '''mcload''' to load additional language
files.  Then '''mclocale''' may be called to change the locale on runtime
without the need to re-execute '''mcload''' (which would normally imply to
reinitialise or reload the package).

~ Specification

This TIP proposes to add a new command:

 > '''msgcat::mcconfig -pattern''' ?''patternlist''?

This command may get or set package options.
There is currently one option "'''-pattern'''".

Options may be set using

 > '''msgcat::mcconfig''' ''option value'' ?''option''? ?''value''?

Current option values may be read using:

 > '''msgcat::mcconfig''' ''option''

~~ Option -pattern

The option '''-pattern''' consists of a list of language file name patterns
like '''fr*''', '''*''', or '''fr_ch'''.

Any '''mcload''' command executed after this setting will consider this list ''in addition'' to the current locale list.
Files are searched using a '''glob''' command per element on the specified pattern plus the string ".msg".
If "fr*" is specified within the pattern list, the file search pattern is "fr*.msg".

The default option value is the empty list {}.
In consequence, only files covered by the current locale list are sourced.

~ Example Usage

Imagine an application which supports the current user language and French,
German and English.  An external package '''tp''' is used.  The package uses
'''msgcat''' and performes within the '''package require tp''' call:

|package require msgcat
|msgcat::mcload [file join [file dirname [info script]] msgs]

An implementation of the application with the current msgcat 1.4.4 would
require the following initialisation sequence:

|package require msgcat
|package require np

and the following code to change the locale to French:

|package forget np
|msgcat::mclocale fr
|package require np

Using the extension of this tip, the required code for initialisation is:

|package require msgcat
|msgcat::mcconfig -pattern {fr* de* en*}
|package require np

and to change to french locale:

|msgcat::mclocale fr

Within this modification, locale change is a cheap operation.  Before, it was
computational expensive (if possible, as many packages are not reloadable or a
reload may disturb current processing, e.g., by forcing the closing of
sockets, etc.).

~ Reference Implementation

See Tcl Feature Request 3511941.
[http://sourceforge.net/support/tracker.php/?aid=3511941]

~ Compatibility

No incompatibilities are introduced.

~ Issues

Packages might not be aware of a locale change and may buffer translations outside of '''msgcat'''.
Packages should not buffer msgcat messages if they are used in a dynamic locale application (like tklib tooltip does for example).

~ Alternatives

This implementation requires the setting of the pattern before any package
with msgcat is loaded. To avoid this, msgcat must store all paths passed by
any '''mcload''' call. When a locale change happens, any currently missing
files are loaded. This requires much more housekeeping and may lead to side
effects, especially if packages are not aware of the fact that their package
files are loaded outside of the '''mcload''' command.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|




|



|


|


|




|
|

|
|
|
|

|



|


|



|



|

|

|
|

|
|
|

|


|


|
|

|
|




|
|



|
|
|



|
|
|



|


|

|

|


|

|



|

|
|

|



|


|

|


>

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
136
137

# TIP 399: Dynamic Locale Changing for msgcat

	Author:         Harald Oehlmann <[email protected]>
	State:          Accepted
	Type:           Project
	Vote:           Done
	Created:        27-Mar-2012
	Post-History:   
	Keywords:       Tcl,localization,msgcat
	Tcl-Version:    8.6
	Obsoleted-By:	412
-----

# Abstract

This TIP adds dynamic locale switching capabilities to the **msgcat**
package.

# Rationale

Within a multi-language application like a web-server, one may change the
locale quite frequently, for example if users with different locales are
requesting pages. Unfortunately, this does not fit well with the model adopted
by the **msgcat** package, which assumes that all code follows this
sequence:

 1.
 Set locale list: **mclocale** _locale_

 2.
 Load language files with other package load: **mcload** _msg-folder_

 3.
 Translate strings: **mc** _key args..._

Note that if the locale should be changed after other packages are loaded, one
must restart at step 2.  This requires reloading all packages which is mostly
not practical.
The key issue is that **mcload** only loads language files included in the
current locale \(**mcpreferences**\) and does not load any others.

The aim of this TIP is to extend **mcload** to load additional language
files.  Then **mclocale** may be called to change the locale on runtime
without the need to re-execute **mcload** \(which would normally imply to
reinitialise or reload the package\).

# Specification

This TIP proposes to add a new command:

 > **msgcat::mcconfig -pattern** ?_patternlist_?

This command may get or set package options.
There is currently one option "**-pattern**".

Options may be set using

 > **msgcat::mcconfig** _option value_ ?_option_? ?_value_?

Current option values may be read using:

 > **msgcat::mcconfig** _option_

## Option -pattern

The option **-pattern** consists of a list of language file name patterns
like **fr\***, **\***, or **fr\_ch**.

Any **mcload** command executed after this setting will consider this list _in addition_ to the current locale list.
Files are searched using a **glob** command per element on the specified pattern plus the string ".msg".
If "fr\*" is specified within the pattern list, the file search pattern is "fr\*.msg".

The default option value is the empty list \{\}.
In consequence, only files covered by the current locale list are sourced.

# Example Usage

Imagine an application which supports the current user language and French,
German and English.  An external package **tp** is used.  The package uses
**msgcat** and performes within the **package require tp** call:

	package require msgcat
	msgcat::mcload [file join [file dirname [info script]] msgs]

An implementation of the application with the current msgcat 1.4.4 would
require the following initialisation sequence:

	package require msgcat
	package require np

and the following code to change the locale to French:

	package forget np
	msgcat::mclocale fr
	package require np

Using the extension of this tip, the required code for initialisation is:

	package require msgcat
	msgcat::mcconfig -pattern {fr* de* en*}
	package require np

and to change to french locale:

	msgcat::mclocale fr

Within this modification, locale change is a cheap operation.  Before, it was
computational expensive \(if possible, as many packages are not reloadable or a
reload may disturb current processing, e.g., by forcing the closing of
sockets, etc.\).

# Reference Implementation

See Tcl Feature Request 3511941.
<http://sourceforge.net/support/tracker.php/?aid=3511941> 

# Compatibility

No incompatibilities are introduced.

# Issues

Packages might not be aware of a locale change and may buffer translations outside of **msgcat**.
Packages should not buffer msgcat messages if they are used in a dynamic locale application \(like tklib tooltip does for example\).

# Alternatives

This implementation requires the setting of the pattern before any package
with msgcat is loaded. To avoid this, msgcat must store all paths passed by
any **mcload** call. When a locale change happens, any currently missing
files are loaded. This requires much more housekeeping and may lead to side
effects, especially if packages are not aware of the fact that their package
files are loaded outside of the **mcload** command.

# Copyright

This document has been placed in the public domain.

Name change from tip/4.tip to tip/4.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265

TIP:            4
Title:          Tcl Release and Distribution Philosophy
Version:        $Revision: 1.10 $
Author:         Brent Welch <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         Larry W. Virden <[email protected]>
Author:         Larry W. Virden <[email protected]>
State:          Draft
Type:           Informative
Vote:           Pending
Created:        26-Oct-2000
Post-History:   
Discussions-To: news:comp.lang.tcl


~ Abstract

This document outlines how Tcl should be distributed, with
particular reference to issues related to building a
distribution with the ''batteries included'' so that most people
can have access to the useful extensions without having to
chasing halfway across the 'net for them.

~ Overview

Tcl has traditionally been a "core" that is extensible with binary
extensions and Tcl scripts.  There have been two styles of Tcl
distributions: source and binary.  The Tcl source distribution
contains the Tcl "core" and a small number of support scripts.  The
binary distributions have included Tk, and in some cases (e.g.,
TclPro) other extensions like [[incr Tcl]], TclX, and Expect.  Users
with access to a compiler can get source distributions of the various
extensions and compile them for their own installation.  ''(Thanks to
Bob Technetin <[email protected]> for the inspiration for
these pictures - DKF.)''

#image:4layers1 Traditional Tcl Distribution Architecture

This proposal formalizes the notion of a small Tcl source core
and larger distribution bundle that includes one or many
extensions.  The distribution can be in source or binary form.
The goal is to keep a small core that is suitable for embedding
with the smallest footprint, while acknowleding that desktop
users and application developers want a larger ''standard
distribution'' that has a set of well known and widely used
extensions.

The goal of this proposal is to establish a standard
for future Tcl distributions.  There will be two kinds
of Tcl distributions:  a small core suitable for
specialized embedded applications, and a larger bundled
distribution suitable for more general application
development.

#image:4layers2 Batteries-Included Tcl Distribution Architecture

~ The Tcl Core Distribution

The Tcl "core" should remain as small as possible, and could
become smaller in the future as certain features are moved into
extensions.  The "core" distribution must include:

 1. The C sources required to create the Tcl binary library.

 1. The C sources required to create a "Tcl Shell" application.
    This is commonly known as "tclsh".

 1. The Tcl script libraries that implement the code library and
    packaging systems.  This includes the "unknown" command and
    various commands related to auto loading of packages.

 1. The Tcl test framework used for testing the Tcl binary
    library and the support scripts.

Additional items may appear in the "core" distribution,
especially for historical reasons.  But, some Tcl scripts and
binary extensions that currently exist (as of Tcl 8.3) in the
Tcl source distributions may migrate into the larger
distribution described below.

~ The Bundled Distribution

The ''bundled'' Tcl distribution will contain Tcl, various
binary extensions, and various Tcl script packages.  This
proposal establishes an initial set of binary extensions, but
following the model and using the distribution infrastructure we
create, various bundles should be easily created.

Each package included in the bundled distribution must
have a test suite and documentation.  At this stage
the documentation will probably be in a variety of
formats, but ultimately we should standardize on an
XML-based representation and supply tools that generate
other formats from that representation.

~ Mandatory Packages

The bundled distribution must include (but is not limited to):

 1. The "core" distribution described above.

 1. The Tk toolkit for GUI applications.  This includes the well
    known "wish" shell application.

 1. The registry and dde extensions for the Windows platform.

 1. The [[incr Tcl]] extension.  

 1. The TclX extension.  There are some historical features of
    TclX that should not necessarily be included, including the
    tclx shell and its alternate library format.  However, the
    TclX help system should not only be included, but updated to
    include info on all commands included in the distribution.

 1. The Expect extension for UNIX platforms.

 1. The TkCon enhanced console application.

~ Optional Packages

In addition, it is likely that several of the following packages
will be included in the bundled distribution, as well as
others not listed.

 1. The Standard Tcl Library of Tcl scripts.  Currently this
    includes packages for:

 > 1. base64 encoding/decoding

 > 1. file utilities

 > 1. command line processing

 > 1. FTP client library

 > 1. FTP server

 > 1. HTML and JavaScript generation

 > 1. Math and statistics utilities

 > 1. MIME encoder and parser

 > 1. CGI processing (ncgi)

 > 1. NNTP client

 > 1. POP3 client

 > 1. Profiler for Tcl scripts

 > 1. Event counters and interval timers

 > 1. Structures, including tree, stack, graph, queue

 > 1. URI parsing

 > 1. Text string manipulation utilities (trim, tab, etc.)

 1. BLT.

 1. [[incr Tk]] and [[incr Widgets]].

 1. TkTable.

 1. The Standard Tk Library of Tcl/Tk scripts.  Currently
    this includes packages for:

 > 1. BWidgets

 > 1. mclistbox

 1. Img

~ Rationale

The small "core" distribution must retain its identity for those
applications that embed the Tcl interpreter into constrained
environments and require a small footprint. The footprint must
remain small, and in fact it should grow smaller, if possible.
For example, in the early days of Tcl it was possible at compile
time to remove all the file system and exec commands to create a
very small Tcl core.  There are wide variety of vendors that
embed Tcl into, e.g., CAD applications, router firmware, and
other limited environments.  They only need the basic commands
for procedural programming and basic data types.

The larger, bundled distribution must become the standard for
desktop distributions (e.g., Linux) so that application writers
have a richer set of Tcl commands that they can assume are
available.  This includes the [[incr Tcl]] class system and the
OS-specific commands provided the TclX and the registry and dde
extensions.

The set of packages in the bundled distribution are divided into
''mandatory'' and ''optional'' packages.  The intent of this
distinction is to set a goal for the initial ''bundled''
distribution, but not close the door to inclusion of other
packages.  Over time the set of packages in the bundled
distribution will surely grow, and some packages may become
superceeded by other better packages.  The ''mandatory set'' of
packages, however, should be common among all bundles to
application writers know what to expect.

In particular, the mandatory set includes [[incr Tcl]] to
promote object oriented programming, Tk to promote easy GUI
development, TclX, Dde and Registry to provide access to
OS-dependent functionality, and Expect to support automated test
environments.

At this time there are a variety of Tk widgets that are optional
because there is some overlap and we anticipate continuted
evolution of the Tk widget set.  I expect that the first bundle
will include all the major widget sets, including BLT, [[incr
Tk]] and [[incr Widgets]], TkTable, the "vu" collection, and
possibly Tix.

~ The Role of the TCT

The larger bundled distribution will contain packages that are
"owned" by the TCT and some that are not.  The whole process
will be more scalable if responsibility for packages can be
split out to other individuals and groups.  The role of the TCT
should be to set up the infrastructure for the bundled
distribution and to make ''official'' bundled distributions.

~ Issues

The main purpose of this proposal is to establish three things:

 1. The continued existence of a small Tcl "core" that is
    identifiable unto its own and useful to various specialized
    embedded applications.

 1. The creation of infrastructure to create bundled
    distributions.  The exact nature of this bundling is not
    specified.  The first bundles may well be created by hand
    crafted Makefiles and distribution-creation scripts.

 1. The set of ''mandatory'' extensions that should be included
    in any Tcl bundle.  The list in the first draft of this TIP
    is likely to be wrong, and will surely be amended in the
    future.

 1. Whether further distinctions should be introduced to better
    support people who wish to target Tcl towards small devices or
    embedded environments better.

#image:4layers3 Refined Tcl Distribution Architecture

There are a number of related topics that are deliberately
outside the scope of this TIP:

 1. Documentation format. 

 1. Network aware downloading of packages and more sophisticated
    package management.

 1. Details of the compile and build environment.  Currently
    there is the TEA standard, and the packages listed in the
    Mandatory set have all been set up for TEA as part of
    TclPro.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|



|



|





|
|

|

|

|






|
|









|

|



















|



|

|












|

|








|











|








|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|



|






|

|



|













|

|




|
|



|



|








|
|


|






|

|












|








|














|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265

# TIP 4: Tcl Release and Distribution Philosophy

	Author:         Brent Welch <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        26-Oct-2000
	Post-History:   
	Discussions-To: news:comp.lang.tcl
-----

# Abstract

This document outlines how Tcl should be distributed, with
particular reference to issues related to building a
distribution with the _batteries included_ so that most people
can have access to the useful extensions without having to
chasing halfway across the 'net for them.

# Overview

Tcl has traditionally been a "core" that is extensible with binary
extensions and Tcl scripts.  There have been two styles of Tcl
distributions: source and binary.  The Tcl source distribution
contains the Tcl "core" and a small number of support scripts.  The
binary distributions have included Tk, and in some cases \(e.g.,
TclPro\) other extensions like [incr Tcl], TclX, and Expect.  Users
with access to a compiler can get source distributions of the various
extensions and compile them for their own installation.  _\(Thanks to
Bob Technetin <[email protected]> for the inspiration for
these pictures - DKF.\)_

![Traditional Tcl Distribution Architecture](../assets/4layers1.gif)

This proposal formalizes the notion of a small Tcl source core
and larger distribution bundle that includes one or many
extensions.  The distribution can be in source or binary form.
The goal is to keep a small core that is suitable for embedding
with the smallest footprint, while acknowleding that desktop
users and application developers want a larger _standard
distribution_ that has a set of well known and widely used
extensions.

The goal of this proposal is to establish a standard
for future Tcl distributions.  There will be two kinds
of Tcl distributions:  a small core suitable for
specialized embedded applications, and a larger bundled
distribution suitable for more general application
development.

![Batteries-Included Tcl Distribution Architecture](../assets/4layers2.gif)

# The Tcl Core Distribution

The Tcl "core" should remain as small as possible, and could
become smaller in the future as certain features are moved into
extensions.  The "core" distribution must include:

 1. The C sources required to create the Tcl binary library.

 1. The C sources required to create a "Tcl Shell" application.
    This is commonly known as "tclsh".

 1. The Tcl script libraries that implement the code library and
    packaging systems.  This includes the "unknown" command and
    various commands related to auto loading of packages.

 1. The Tcl test framework used for testing the Tcl binary
    library and the support scripts.

Additional items may appear in the "core" distribution,
especially for historical reasons.  But, some Tcl scripts and
binary extensions that currently exist \(as of Tcl 8.3\) in the
Tcl source distributions may migrate into the larger
distribution described below.

# The Bundled Distribution

The _bundled_ Tcl distribution will contain Tcl, various
binary extensions, and various Tcl script packages.  This
proposal establishes an initial set of binary extensions, but
following the model and using the distribution infrastructure we
create, various bundles should be easily created.

Each package included in the bundled distribution must
have a test suite and documentation.  At this stage
the documentation will probably be in a variety of
formats, but ultimately we should standardize on an
XML-based representation and supply tools that generate
other formats from that representation.

# Mandatory Packages

The bundled distribution must include \(but is not limited to\):

 1. The "core" distribution described above.

 1. The Tk toolkit for GUI applications.  This includes the well
    known "wish" shell application.

 1. The registry and dde extensions for the Windows platform.

 1. The [incr Tcl] extension.  

 1. The TclX extension.  There are some historical features of
    TclX that should not necessarily be included, including the
    tclx shell and its alternate library format.  However, the
    TclX help system should not only be included, but updated to
    include info on all commands included in the distribution.

 1. The Expect extension for UNIX platforms.

 1. The TkCon enhanced console application.

# Optional Packages

In addition, it is likely that several of the following packages
will be included in the bundled distribution, as well as
others not listed.

 1. The Standard Tcl Library of Tcl scripts.  Currently this
    includes packages for:

	 > 1. base64 encoding/decoding

	 > 1. file utilities

	 > 1. command line processing

	 > 1. FTP client library

	 > 1. FTP server

	 > 1. HTML and JavaScript generation

	 > 1. Math and statistics utilities

	 > 1. MIME encoder and parser

	 > 1. CGI processing \(ncgi\)

	 > 1. NNTP client

	 > 1. POP3 client

	 > 1. Profiler for Tcl scripts

	 > 1. Event counters and interval timers

	 > 1. Structures, including tree, stack, graph, queue

	 > 1. URI parsing

	 > 1. Text string manipulation utilities \(trim, tab, etc.\)

 1. BLT.

 1. [incr Tk] and [incr Widgets].

 1. TkTable.

 1. The Standard Tk Library of Tcl/Tk scripts.  Currently
    this includes packages for:

	 > 1. BWidgets

	 > 1. mclistbox

 1. Img

# Rationale

The small "core" distribution must retain its identity for those
applications that embed the Tcl interpreter into constrained
environments and require a small footprint. The footprint must
remain small, and in fact it should grow smaller, if possible.
For example, in the early days of Tcl it was possible at compile
time to remove all the file system and exec commands to create a
very small Tcl core.  There are wide variety of vendors that
embed Tcl into, e.g., CAD applications, router firmware, and
other limited environments.  They only need the basic commands
for procedural programming and basic data types.

The larger, bundled distribution must become the standard for
desktop distributions \(e.g., Linux\) so that application writers
have a richer set of Tcl commands that they can assume are
available.  This includes the [incr Tcl] class system and the
OS-specific commands provided the TclX and the registry and dde
extensions.

The set of packages in the bundled distribution are divided into
_mandatory_ and _optional_ packages.  The intent of this
distinction is to set a goal for the initial _bundled_
distribution, but not close the door to inclusion of other
packages.  Over time the set of packages in the bundled
distribution will surely grow, and some packages may become
superceeded by other better packages.  The _mandatory set_ of
packages, however, should be common among all bundles to
application writers know what to expect.

In particular, the mandatory set includes [incr Tcl] to
promote object oriented programming, Tk to promote easy GUI
development, TclX, Dde and Registry to provide access to
OS-dependent functionality, and Expect to support automated test
environments.

At this time there are a variety of Tk widgets that are optional
because there is some overlap and we anticipate continuted
evolution of the Tk widget set.  I expect that the first bundle
will include all the major widget sets, including BLT, [incr
Tk] and [incr Widgets], TkTable, the "vu" collection, and
possibly Tix.

# The Role of the TCT

The larger bundled distribution will contain packages that are
"owned" by the TCT and some that are not.  The whole process
will be more scalable if responsibility for packages can be
split out to other individuals and groups.  The role of the TCT
should be to set up the infrastructure for the bundled
distribution and to make _official_ bundled distributions.

# Issues

The main purpose of this proposal is to establish three things:

 1. The continued existence of a small Tcl "core" that is
    identifiable unto its own and useful to various specialized
    embedded applications.

 1. The creation of infrastructure to create bundled
    distributions.  The exact nature of this bundling is not
    specified.  The first bundles may well be created by hand
    crafted Makefiles and distribution-creation scripts.

 1. The set of _mandatory_ extensions that should be included
    in any Tcl bundle.  The list in the first draft of this TIP
    is likely to be wrong, and will surely be amended in the
    future.

 1. Whether further distinctions should be introduced to better
    support people who wish to target Tcl towards small devices or
    embedded environments better.

![Refined Tcl Distribution Architecture](../assets/4layers3.gif)

There are a number of related topics that are deliberately
outside the scope of this TIP:

 1. Documentation format. 

 1. Network aware downloading of packages and more sophisticated
    package management.

 1. Details of the compile and build environment.  Currently
    there is the TEA standard, and the packages listed in the
    Mandatory set have all been set up for TEA as part of
    TclPro.

# Copyright

This document has been placed in the public domain.

Name change from tip/40.tip to tip/40.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286

TIP:            40
Title:          Documentation Generator for Tcl Scripts
Version:        $Revision: 1.4 $
Author:         Arjen Markus <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        04-Jul-2001
Post-History:   
Keywords:       documentation,automatic generation,HTML,reference
Tcl-Version:    8.0


~ Abstract

This TIP proposes the adoption of a standard documentation format for
Tcl scripts and the implementation of a simple tool that will extract
this documentation from the source code so that it may be turned into
a programmer's guide.  This is in essence akin to documentation tools
like the well-known ''javadoc'' utility for Java programs and Eiffel's
short utility.

~ Introduction

The style guide by Ray Johnson presents a documentation standard that is
easy to use and is in fact adopted in the Tcl/Tk distribution.
Other than this, the standard has not been enforced or encouraged. It is
also not backed up by some tool (as far as I know) that can generate
pretty looking documents from this.  As a consequence, styles of
documentation may vary widely and at times it is necessary to read the
source code (looking for descriptions) to understand how to use the
script.

The availability of such a tool may encourage people to use the standard,
as the costs of generating the documentation are relatively low.
The tool must accommodate for variations and therefore be flexible -
for instance by providing customisable procedures to support the user's
preferred header format.

The tool also needs to distinguish the types of output: in many cases HTML
output is desirable to make it look pretty and provide hypertext facilities,
in other cases it should provide plain text, formatted so that it can be
read in any ordinary text editor or printed quickly.

Parallel to the development of such a tool, a standard or checklist should be
assembled of what information programmer ought to provide, the version of
Tcl/Tk, extensions that need to be present, what functionality is offered
and so on.

~ Rationale

Automatic documentation generation has two goals: improving usability and
improving maintainability. The first means: pleasant looking documentation,
at low cost for the author, is easy to use. One can also avoid reading the
source code. Further, it ensures homegeneously looking documentation.

Improving the maintainability is achieved by having more or less
technical documentation near the code. There is no need for separate
documents, something which enhances the risk of discrepancies. Remember
the DRY principle: Don't Repeat Yourself.

~ What information

A user clearly needs different information than a maintainer. For the
user it is important to know what functionality is provided, what other
packages or extensions are needed, which (public) procedures are available
and how to use them.

For the maintainer: having an overview of the source files helps finding
the procedures. Part of this information can be extracted directly from
the source (such as via inspection of the proc, package and
namespace statements).

~ Formats

Use the format proposed by the style guide as a guideline (certainly
for the reference implementation):

| # pkg_compareExtension --
| #

| #  Used internally by pkg_mkIndex to compare the extension of a file to
| #  a given extension. On Windows, it uses a case-insensitive comparison
| #  because the file system can be file insensitive.
| #

| # Arguments:
| #  fileName     name of a file whose extension is compared
| #  ext          (optional) The extension to compare against; you must
| #               provide the starting dot.
| #               Defaults to [info sharedlibextension]
| #

| # Results:
| #  Returns 1 if the extension matches, 0 otherwise

(This comes from the "package.tcl" script file that came with Tcl 8.3.1,
it is consistent with the Tcl style guide by Ray Johnson)

~ Requirements

The requirements are simple to describe:

 * Implementation shall be in Tcl, to guarantee availability and
   portability.

 * The system shall be easy to extend to new documentation formats
   (Implementation note:  small procedures that register the
   information piece by piece)

 * It shall be easy to extend to new output formats
   (Implementation note: small procedures that format the registered
   information)

 * It shall properly deal with organisational aspects:  source file,
   package, namespace.

~ Summary of reactions

The replies on the first version of this TIP were quite positive: both
Donal Porter and Cameron Laird think it is a good idea. Juan Gil gave
a very extensive reaction, describing a more general framework that
would eventually result in a system for generating all kinds of output
from Tcl scripts, TIPs and so on.

To do him more justice, without repeating the entire document, he
proposes the use of XML as an intermediate format holding the structure
of the information. The advantage is the possibility to reuse all
existing tools and (de facto) standards, notably DocBook, in this
context.

Even though I share some of the enthousiasm of Juan, I am a bit awed
by it: the original idea of this TIP is not so much creating a
publication system, but rather an easy-to-use tool for
automatically extracting useful information in a nice shape.
Eventually it could develop into something of the kind Juan describes,
but that should not be the first goal.

The technique for representing the information structure he proposes, is
quite useable (and akin to the rendering process of TIPs):

 * Parse the script and store the pieces in "qualified lists".

 * Such qualified lists are an intermediate format, either in memory or
   stored in a suitable format on disk.

 * These lists and lists of lists are then passed to the output
   renderers.

The first problem to solve is then finding a suitable structure for the
information we need to extract. This is the subject of the next section.

Will Duquette and Andreas Kupries mentioned the frequent use of
specialised commands that introduce new commands (rather than a
straightforward call to "proc"). This feature will have to be looked
into, because if you only look for lines like
"proc some-command { ... } {", you might well miss the essentials of
such applications.

~ Information in a Tcl script

Tcl scripts are organised in three essentially unrelated ways:

 * Individual files contain the code

 * Programs consist of one or several files of code

 * Packages are used to identify code that belongs together

In practice these methods will be used in accord with each other, but
there is no guarantee for instance, that a source file contains only one
package and programs will probably quite often use more than one
package.

On a smaller scale, the following items are of importance:

 * Procedures or commands defined inside some namespace (exported or
   not)

 * Variables local to the enclosing namespace or global to the
   application

For a user it will be important to know what a program or package has to
offer and how to get this functionality:

 * A description of the program (with its command-line arguments,
   if any, the packages it uses, if they come separately)

 * A description of the package or packages (assuming it is properly
   installed, its name and version should be enough to load the
   scripts and binaries)

 * A description of each public procedure and a description of the
   arguments and the result, if any

 * A list of all other requirements (other packages or the Tcl version?)

For a maintainer of the code, additional information would include:

 * A list of all variables (local to the namespace and global) that are
   used in the various procedures

 * The contents of each source file (so where does each procedure live?)

 * Detailed maintenance issues that have been written down in comments
   in the code

A possible structure in which all this information can be stored and
retrieved is sketched below:

| program:
|    version
|    source files (list of)
|    packages (list of)
|    procedures (list of)
|    command-line arguments:
|       description of each option and the values (if any)
|       associated with it
|       description of other arguments (such as file names)
| source files:
|    packages (list of)
|    procedures (list of)
| packages:
|    package A:
|       description
|       version
|       requirements
|          Tcl-version
|          packages that are required
|       local and global variables:
|          variable D:
|             used by which procedures?
|          variable E:
|             used by which procedures?
|          ...
|       procedures:
|          procedure F:
|             description
|             exported or not
|             arguments:
|                argument G:
|                   description
|                argument H:
|                   description
|                ...
|             result:
|                description
|          procedure I:
|             ...

Except for the descriptions, all these items can - at least in principle
be extracted automatically. So, even though the programmer has been too
lazy to describe his/her procedures in detail, some information can be
retrieved about the use of global data for instance and the complexity
of the argument lists.

Note that as far as the three methods of organisation is concerned,
there is no attempt to define a practical relationship between them.

To refer to the example above:

| procedure: pkg_compareExtension
|    description:
|       "Used internally by pkg_mkIndex to compare the extension of a file to
|       a given extension. On Windows, it uses a case-insensitive comparison
|       because the file system can be file insensitive."
|    arguments:
|       argument fileName:
|          description:
|             "name of a file whose extension is compared"
|       argument ext:
|          description:
|             "(optional) The extension to compare against; you must
|             provide the starting dot.
|             Defaults to [info sharedlibextension]"
|    result:
|       description:
|          "Returns 1 if the extension matches, 0 otherwise"

By adopting a tree structure to represent the information extracted from
the source code, one can be as flexible as probably needed. For instance,
suppose one would like to extract certain metrics, like the number of
lines or the cyclometric complexity. This could then be an additional
node in the subtree for the command procedure, besides the list of arguments,
the result and the description.

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|





|


|




|


|


















|











|



|




|
|

|

|
|

|
<
>
|
|
|
<
>
|
|
|
|
|
<
>
|
|

|
|

|







|
|


|
|




|










|










|













|
|

|


|
















|
|







|
|

|

|




|



|


|







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|












|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|








|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286

# TIP 40: Documentation Generator for Tcl Scripts

	Author:         Arjen Markus <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        04-Jul-2001
	Post-History:   
	Keywords:       documentation,automatic generation,HTML,reference
	Tcl-Version:    8.0
-----

# Abstract

This TIP proposes the adoption of a standard documentation format for
Tcl scripts and the implementation of a simple tool that will extract
this documentation from the source code so that it may be turned into
a programmer's guide.  This is in essence akin to documentation tools
like the well-known _javadoc_ utility for Java programs and Eiffel's
short utility.

# Introduction

The style guide by Ray Johnson presents a documentation standard that is
easy to use and is in fact adopted in the Tcl/Tk distribution.
Other than this, the standard has not been enforced or encouraged. It is
also not backed up by some tool \(as far as I know\) that can generate
pretty looking documents from this.  As a consequence, styles of
documentation may vary widely and at times it is necessary to read the
source code \(looking for descriptions\) to understand how to use the
script.

The availability of such a tool may encourage people to use the standard,
as the costs of generating the documentation are relatively low.
The tool must accommodate for variations and therefore be flexible -
for instance by providing customisable procedures to support the user's
preferred header format.

The tool also needs to distinguish the types of output: in many cases HTML
output is desirable to make it look pretty and provide hypertext facilities,
in other cases it should provide plain text, formatted so that it can be
read in any ordinary text editor or printed quickly.

Parallel to the development of such a tool, a standard or checklist should be
assembled of what information programmer ought to provide, the version of
Tcl/Tk, extensions that need to be present, what functionality is offered
and so on.

# Rationale

Automatic documentation generation has two goals: improving usability and
improving maintainability. The first means: pleasant looking documentation,
at low cost for the author, is easy to use. One can also avoid reading the
source code. Further, it ensures homegeneously looking documentation.

Improving the maintainability is achieved by having more or less
technical documentation near the code. There is no need for separate
documents, something which enhances the risk of discrepancies. Remember
the DRY principle: Don't Repeat Yourself.

# What information

A user clearly needs different information than a maintainer. For the
user it is important to know what functionality is provided, what other
packages or extensions are needed, which \(public\) procedures are available
and how to use them.

For the maintainer: having an overview of the source files helps finding
the procedures. Part of this information can be extracted directly from
the source \(such as via inspection of the proc, package and
namespace statements\).

# Formats

Use the format proposed by the style guide as a guideline \(certainly
for the reference implementation\):

	 # pkg_compareExtension --

	 #
	 #  Used internally by pkg_mkIndex to compare the extension of a file to
	 #  a given extension. On Windows, it uses a case-insensitive comparison
	 #  because the file system can be file insensitive.

	 #
	 # Arguments:
	 #  fileName     name of a file whose extension is compared
	 #  ext          (optional) The extension to compare against; you must
	 #               provide the starting dot.
	 #               Defaults to [info sharedlibextension]

	 #
	 # Results:
	 #  Returns 1 if the extension matches, 0 otherwise

\(This comes from the "package.tcl" script file that came with Tcl 8.3.1,
it is consistent with the Tcl style guide by Ray Johnson\)

# Requirements

The requirements are simple to describe:

 * Implementation shall be in Tcl, to guarantee availability and
   portability.

 * The system shall be easy to extend to new documentation formats
   \(Implementation note:  small procedures that register the
   information piece by piece\)

 * It shall be easy to extend to new output formats
   \(Implementation note: small procedures that format the registered
   information\)

 * It shall properly deal with organisational aspects:  source file,
   package, namespace.

# Summary of reactions

The replies on the first version of this TIP were quite positive: both
Donal Porter and Cameron Laird think it is a good idea. Juan Gil gave
a very extensive reaction, describing a more general framework that
would eventually result in a system for generating all kinds of output
from Tcl scripts, TIPs and so on.

To do him more justice, without repeating the entire document, he
proposes the use of XML as an intermediate format holding the structure
of the information. The advantage is the possibility to reuse all
existing tools and \(de facto\) standards, notably DocBook, in this
context.

Even though I share some of the enthousiasm of Juan, I am a bit awed
by it: the original idea of this TIP is not so much creating a
publication system, but rather an easy-to-use tool for
automatically extracting useful information in a nice shape.
Eventually it could develop into something of the kind Juan describes,
but that should not be the first goal.

The technique for representing the information structure he proposes, is
quite useable \(and akin to the rendering process of TIPs\):

 * Parse the script and store the pieces in "qualified lists".

 * Such qualified lists are an intermediate format, either in memory or
   stored in a suitable format on disk.

 * These lists and lists of lists are then passed to the output
   renderers.

The first problem to solve is then finding a suitable structure for the
information we need to extract. This is the subject of the next section.

Will Duquette and Andreas Kupries mentioned the frequent use of
specialised commands that introduce new commands \(rather than a
straightforward call to "proc"\). This feature will have to be looked
into, because if you only look for lines like
"proc some-command \{ ... \} \{", you might well miss the essentials of
such applications.

# Information in a Tcl script

Tcl scripts are organised in three essentially unrelated ways:

 * Individual files contain the code

 * Programs consist of one or several files of code

 * Packages are used to identify code that belongs together

In practice these methods will be used in accord with each other, but
there is no guarantee for instance, that a source file contains only one
package and programs will probably quite often use more than one
package.

On a smaller scale, the following items are of importance:

 * Procedures or commands defined inside some namespace \(exported or
   not\)

 * Variables local to the enclosing namespace or global to the
   application

For a user it will be important to know what a program or package has to
offer and how to get this functionality:

 * A description of the program \(with its command-line arguments,
   if any, the packages it uses, if they come separately\)

 * A description of the package or packages \(assuming it is properly
   installed, its name and version should be enough to load the
   scripts and binaries\)

 * A description of each public procedure and a description of the
   arguments and the result, if any

 * A list of all other requirements \(other packages or the Tcl version?\)

For a maintainer of the code, additional information would include:

 * A list of all variables \(local to the namespace and global\) that are
   used in the various procedures

 * The contents of each source file \(so where does each procedure live?\)

 * Detailed maintenance issues that have been written down in comments
   in the code

A possible structure in which all this information can be stored and
retrieved is sketched below:

	 program:
	    version
	    source files (list of)
	    packages (list of)
	    procedures (list of)
	    command-line arguments:
	       description of each option and the values (if any)
	       associated with it
	       description of other arguments (such as file names)
	 source files:
	    packages (list of)
	    procedures (list of)
	 packages:
	    package A:
	       description
	       version
	       requirements
	          Tcl-version
	          packages that are required
	       local and global variables:
	          variable D:
	             used by which procedures?
	          variable E:
	             used by which procedures?
	          ...
	       procedures:
	          procedure F:
	             description
	             exported or not
	             arguments:
	                argument G:
	                   description
	                argument H:
	                   description
	                ...
	             result:
	                description
	          procedure I:
	             ...

Except for the descriptions, all these items can - at least in principle
be extracted automatically. So, even though the programmer has been too
lazy to describe his/her procedures in detail, some information can be
retrieved about the use of global data for instance and the complexity
of the argument lists.

Note that as far as the three methods of organisation is concerned,
there is no attempt to define a practical relationship between them.

To refer to the example above:

	 procedure: pkg_compareExtension
	    description:
	       "Used internally by pkg_mkIndex to compare the extension of a file to
	       a given extension. On Windows, it uses a case-insensitive comparison
	       because the file system can be file insensitive."
	    arguments:
	       argument fileName:
	          description:
	             "name of a file whose extension is compared"
	       argument ext:
	          description:
	             "(optional) The extension to compare against; you must
	             provide the starting dot.
	             Defaults to [info sharedlibextension]"
	    result:
	       description:
	          "Returns 1 if the extension matches, 0 otherwise"

By adopting a tree structure to represent the information extracted from
the source code, one can be as flexible as probably needed. For instance,
suppose one would like to extract certain metrics, like the number of
lines or the cyclometric complexity. This could then be an additional
node in the subtree for the command procedure, besides the list of arguments,
the result and the description.

# Copyright

This document is placed in the public domain.

Name change from tip/400.tip to tip/400.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

TIP:		400
Title:		Setting the Compression Dictionary and Other 'zlib' Updates
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Post-History:	
Version:	$Revision: 1.7 $
Author:		Donal K. Fellows <[email protected]>
Created:	30-Mar-2012
Keywords:	Tcl, zlib


~ Abstract

Sometimes it is necessary to set the compression dictionary so that a sequence
of bytes may be compressed more efficiently (and decompressed as well). This
TIP exposes that functionality. It also reduces the number of inconsistencies
in the '''zlib''' command.

~ Rationale

The SPDY protocol extensions to HTTP require the seeding of the zlib
compression dictionary (which greatly improves the performance of compression
on small amounts of data, such as HTTP headers). In order to allow a pure Tcl
implementation of the SPDY protocol, it is therefore necessary to provide a
mechanism whereby the compression dictionary (a byte-array, normally up to 262
bytes long according to the zlib documentation).

There is to be no mechanism for retrieving the compression dictionary
generated by the compression engine; there is no API for doing that.

A side issue discovered during working on this TIP was that there was
considerable variation in what could be achieved by various parts of the API.
In partcular, it was identified that the API was inconsistent, providing
access to some features in "simplified" parts of the API that could not be
controlled from the "advanced" parts (e.g., there was no way to set the GZIP
header descriptor with '''zlib stream gzip''').

~ Proposed Changes: Tcl

~~ Changes to the Channel Transforms

The '''zlib push''' command will gain two extra options, '''-dictionary''' and
'''-limit''':

 > '''-dictionary''' ''bytes''

This option will provide a compression dictionary to be used (''bytes'' is a
byte-array used to initialize the compression engine) which will be supplied
to the zlib compression engine at the correct moment during compression or
provided on request of the compression engine on decompression. The ''bytes''
argument must be non-empty if given (we will not enforce a limit on the length
of the dictionary, but using an excessively long one may cause the zlib engine
to issue errors).
This will be illegal to use with '''gzip''' and '''gunzip''' streams, and its
use with raw ('''deflate''') streams will be not recommended due to the
difficulty of detecting whether a compression dictionary was applied; the
zlib-format header adds very little overhead. This value can also be set with
'''chan configure''', though doing so after data has started to be pushed
through the compression engine (except if an error requesting a compression
dictionary was received) is not recommended.

 > '''-limit''' ''size''

This option (valid on the three decompressing transforms only, and where
''size'' must be a positive integer of no more than 0x10000) allows for
control over the size of chunks read from the underlying channel for feeding
into the decompression engine. Its default is 1, which makes for the correct
behavior under the widest range of conditions, but at a significant cost in
terms of computational complexity: when the underlying data source is known to
never block for long and to have complete data, a larger value can be used
which will greatly improve performance. This value can be set at runtime using
'''chan configure'''.

~~ Changes to the Streams

The '''zlib stream''' command will also gain some complexity. In particular, 
the '''compress''', '''decompress''', '''deflate''' and '''inflate'''
subcommands will gain the ability to take an extra '''-dictionary''' ''bytes''
pair of options (same interpretation as above), as will the '''add''' and
'''put''' subcommands of the stream instance command.

In addition (as a correction to the functionality originally proposed in
[234]) the '''zlib stream gzip''' subcommand will also gain the ability to
take:

 > '''-header''' ''dict''

(where ''dict'' is a Tcl dictionary such as is passed to the '''-header'''
option to '''zlib gzip''' and not a compression dictionary), and the stream
instance subcommand will gain a '''header''' subcommand to retrieve the gzip
header (it will be an error to use it on a stream not produced by '''zlib
stream gunzip'''). In order to facilitate the above change, the compression
level used in that case will be altered to be specified via an option:

 > '''-level''' ''compressionLevel''

~ Proposed Change: C

At the C level, one additional function will be provided:

 > void '''Tcl_ZlibStreamSetCompressionDictionary'''(Tcl_ZlibStream
   ''zshandle'', Tcl_Obj *''compressionDictionaryObj'')

This sets the compression dictionary for a particular stream to the given
(byte-array) Tcl_Obj, which will be duplicated. It is the caller's
responsibility to dispose of the object passed in if they allocated it; they
may do so immediately after calling this function.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|


|

|

|


|
|

|
|








|
|

|

|

|
|

|

|
|

|
|

|
|
|


|
|
|

|

|
|






|

|

|
|
|
|
|

|
|


|

|
|
|
|
|


|

|



|
|


|



|


>

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

# TIP 400: Setting the Compression Dictionary and Other 'zlib' Updates
	State:		Final
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Done
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	30-Mar-2012
	Keywords:	Tcl, zlib
-----

# Abstract

Sometimes it is necessary to set the compression dictionary so that a sequence
of bytes may be compressed more efficiently \(and decompressed as well\). This
TIP exposes that functionality. It also reduces the number of inconsistencies
in the **zlib** command.

# Rationale

The SPDY protocol extensions to HTTP require the seeding of the zlib
compression dictionary \(which greatly improves the performance of compression
on small amounts of data, such as HTTP headers\). In order to allow a pure Tcl
implementation of the SPDY protocol, it is therefore necessary to provide a
mechanism whereby the compression dictionary \(a byte-array, normally up to 262
bytes long according to the zlib documentation\).

There is to be no mechanism for retrieving the compression dictionary
generated by the compression engine; there is no API for doing that.

A side issue discovered during working on this TIP was that there was
considerable variation in what could be achieved by various parts of the API.
In partcular, it was identified that the API was inconsistent, providing
access to some features in "simplified" parts of the API that could not be
controlled from the "advanced" parts \(e.g., there was no way to set the GZIP
header descriptor with **zlib stream gzip**\).

# Proposed Changes: Tcl

## Changes to the Channel Transforms

The **zlib push** command will gain two extra options, **-dictionary** and
**-limit**:

 > **-dictionary** _bytes_

This option will provide a compression dictionary to be used \(_bytes_ is a
byte-array used to initialize the compression engine\) which will be supplied
to the zlib compression engine at the correct moment during compression or
provided on request of the compression engine on decompression. The _bytes_
argument must be non-empty if given \(we will not enforce a limit on the length
of the dictionary, but using an excessively long one may cause the zlib engine
to issue errors\).
This will be illegal to use with **gzip** and **gunzip** streams, and its
use with raw \(**deflate**\) streams will be not recommended due to the
difficulty of detecting whether a compression dictionary was applied; the
zlib-format header adds very little overhead. This value can also be set with
**chan configure**, though doing so after data has started to be pushed
through the compression engine \(except if an error requesting a compression
dictionary was received\) is not recommended.

 > **-limit** _size_

This option \(valid on the three decompressing transforms only, and where
_size_ must be a positive integer of no more than 0x10000\) allows for
control over the size of chunks read from the underlying channel for feeding
into the decompression engine. Its default is 1, which makes for the correct
behavior under the widest range of conditions, but at a significant cost in
terms of computational complexity: when the underlying data source is known to
never block for long and to have complete data, a larger value can be used
which will greatly improve performance. This value can be set at runtime using
**chan configure**.

## Changes to the Streams

The **zlib stream** command will also gain some complexity. In particular, 
the **compress**, **decompress**, **deflate** and **inflate**
subcommands will gain the ability to take an extra **-dictionary** _bytes_
pair of options \(same interpretation as above\), as will the **add** and
**put** subcommands of the stream instance command.

In addition \(as a correction to the functionality originally proposed in
[[234]](234.md)\) the **zlib stream gzip** subcommand will also gain the ability to
take:

 > **-header** _dict_

\(where _dict_ is a Tcl dictionary such as is passed to the **-header**
option to **zlib gzip** and not a compression dictionary\), and the stream
instance subcommand will gain a **header** subcommand to retrieve the gzip
header \(it will be an error to use it on a stream not produced by **zlib
stream gunzip**\). In order to facilitate the above change, the compression
level used in that case will be altered to be specified via an option:

 > **-level** _compressionLevel_

# Proposed Change: C

At the C level, one additional function will be provided:

 > void **Tcl\_ZlibStreamSetCompressionDictionary**\(Tcl\_ZlibStream
   _zshandle_, Tcl\_Obj \*_compressionDictionaryObj_\)

This sets the compression dictionary for a particular stream to the given
\(byte-array\) Tcl\_Obj, which will be duplicated. It is the caller's
responsibility to dispose of the object passed in if they allocated it; they
may do so immediately after calling this function.

# Copyright

This document has been placed in the public domain.

Name change from tip/401.tip to tip/401.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

153
154
155

156
157
158

159
160
161
162
163
164
165

166
167
168

169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292


293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322

323
324
325
326
327
328


329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377


378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524

TIP:            401
Title:          Comment Words with Leading {#}
Version:        $Revision: 1.5 $
Author:         Lars Hellstr�m <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        29-Apr-2012
Post-History:   
Tcl-Version:    8.7


~ Abstract

The basic syntax rules of Tcl (the "dodekalogue") are modified to allow words
that are comments. In analogy with the argument expansion '''{*}''', such
comment words will begin with '''{#}''' (left brace, hash sign, right brace).  
The change concerns both words in scripts and, more importantly, words in lists.

~ Rationale

Tcl is special in that comments appear at the "statement" (command) level of
the language syntax rather than the "token" level (as is the case in e.g. the
ALGOL language family: C, Pascal, Java, etc.). This means a Tcl program has
fewer places in which a comment can be placed than many other languages, but
this has not been a serious problem in traditional Tcl programming as commands
tend to be short (except when they have arguments that are themselves Tcl
scripts) and places where a comment can be inserted thus frequent enough.
Recent developments in the language have however changed this.

Various new features -- particularly dictionaries, ensembles, and argument
expansion (all of which were introduced with Tcl 8.5) -- have encouraged a
coding style where occasionally fairly large blocks of code can be spent
setting up data structures as explicit values. For example, an ensemble that
relies on the '''-map''' option typically has the entire mapping dictionary as
a braced word in the code, and this can grow rather large if subcommands are
being mapped to command prefixes of length greater than one. '''string map'''
mappings can grow very large if there are many cases to deal with.
Dictionaries have greatly simplified the use of values with inner structure,
and as a result the complexity of the data that routinely gets passed to
package commands has increased; a controlling data structure (e.g. a grammar,
in the case of a parser) that once required an entire API of constructors to
build might now have been redesigned as a simple nested dictionary that can be
written raw in the code. And on top of it all, the various examples given
above are not excluding each other, but may rather nest to form even larger
blocks of code without any part that is a script. Adding a class of comments
that can begin anywhere a word can begin undoes the forced "comment desert"
status of such code blocks, because words are syntactic units not just in
commands but also in lists, and all of the structured explicit values
mentioned above are syntactically either plain lists or lists with additional
restrictions.

A parallel development is that the gap between what some piece of Tcl looks
like at coding time and at runtime has begun to widen, because an increasing
number of APIs call for fragments of commands (particularly command prefixes)
rather than full commands or scripts. This change is often good from a
correctness and efficiency point of view, but can make code harder to maintain
on account of being more obscure; the evocation of runtime calls resulting
from a particular piece of code sometimes requires a considerable effort of
imagination, even if all APIs involved are well documented. Comment words that
appear in the position(s) where additional material is inserted at runtime can
help the mind here, by letting the eyes see in the code those things that will
be there when it is evaluated, e.g. rather than

|  socket -server [list ::some::handler $settings] $port

one might write

|  socket -server [
|      list ::some::handler $settings {#}chan {#}client {#}clientport
|  ] $port

to emphasize the fact that this '''::some::handler''' command takes those four
things as arguments, even though only one of them is present in the command
prefix.

For command words to not change the interpretation of any presently legal
syntactic construction, they must be something which is not valid as a list
element word. The brace-something-brace-something syntax region where argument
expansion was given a home is pretty much the only possibility there is for
this (if one rules out unbalanced words), since there is very little that the
Tcl parser finds outright wrong. The '''#''' character is the normal way of
starting a command-level comment, so it is natural that it occurs also in the
syntax of word-level comments.

~ Specification

Clause 5 (argument expansion) of the Tcl.n manpage is to be amended with the
following conditions, and the language parser is to be modified accordingly.

 > If a word starts with the string "{#}" followed by a non-whitespace
   character, then the leading "{#}" is removed and the rest of the word is
   parsed and substituted as any other word. The result of this substitution
   is not used for anything, and no word is added to the command being
   substituted. For instance, "cmd a {#}{b c} d {#}e f" is equivalent to "cmd
   a d f".

Moreover, the analogous modification shall be made to the list parser; a word
with '''{#}''' proper prefix is recognised as a comment also in a list, where
the initial substitution phase only performs backslash substitution.

''Note 1:''
The point of doing substitution is to stick as close to the behaviour of
'''{*}''' as possible. Of the three steps involved in argument expansion -
parse and substitute word, reparse result without substitution as a list of
words, and append those words to command being built -- only the middle one
need to be different for '''{#}''', and thus a lot of the code can be shared.

''Note 2:''
The comment prefix is typically most useful with words like

| cmd {#}{some [text]} {#}bareword {#}"Comment goes here"

but things like this are also legal:

| cmd {#}$var {#}$x,\n {#}[foo bar]

''Note 3:''
It is ''very'' important for serveral use-cases that comment words are
recognised as such also in lists. One might (as I would) argue that this
should really follow automatically, since outside the source itself the only
(and not very explicit) documentation of the string representation of lists is
found in the lindex.n manpage which merely says that:

 > In extracting the element, '''lindex''' observes the same rules concerning
   braces and quotes and backslashes as the Tcl command interpreter; however,
   variable substitution and command substitution do not occur.

As only variable and command substitution are mentioned as things which differ
between lists and commands, they therefore must treat '''{#}''' the same.
However, presently the argument expansion '''{*}''' is not recognised in
lists, despite there not being a stated exception for that either. (This state
of affairs is reasonable, since it would be very complicated to extend present
mechanisms to support argument expansion in lists and the benefit of doing so
is slim at best, but it should be more clearly documented.)

~ Use Cases

~~ More comments in switch

Beginning with an old issue, one may consider the placement of comments to
'''switch''' cases. The current advice is to place them first in the bodies
(which of course works), but it can often be exposition-wise more natural to
place them before the pattern, especially if there is not a 1-1 correspondence
between comments and bodies.

|  switch -regexp [string trimleft $number +-] {
| 
|      {#}"Integer formats"
|      {^0$} - 
|      {^[1-9][0-9]*$} {
|           # ...
|      }

|      {^0o[0-7]+$} {
|           # ...
|      }

|      {^0x[0-9A-Fa-f]+$} {
|           # ...
|      }

|      
|      {#}"Float formats"
|      {^[0-9]*\.[0-9]+(e[+-][0-9]+)$} -
|      {^[0-9]+\.[0-9]*(e[+-][0-9]+)$} -
|      {^[0-9]+e[+-][0-9]+$}  {
|           # ...
|      }

|      
|  }


~~ Inline comments in long commands

Some commands can be very long simply because they require a lot of arguments
to express what one wants, and then comments can help clarify what a
particular argument contributes to.

|  $canvas create polygon 0 0 {#}"left top" 30 0 {#}"bend down" 30 30 \
|    {#}"concave part" 60 30 {#}"bend up" 60 0 {#}"right top" 90 0 \
|    {#}"curving back" 90 30 45 67 0 30 {#}"done" -smooth true \
|    -width 2 -fill orange -outline green {#}"Official colours" \
|    -tags {button {#}"for clicking" buoyant {#}"affects movement"}

If there are several ideas in such a command, it might be nice to put the
comments pertaining to each next to where that idea actually shows up in the
code.

~~ Inline argument descriptions

The Tcl style guide for C code suggests that comments describing function
arguments appear inline with the argument declarations. Comment words would
permit the same style in Tcl code.

| proc tcl::Pkg::CompareExtension {
|    fileName      {#}"name of a file whose extension is compared"
|    {ext {}}      {#}"The extension to compare against; you must
|                      provide the starting dot. Defaults to the 
|                      info sharedlibextension."
| } {
|    # ...
| }


(Whether that style would be regarded as an improvement or not probably
depends on one's taste.)

~~ Filling in words that will be there at runtime

At one point, I found myself wanting to do some calculations with matrices
whose elements were polynomials (with integer coefficients) of four
noncommuting variables ''A'', ''B'', ''C'', and ''D''. Having previously
implemented some basic algebraic constructions, I could quickly set up a
command that implemented arithmetic with such matrices through the two
'''interp alias'''es

| interp alias {} Z<A,B,C,D> {} \
|   ::mtmtcl::rings::semigroup_algebra ::mtmtcl::rings::integers::all\
|     ::mtmtcl::groups::string_free_monoid
| interp alias {} matrices {} \
|   ::mtmtcl::matprop::trivial dummy ::Z<A,B,C,D>

This is however not a very readable definition even if one is familiar with
the commands it uses (and realises that there is nothing magical about the
command name '''Z<A,B,C,D>'''), because the way that things appear in this
piece of code is visually quite different from the context in which they will
appear when evaluated. If instead comment words are inserted as visual
placeholders for the missing material, then the overall appearance becomes
much closer to that of a script calling these commands.

| interp alias {} Z<A,B,C,D> {#}method {#}args {} \
|   ::mtmtcl::rings::semigroup_algebra {
|      ::mtmtcl::rings::integers::all {#}method {#}args
|   } {
|      ::mtmtcl::groups::string_free_monoid {#}method {#}args
|   } {#}method {#}args
| interp alias {} matrices {#}method {#}args {} \
|   ::mtmtcl::matprop::trivial dummy {
|      ::Z<A,B,C,D> {#}method {#}args
|   } {#}method {#}args

~~ "K combinator"

In the Tcl community, the ''K combinator'' idiom is when you first produce an
argument for the main command (through variable or command substitution), then
evaluate some other command which has beneficial side-effects but whose result
is of no interest, and finally evaluate the main command.  (The original K
combinator, as found combinatory logic, is more about getting rid of unwanted
arguments supplied to a command prefix than about exploiting side-effects, but
there is a continuum connecting the two.)  This is most often employed to have
a variable release its reference to a Tcl_Obj, so that the latter becomes
unshared and possible for a command to modify directly. '''{#}''' introduces
the new form

| set stack [lreplace $stack {#}[set stack whatever] end end]

of this, providing yet another alternative to such old forms as

| set stack [lreplace $stack [set stack end] end]
| set stack [lreplace $stack[set stack ""] end end]
| set stack [lreplace $stack {*}[set stack ""] end end]

Of course, any

| foo $apa {#}[bar baz]

can trivially be rewritten to achieve the same effect using argument expansion
instead:

| foo $apa {*}[bar baz; list]

~~�Commenting out list elements

If a programmer needs to temporarily disable some functionality, then a
standard technique is to comment out the corresponding code. However, if the
code that needs to be commented out amounts to some elements in a long list
(e.g., a list of commands to [[interp expose]] in a slave interpreter) then
there is presently no way of commenting out less than the whole command
containing that list. Comment words provide a more specific alternative.

|   set tclCommands {
|       after append array binary break case catch cd clock close concat
|       continue dde else elseif encoding eof error eval exec exit expr
|       fblocked fcondict figure fcopy file fileevent flush for foreach 
|       format gets glob global history if incr info interp join lappend
|       lassign lindex linsert list llength load lrange lrepeat lreplace
|       lsearch lset lsort namespace open package pid proc puts pwd read
|       regexp regsub rename resource return scan seek set slave socket
|       source split string subst switch tell time trace unknown
|       unset update uplevel upvar variable vwait while
|       {#}{ {#}"Auto-loaded commands"
|       auto_execok auto_import auto_load auto_mkindex auto_mkindex_old
|       auto_qualify auto_reset parray pkg::create pkg_mkIndex tcl_endOfWord
|       tcl_findLibrary tcl_startOfNextWord tcl_startOfPreviousWord
|       tcl_wordBreakAfter tcl_wordBreakBefore
|       }
|   }



The same is true in dictionaries.

| namespace eval ::tcl::info {
|     namespace ensemble create -command ::info -map {
|        exists             ::tcl::info::exists 
|        globals            ::tcl::info::globals 
|        locals             ::tcl::info::locals 
|        vars               ::tcl::info::vars 
|        args               ::tcl::info::args 
|        body               ::tcl::info::body 
|        default            ::tcl::info::default 
|        commands           ::tcl::info::commands 
|        procs              ::tcl::info::procs 
|        functions          ::tcl::info::functions 
|        cmdcount           ::tcl::info::cmdcount 
|        complete           ::tcl::info::complete 
|        script             ::tcl::info::script 
|        level              ::tcl::info::level 
|        frame              ::tcl::info::frame 
|        errorstack         ::tcl::info::errorstack 
|        patchlevel         ::tcl::info::patchlevel 
|        tclversion         ::tcl::info::tclversion 
|        {#}{ {#}"Commented out for bug #nnnnnn."
|        hostname           ::tcl::info::hostname 
|        sharedlibextension ::tcl::info::sharedlibextension 
|        loaded             ::tcl::info::loaded 
|        library            ::tcl::info::library 
|        nameofexecutable   ::tcl::info::nameofexecutable 
|        }

|        coroutine          ::tcl::info::coroutine 
|        object             ::oo::InfoObject 
|        class              ::oo::InfoClass
|     }
| }



~~ Line continuation

Comment words also provide an alternative to backslash--newline line
continuations, namely as in

|  a command which continues well beyond the normal line width {#}{
|  } and which one therefore might want to split over two or more {#}{
|  } lines of code

Being several times longer than the simple backslash, this is unlikely to
replace it, but there could be cases where one wants to avoid the backslash
because that character would be intercepted by something else.

~ Alternatives

Using the author's '''docstrip''' package
[http://tcllib.sourceforge.net/doc/docstrip.html], one can place comments
between any two lines of code (whether there is a command separator there or
not) and also comment out arbitrary code lines, even if that comes at the
price of working with sources that are not raw Tcl code. However, such
comments have a tendency to become more of a separate commentary track than an
integrated part of the program narrative, and sometimes (for example to show
things that are invisible in the code) one specifically desires comments to be
an integral part of the Tcl code.

It is also possible to use '''regsub''' or something similar to the end of
removing comments from a block of code before it is evaluated or put in a
variable; instead of having the core language recognise some pieces of code as
comments, one preprocesses the code as a string before telling the core that
it actually is Tcl code (or a list/dict/etc.). Thus instead of (assuming 
comment words):

|   set tclCommands {
|       after append array binary break case catch cd clock close concat
|       continue dde else elseif encoding eof error eval exec exit expr
|       fblocked fcondict figure fcopy file fileevent flush for foreach 
|       format gets glob global history if incr info interp join lappend
|       lassign lindex linsert list llength load lrange lrepeat lreplace
|       lsearch lset lsort namespace open package pid proc puts pwd read
|       regexp regsub rename resource return scan seek set slave socket
|       source split string subst switch tell time trace unknown
|       unset update uplevel upvar variable vwait while
|       {#}{ {#}"Auto-loaded commands"
|       auto_execok auto_import auto_load auto_mkindex auto_mkindex_old
|       auto_qualify auto_reset parray pkg::create pkg_mkIndex tcl_endOfWord
|       tcl_findLibrary tcl_startOfNextWord tcl_startOfPreviousWord
|       tcl_wordBreakAfter tcl_wordBreakBefore
|       }
|   }



one might write

|   set tclCommands [regsub -all {#[^\n]*\n} {
|       after append array binary break case catch cd clock close concat
|       continue dde else elseif encoding eof error eval exec exit expr
|       fblocked fcondict figure fcopy file fileevent flush for foreach 
|       format gets glob global history if incr info interp join lappend
|       lassign lindex linsert list llength load lrange lrepeat lreplace
|       lsearch lset lsort namespace open package pid proc puts pwd read
|       regexp regsub rename resource return scan seek set slave socket
|       source split string subst switch tell time trace unknown
|       unset update uplevel upvar variable vwait while
|       ## Auto-loaded commands
|       # auto_execok auto_import auto_load auto_mkindex auto_mkindex_old
|       # auto_qualify auto_reset parray pkg::create pkg_mkIndex tcl_endOfWord
|       # tcl_findLibrary tcl_startOfNextWord tcl_startOfPreviousWord
|       # tcl_wordBreakAfter tcl_wordBreakBefore
|   } \n]

A problem with the latter is that it destroys code line correspondences for
[280]. The boilerplate code for performing the preprocessing may also need to
be inserted far from the actual comment, which discourages use of commenting
using such a mechanism. But the main problem with it is that quick fixes like
this have a tendency to be half-baked, and would break some otherwise legal
code. (Everything works fine in the example until the day someone needs to
insert an element which contains the # character into the list.)

Since the canonical list-quoting of '''#''' is precisely '''{#}''', one could
(in analogy with the argument against '''{}''' as expansion prefix) argue that
'''{#}something''' is too likely to arise as a typo for '''{#} something''',
which would suggest using some other character than '''#''' in the comment
prefix. '''\#''' is however a shorter way to list-quote '''#''', so it seems
unlikely that '''{#}''' should be common in manually written code (unlike
'''{}''', which is very common).

~~ Additional alternatives from tcl-core discussion

That (in script words) the initial substitution round performs variable 
and command substitution is by several seen as problematic. Only 
performing backslash substitution there is no great loss, as the only 
use-case above which relies on other substitutions is the K combinator one 
that anyway has several alternatives already, but it complicates the 
implementation by introducing a new parsing mode for scripts (grab word 
without variable or command substitution, but with backslash substitution). 
In particular, one would have to decide on the exact rules for this; it 
would probably be best to use the same rules as for command words in 
lists, which however implies that

| list {#}[foo bar]

would produce a list with one element, namely the string "bar]".

A different way of fitting comments into the 
brace-''something''-brace-''something'' syntax region would be to put the 
comment material in the first ''something'' rather than the second. This 
could take the form of comment words which begin with '''{#''' and end 
with '''}#''', as in

|  $canvas create polygon 0 0 {# left top }# 30 0 {#bend down}# 30 30 \
|    {# concave part}# 60 30 {#bend up }# 60 0 {# right top }# 90 0 \
|    {# curving back }# 90 30 45 67 0 30 {# done }# -smooth true \
|    -width 2 -fill orange -outline green {# Official colours }# \
|    -tags {button {# for clicking }# buoyant {#affects movement}#}

This is similar to Cloverfield's current '''#{''' and '''}#''' comment 
delimiters, and perhaps also reminicient of C's '''/*''' ... '''*/''' and 
Pascal's '''(*''' ... '''*)'''. It should however be stressed that the 
nesting here would still be that of braces rather than brace+hash 
combinations, so

|  {# a b { c }# d {# e f } g }#

would be one comment word, not two with a non-comment word '''d''' in 
between. Using this syntax could thus lead to false expectations about 
where a comment ends.

A technical disadvantage of '''{#''' and '''}#''' for comment word 
delimiters is that they make TclFindElement slightly more expensive than 
for the proposed '''{#}''' prefix. The reason is that TclFindElement needs 
to peek at the word after the element it finds to check if that is a 
comment (and if so scan past it and peek at the word after that too). If 
the comment status of a word can be determined from whether it carries a 
'''{#}''' prefix, then it is at worst necessary to peek at the first four 
characters, but if it matters how the word ends then it might be necessary 
to parse the whole of the next element in a list before being able to tell 
that it indeed was not a comment. From a usability point of view, this 
syntax lends less support for the argument placeholder use-case than the 
proposed prefix.

Donald G Porter has pointed out that this proposal has two functionally 
unrelated parts, which indeed are easy to discern in the reference 
implementation: comment words in lists and the like (changes in 
TclFindElement) and comment words in scripts (all other changes). It would 
be possible to propose implementing either one of these parts alone, and 
the one which is most interesting is then comment words in lists. (Given 
just that, one could even use

|   {*}{{#}"Comment goes here"}

as an ugly substitute for word comments in scripts.) However, I believe it 
is more natural to introduce both together.

~ Suggested Stylistic Considerations

Like ordinary words, comment words come in three varieties: brace-delimited,
quote-delimited, and barewords. A style rule which has been used in the above
examples is that:

 * Natural language comment words are of the quote-delimited kind.  This is
   for consistency with the common practice of quote-delimiting text strings
   within Tcl code, even if said string does not require substitution.

 * Comment words that serve as placeholders for actual program code are of the
   bareword variety, e.g. '''{#}method'''.

 * Comment words which serve a programmatic purpose, essentially that of the
   "K combinator", are barewords too.

 * Comment words which do not fall into any of the above categories, for
   example those used to comment of a block of words, are brace-delimited.

One reason for having a style rule about this is that prettyprinting and
syntax colouring utilities ''might'' want to highlight these cases
differently. Arguably, syntax colouring of Tcl code tends to do ''at least as
much harm'' as it does good since few engines are able to keep track of enough
context to found their claims about the code on reasonably accurate
interpretations thereof, but comment words is one of the few things that they
might actually manage to get right most of the time, precisely because a
comment word is a comment word throughout so many contexts.

~ Reference Implementation

A reference implementation is available as SF Tcl patch #3522426
[https://sourceforge.net/support/tracker.php?aid=3522426]. It includes some
tests, but more could be needed. DGP has also created a branch 
'''tip-401''' [http://core.tcl.tk/tcl/timeline?r=tip-401] for it in the 
core fossil respository; further development is best conducted in the 
latter.

Implementing comment words in lists and the like could be achieved by
modifications only in TclFindElement. Comment words in scripts are implemented
as argument expansion that does not contribute any word.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|
|


|

|
|
|


|
|



|


|

|



|
|












|





|



|



|
|
|

|







|
|



|

|


|
|


|



|


|

|


|

|


|



|

|
|
|

|


|




|
|
|


|

|

|


|
|



|
|
|
|
|
|
<
>
|
|
<
>
|
|
<
>
|
|
|
|
|
|
<
>
|
<
|
>
|





|
|
|
|
|





|





|
|
|
|
|
|
|
<
|
>
|
|

|


|
|


|

|
|
|
|
|


|
|





|
|
|
|
|
|
|
|
|
|

|

|
|

|


|
|
|


|



|
|
|



|




|

|




|



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
>
>



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
<
<
|
>
>
|




|
|
|





|

|
|
|
|


|
|


|



|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
>
>



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


|



|
|

|
|
|
|
|
|
|

|

|




|
|




|




|
|
|
|

|
|
|
|
|

|
|
|
|


|

|



|

|

|

|








|
|

|


|

|


|










|








|
|
|





|

|
|

|







|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

151
152
153

154
155
156

157
158
159
160
161
162
163

164
165

166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289


290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320

321
322
323
324


325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374


375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524

# TIP 401: Comment Words with Leading {#}

	Author:         Lars Hellström <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        29-Apr-2012
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

The basic syntax rules of Tcl \(the "dodekalogue"\) are modified to allow words
that are comments. In analogy with the argument expansion **\{\*\}**, such
comment words will begin with **\{\#\}** \(left brace, hash sign, right brace\).  
The change concerns both words in scripts and, more importantly, words in lists.

# Rationale

Tcl is special in that comments appear at the "statement" \(command\) level of
the language syntax rather than the "token" level \(as is the case in e.g. the
ALGOL language family: C, Pascal, Java, etc.\). This means a Tcl program has
fewer places in which a comment can be placed than many other languages, but
this has not been a serious problem in traditional Tcl programming as commands
tend to be short \(except when they have arguments that are themselves Tcl
scripts\) and places where a comment can be inserted thus frequent enough.
Recent developments in the language have however changed this.

Various new features -- particularly dictionaries, ensembles, and argument
expansion \(all of which were introduced with Tcl 8.5\) -- have encouraged a
coding style where occasionally fairly large blocks of code can be spent
setting up data structures as explicit values. For example, an ensemble that
relies on the **-map** option typically has the entire mapping dictionary as
a braced word in the code, and this can grow rather large if subcommands are
being mapped to command prefixes of length greater than one. **string map**
mappings can grow very large if there are many cases to deal with.
Dictionaries have greatly simplified the use of values with inner structure,
and as a result the complexity of the data that routinely gets passed to
package commands has increased; a controlling data structure \(e.g. a grammar,
in the case of a parser\) that once required an entire API of constructors to
build might now have been redesigned as a simple nested dictionary that can be
written raw in the code. And on top of it all, the various examples given
above are not excluding each other, but may rather nest to form even larger
blocks of code without any part that is a script. Adding a class of comments
that can begin anywhere a word can begin undoes the forced "comment desert"
status of such code blocks, because words are syntactic units not just in
commands but also in lists, and all of the structured explicit values
mentioned above are syntactically either plain lists or lists with additional
restrictions.

A parallel development is that the gap between what some piece of Tcl looks
like at coding time and at runtime has begun to widen, because an increasing
number of APIs call for fragments of commands \(particularly command prefixes\)
rather than full commands or scripts. This change is often good from a
correctness and efficiency point of view, but can make code harder to maintain
on account of being more obscure; the evocation of runtime calls resulting
from a particular piece of code sometimes requires a considerable effort of
imagination, even if all APIs involved are well documented. Comment words that
appear in the position\(s\) where additional material is inserted at runtime can
help the mind here, by letting the eyes see in the code those things that will
be there when it is evaluated, e.g. rather than

	  socket -server [list ::some::handler $settings] $port

one might write

	  socket -server [
	      list ::some::handler $settings {#}chan {#}client {#}clientport
	  ] $port

to emphasize the fact that this **::some::handler** command takes those four
things as arguments, even though only one of them is present in the command
prefix.

For command words to not change the interpretation of any presently legal
syntactic construction, they must be something which is not valid as a list
element word. The brace-something-brace-something syntax region where argument
expansion was given a home is pretty much the only possibility there is for
this \(if one rules out unbalanced words\), since there is very little that the
Tcl parser finds outright wrong. The **\#** character is the normal way of
starting a command-level comment, so it is natural that it occurs also in the
syntax of word-level comments.

# Specification

Clause 5 \(argument expansion\) of the Tcl.n manpage is to be amended with the
following conditions, and the language parser is to be modified accordingly.

 > If a word starts with the string "\{\#\}" followed by a non-whitespace
   character, then the leading "\{\#\}" is removed and the rest of the word is
   parsed and substituted as any other word. The result of this substitution
   is not used for anything, and no word is added to the command being
   substituted. For instance, "cmd a \{\#\}\{b c\} d \{\#\}e f" is equivalent to "cmd
   a d f".

Moreover, the analogous modification shall be made to the list parser; a word
with **\{\#\}** proper prefix is recognised as a comment also in a list, where
the initial substitution phase only performs backslash substitution.

_Note 1:_
The point of doing substitution is to stick as close to the behaviour of
**\{\*\}** as possible. Of the three steps involved in argument expansion -
parse and substitute word, reparse result without substitution as a list of
words, and append those words to command being built -- only the middle one
need to be different for **\{\#\}**, and thus a lot of the code can be shared.

_Note 2:_
The comment prefix is typically most useful with words like

	 cmd {#}{some [text]} {#}bareword {#}"Comment goes here"

but things like this are also legal:

	 cmd {#}$var {#}$x,\n {#}[foo bar]

_Note 3:_
It is _very_ important for serveral use-cases that comment words are
recognised as such also in lists. One might \(as I would\) argue that this
should really follow automatically, since outside the source itself the only
\(and not very explicit\) documentation of the string representation of lists is
found in the lindex.n manpage which merely says that:

 > In extracting the element, **lindex** observes the same rules concerning
   braces and quotes and backslashes as the Tcl command interpreter; however,
   variable substitution and command substitution do not occur.

As only variable and command substitution are mentioned as things which differ
between lists and commands, they therefore must treat **\{\#\}** the same.
However, presently the argument expansion **\{\*\}** is not recognised in
lists, despite there not being a stated exception for that either. \(This state
of affairs is reasonable, since it would be very complicated to extend present
mechanisms to support argument expansion in lists and the benefit of doing so
is slim at best, but it should be more clearly documented.\)

# Use Cases

## More comments in switch

Beginning with an old issue, one may consider the placement of comments to
**switch** cases. The current advice is to place them first in the bodies
\(which of course works\), but it can often be exposition-wise more natural to
place them before the pattern, especially if there is not a 1-1 correspondence
between comments and bodies.

	  switch -regexp [string trimleft $number +-] {
	 
	      {#}"Integer formats"
	      {^0$} - 
	      {^[1-9][0-9]*$} {
	           # ...

	      }
	      {^0o[0-7]+$} {
	           # ...

	      }
	      {^0x[0-9A-Fa-f]+$} {
	           # ...

	      }
	      
	      {#}"Float formats"
	      {^[0-9]*\.[0-9]+(e[+-][0-9]+)$} -
	      {^[0-9]+\.[0-9]*(e[+-][0-9]+)$} -
	      {^[0-9]+e[+-][0-9]+$}  {
	           # ...

	      }
	      

	  }

## Inline comments in long commands

Some commands can be very long simply because they require a lot of arguments
to express what one wants, and then comments can help clarify what a
particular argument contributes to.

	  $canvas create polygon 0 0 {#}"left top" 30 0 {#}"bend down" 30 30 \
	    {#}"concave part" 60 30 {#}"bend up" 60 0 {#}"right top" 90 0 \
	    {#}"curving back" 90 30 45 67 0 30 {#}"done" -smooth true \
	    -width 2 -fill orange -outline green {#}"Official colours" \
	    -tags {button {#}"for clicking" buoyant {#}"affects movement"}

If there are several ideas in such a command, it might be nice to put the
comments pertaining to each next to where that idea actually shows up in the
code.

## Inline argument descriptions

The Tcl style guide for C code suggests that comments describing function
arguments appear inline with the argument declarations. Comment words would
permit the same style in Tcl code.

	 proc tcl::Pkg::CompareExtension {
	    fileName      {#}"name of a file whose extension is compared"
	    {ext {}}      {#}"The extension to compare against; you must
	                      provide the starting dot. Defaults to the 
	                      info sharedlibextension."
	 } {
	    # ...

	 }

\(Whether that style would be regarded as an improvement or not probably
depends on one's taste.\)

## Filling in words that will be there at runtime

At one point, I found myself wanting to do some calculations with matrices
whose elements were polynomials \(with integer coefficients\) of four
noncommuting variables _A_, _B_, _C_, and _D_. Having previously
implemented some basic algebraic constructions, I could quickly set up a
command that implemented arithmetic with such matrices through the two
**interp alias**es

	 interp alias {} Z<A,B,C,D> {} \
	   ::mtmtcl::rings::semigroup_algebra ::mtmtcl::rings::integers::all\
	     ::mtmtcl::groups::string_free_monoid
	 interp alias {} matrices {} \
	   ::mtmtcl::matprop::trivial dummy ::Z<A,B,C,D>

This is however not a very readable definition even if one is familiar with
the commands it uses \(and realises that there is nothing magical about the
command name **Z<A,B,C,D>**\), because the way that things appear in this
piece of code is visually quite different from the context in which they will
appear when evaluated. If instead comment words are inserted as visual
placeholders for the missing material, then the overall appearance becomes
much closer to that of a script calling these commands.

	 interp alias {} Z<A,B,C,D> {#}method {#}args {} \
	   ::mtmtcl::rings::semigroup_algebra {
	      ::mtmtcl::rings::integers::all {#}method {#}args
	   } {
	      ::mtmtcl::groups::string_free_monoid {#}method {#}args
	   } {#}method {#}args
	 interp alias {} matrices {#}method {#}args {} \
	   ::mtmtcl::matprop::trivial dummy {
	      ::Z<A,B,C,D> {#}method {#}args
	   } {#}method {#}args

## "K combinator"

In the Tcl community, the _K combinator_ idiom is when you first produce an
argument for the main command \(through variable or command substitution\), then
evaluate some other command which has beneficial side-effects but whose result
is of no interest, and finally evaluate the main command.  \(The original K
combinator, as found combinatory logic, is more about getting rid of unwanted
arguments supplied to a command prefix than about exploiting side-effects, but
there is a continuum connecting the two.\)  This is most often employed to have
a variable release its reference to a Tcl\_Obj, so that the latter becomes
unshared and possible for a command to modify directly. **\{\#\}** introduces
the new form

	 set stack [lreplace $stack {#}[set stack whatever] end end]

of this, providing yet another alternative to such old forms as

	 set stack [lreplace $stack [set stack end] end]
	 set stack [lreplace $stack[set stack ""] end end]
	 set stack [lreplace $stack {*}[set stack ""] end end]

Of course, any

	 foo $apa {#}[bar baz]

can trivially be rewritten to achieve the same effect using argument expansion
instead:

	 foo $apa {*}[bar baz; list]

## Commenting out list elements

If a programmer needs to temporarily disable some functionality, then a
standard technique is to comment out the corresponding code. However, if the
code that needs to be commented out amounts to some elements in a long list
\(e.g., a list of commands to [interp expose] in a slave interpreter\) then
there is presently no way of commenting out less than the whole command
containing that list. Comment words provide a more specific alternative.

	   set tclCommands {
	       after append array binary break case catch cd clock close concat
	       continue dde else elseif encoding eof error eval exec exit expr
	       fblocked fcondict figure fcopy file fileevent flush for foreach 
	       format gets glob global history if incr info interp join lappend
	       lassign lindex linsert list llength load lrange lrepeat lreplace
	       lsearch lset lsort namespace open package pid proc puts pwd read
	       regexp regsub rename resource return scan seek set slave socket
	       source split string subst switch tell time trace unknown
	       unset update uplevel upvar variable vwait while
	       {#}{ {#}"Auto-loaded commands"
	       auto_execok auto_import auto_load auto_mkindex auto_mkindex_old
	       auto_qualify auto_reset parray pkg::create pkg_mkIndex tcl_endOfWord
	       tcl_findLibrary tcl_startOfNextWord tcl_startOfPreviousWord
	       tcl_wordBreakAfter tcl_wordBreakBefore


	       }
	   }

The same is true in dictionaries.

	 namespace eval ::tcl::info {
	     namespace ensemble create -command ::info -map {
	        exists             ::tcl::info::exists 
	        globals            ::tcl::info::globals 
	        locals             ::tcl::info::locals 
	        vars               ::tcl::info::vars 
	        args               ::tcl::info::args 
	        body               ::tcl::info::body 
	        default            ::tcl::info::default 
	        commands           ::tcl::info::commands 
	        procs              ::tcl::info::procs 
	        functions          ::tcl::info::functions 
	        cmdcount           ::tcl::info::cmdcount 
	        complete           ::tcl::info::complete 
	        script             ::tcl::info::script 
	        level              ::tcl::info::level 
	        frame              ::tcl::info::frame 
	        errorstack         ::tcl::info::errorstack 
	        patchlevel         ::tcl::info::patchlevel 
	        tclversion         ::tcl::info::tclversion 
	        {#}{ {#}"Commented out for bug #nnnnnn."
	        hostname           ::tcl::info::hostname 
	        sharedlibextension ::tcl::info::sharedlibextension 
	        loaded             ::tcl::info::loaded 
	        library            ::tcl::info::library 
	        nameofexecutable   ::tcl::info::nameofexecutable 

	        }
	        coroutine          ::tcl::info::coroutine 
	        object             ::oo::InfoObject 
	        class              ::oo::InfoClass


	     }
	 }

## Line continuation

Comment words also provide an alternative to backslash--newline line
continuations, namely as in

	  a command which continues well beyond the normal line width {#}{
	  } and which one therefore might want to split over two or more {#}{
	  } lines of code

Being several times longer than the simple backslash, this is unlikely to
replace it, but there could be cases where one wants to avoid the backslash
because that character would be intercepted by something else.

# Alternatives

Using the author's **docstrip** package
<http://tcllib.sourceforge.net/doc/docstrip.html> , one can place comments
between any two lines of code \(whether there is a command separator there or
not\) and also comment out arbitrary code lines, even if that comes at the
price of working with sources that are not raw Tcl code. However, such
comments have a tendency to become more of a separate commentary track than an
integrated part of the program narrative, and sometimes \(for example to show
things that are invisible in the code\) one specifically desires comments to be
an integral part of the Tcl code.

It is also possible to use **regsub** or something similar to the end of
removing comments from a block of code before it is evaluated or put in a
variable; instead of having the core language recognise some pieces of code as
comments, one preprocesses the code as a string before telling the core that
it actually is Tcl code \(or a list/dict/etc.\). Thus instead of \(assuming 
comment words\):

	   set tclCommands {
	       after append array binary break case catch cd clock close concat
	       continue dde else elseif encoding eof error eval exec exit expr
	       fblocked fcondict figure fcopy file fileevent flush for foreach 
	       format gets glob global history if incr info interp join lappend
	       lassign lindex linsert list llength load lrange lrepeat lreplace
	       lsearch lset lsort namespace open package pid proc puts pwd read
	       regexp regsub rename resource return scan seek set slave socket
	       source split string subst switch tell time trace unknown
	       unset update uplevel upvar variable vwait while
	       {#}{ {#}"Auto-loaded commands"
	       auto_execok auto_import auto_load auto_mkindex auto_mkindex_old
	       auto_qualify auto_reset parray pkg::create pkg_mkIndex tcl_endOfWord
	       tcl_findLibrary tcl_startOfNextWord tcl_startOfPreviousWord
	       tcl_wordBreakAfter tcl_wordBreakBefore


	       }
	   }

one might write

	   set tclCommands [regsub -all {#[^\n]*\n} {
	       after append array binary break case catch cd clock close concat
	       continue dde else elseif encoding eof error eval exec exit expr
	       fblocked fcondict figure fcopy file fileevent flush for foreach 
	       format gets glob global history if incr info interp join lappend
	       lassign lindex linsert list llength load lrange lrepeat lreplace
	       lsearch lset lsort namespace open package pid proc puts pwd read
	       regexp regsub rename resource return scan seek set slave socket
	       source split string subst switch tell time trace unknown
	       unset update uplevel upvar variable vwait while
	       ## Auto-loaded commands
	       # auto_execok auto_import auto_load auto_mkindex auto_mkindex_old
	       # auto_qualify auto_reset parray pkg::create pkg_mkIndex tcl_endOfWord
	       # tcl_findLibrary tcl_startOfNextWord tcl_startOfPreviousWord
	       # tcl_wordBreakAfter tcl_wordBreakBefore
	   } \n]

A problem with the latter is that it destroys code line correspondences for
[[280]](280.md). The boilerplate code for performing the preprocessing may also need to
be inserted far from the actual comment, which discourages use of commenting
using such a mechanism. But the main problem with it is that quick fixes like
this have a tendency to be half-baked, and would break some otherwise legal
code. \(Everything works fine in the example until the day someone needs to
insert an element which contains the \# character into the list.\)

Since the canonical list-quoting of **\#** is precisely **\{\#\}**, one could
\(in analogy with the argument against **\{\}** as expansion prefix\) argue that
**\{\#\}something** is too likely to arise as a typo for **\{\#\} something**,
which would suggest using some other character than **\#** in the comment
prefix. **\\\#** is however a shorter way to list-quote **\#**, so it seems
unlikely that **\{\#\}** should be common in manually written code \(unlike
**\{\}**, which is very common\).

## Additional alternatives from tcl-core discussion

That \(in script words\) the initial substitution round performs variable 
and command substitution is by several seen as problematic. Only 
performing backslash substitution there is no great loss, as the only 
use-case above which relies on other substitutions is the K combinator one 
that anyway has several alternatives already, but it complicates the 
implementation by introducing a new parsing mode for scripts \(grab word 
without variable or command substitution, but with backslash substitution\). 
In particular, one would have to decide on the exact rules for this; it 
would probably be best to use the same rules as for command words in 
lists, which however implies that

	 list {#}[foo bar]

would produce a list with one element, namely the string "bar]".

A different way of fitting comments into the 
brace-_something_-brace-_something_ syntax region would be to put the 
comment material in the first _something_ rather than the second. This 
could take the form of comment words which begin with **\{\#** and end 
with **\}\#**, as in

	  $canvas create polygon 0 0 {# left top }# 30 0 {#bend down}# 30 30 \
	    {# concave part}# 60 30 {#bend up }# 60 0 {# right top }# 90 0 \
	    {# curving back }# 90 30 45 67 0 30 {# done }# -smooth true \
	    -width 2 -fill orange -outline green {# Official colours }# \
	    -tags {button {# for clicking }# buoyant {#affects movement}#}

This is similar to Cloverfield's current **\#\{** and **\}\#** comment 
delimiters, and perhaps also reminicient of C's **/\*** ... **\*/** and 
Pascal's **\(\*** ... **\*\)**. It should however be stressed that the 
nesting here would still be that of braces rather than brace\+hash 
combinations, so

	  {# a b { c }# d {# e f } g }#

would be one comment word, not two with a non-comment word **d** in 
between. Using this syntax could thus lead to false expectations about 
where a comment ends.

A technical disadvantage of **\{\#** and **\}\#** for comment word 
delimiters is that they make TclFindElement slightly more expensive than 
for the proposed **\{\#\}** prefix. The reason is that TclFindElement needs 
to peek at the word after the element it finds to check if that is a 
comment \(and if so scan past it and peek at the word after that too\). If 
the comment status of a word can be determined from whether it carries a 
**\{\#\}** prefix, then it is at worst necessary to peek at the first four 
characters, but if it matters how the word ends then it might be necessary 
to parse the whole of the next element in a list before being able to tell 
that it indeed was not a comment. From a usability point of view, this 
syntax lends less support for the argument placeholder use-case than the 
proposed prefix.

Donald G Porter has pointed out that this proposal has two functionally 
unrelated parts, which indeed are easy to discern in the reference 
implementation: comment words in lists and the like \(changes in 
TclFindElement\) and comment words in scripts \(all other changes\). It would 
be possible to propose implementing either one of these parts alone, and 
the one which is most interesting is then comment words in lists. \(Given 
just that, one could even use

	   {*}{{#}"Comment goes here"}

as an ugly substitute for word comments in scripts.\) However, I believe it 
is more natural to introduce both together.

# Suggested Stylistic Considerations

Like ordinary words, comment words come in three varieties: brace-delimited,
quote-delimited, and barewords. A style rule which has been used in the above
examples is that:

 * Natural language comment words are of the quote-delimited kind.  This is
   for consistency with the common practice of quote-delimiting text strings
   within Tcl code, even if said string does not require substitution.

 * Comment words that serve as placeholders for actual program code are of the
   bareword variety, e.g. **\{\#\}method**.

 * Comment words which serve a programmatic purpose, essentially that of the
   "K combinator", are barewords too.

 * Comment words which do not fall into any of the above categories, for
   example those used to comment of a block of words, are brace-delimited.

One reason for having a style rule about this is that prettyprinting and
syntax colouring utilities _might_ want to highlight these cases
differently. Arguably, syntax colouring of Tcl code tends to do _at least as
much harm_ as it does good since few engines are able to keep track of enough
context to found their claims about the code on reasonably accurate
interpretations thereof, but comment words is one of the few things that they
might actually manage to get right most of the time, precisely because a
comment word is a comment word throughout so many contexts.

# Reference Implementation

A reference implementation is available as SF Tcl patch \#3522426
<https://sourceforge.net/support/tracker.php?aid=3522426> . It includes some
tests, but more could be needed. DGP has also created a branch 
**tip-401** <http://core.tcl.tk/tcl/timeline?r=tip-401>  for it in the 
core fossil respository; further development is best conducted in the 
latter.

Implementing comment words in lists and the like could be achieved by
modifications only in TclFindElement. Comment words in scripts are implemented
as argument expansion that does not contribute any word.

# Copyright

This document has been placed in the public domain.

Name change from tip/402.tip to tip/402.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

TIP:            402
Title:          General Platform UNC Support
Version:        $Revision: 1.2 $
Author:         Jan Nijtmans <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        16-Jul-2011
Post-History:   
Discussions-To: Tcl Core list
Keywords:       Tcl
Tcl-Version:    8.7


~ Abstract

Both Windows and Cygwin interpret paths starting with '''//''' as a special
prefix, indicating that the path has the form: '''//server/share/file_path'''.
Windows has built-in handling of such paths built-in. UNIX doesn't have this.
It could be implemented through a VFS extension, but there is one problem:
File normalization on UNIX collapes multiple slashes into a single slash, so
this would convert the UNC path into a normal path. This makes it impossible
to implement a VFS extension which uses '''//''' as prefix, implementing
connection to a Samba server using the UNC path format.

~ Rationale

At the moment, Cygwin and Windows have built-in a special case that paths
starting with double-slash will not be collapsed into a single slash. UNIX
does not do that. This change will allow a single uniform format for accessing
(Samba) shares on external machines using the path format
'''//server/share/file_path'''. On Windows and Cygwin this already works,
because it is built-in Windows functionality.  On UNIX a VFS extension could
be developed which does the same.

~ Specification

This document proposes:

 * Extend the special case built-in for Windows and Cygwin to UNIX, so paths
   starting with double-slash will no longer normalize to paths starting with
   a single slash.

 > '''POTENTIAL INCOMPATIBILITY'''

 * As '''//''' becomes a special prefix, the '''file split''' will return
   '''//''' as its first list element when the original path starts with a
   double slash.

~ Compatibility

On UNIX, this means that paths like '''//usr/bin/tclsh''' might no longer do
what it did earlier, if a VFS exists which uses '''//''' as path prefix. If no
such VFS exists, it will probably still work, only comparing normalized paths
will no longer regard '''//<foo>''' as equal to '''/<foo>'''.

Handling of multiple slashes in other locations of the string will not
change. So normalizing '''/foo//bar''' will still give '''/foo/bar'''.  The
most likely cause of multiple slashes appearing in a path is because of
appending a file name to a path which already ends with a slash, e.g.

|set dir "somedir/"
|set path $dir/filename

Of course, the '''file join''' command does not have this danger:

|set dir "somedir/"
|set path [file join $dir filename]

On Windows and Cygwin, there is no change in behavior at all.

~ Alternatives

Variations are possible in the handling of paths starting with 3 or more
slashes. The current TIP implementation collapes more than 2 slashes to
exactly 2 slashes, as the current Windows and Cygwin implementations do.

~ Reference Implementation

A reference implementation is available at http://core.tcl.tk/tcl in branch
''jn-unc-vfs''.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|
|




|


|




|
|



|







|

|
|


|

|
|

|


|



|
|

|

|
|



|





|

|
|

|


>

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

# TIP 402: General Platform UNC Support

	Author:         Jan Nijtmans <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        16-Jul-2011
	Post-History:   
	Discussions-To: Tcl Core list
	Keywords:       Tcl
	Tcl-Version:    8.7
-----

# Abstract

Both Windows and Cygwin interpret paths starting with **//** as a special
prefix, indicating that the path has the form: **//server/share/file\_path**.
Windows has built-in handling of such paths built-in. UNIX doesn't have this.
It could be implemented through a VFS extension, but there is one problem:
File normalization on UNIX collapes multiple slashes into a single slash, so
this would convert the UNC path into a normal path. This makes it impossible
to implement a VFS extension which uses **//** as prefix, implementing
connection to a Samba server using the UNC path format.

# Rationale

At the moment, Cygwin and Windows have built-in a special case that paths
starting with double-slash will not be collapsed into a single slash. UNIX
does not do that. This change will allow a single uniform format for accessing
\(Samba\) shares on external machines using the path format
**//server/share/file\_path**. On Windows and Cygwin this already works,
because it is built-in Windows functionality.  On UNIX a VFS extension could
be developed which does the same.

# Specification

This document proposes:

 * Extend the special case built-in for Windows and Cygwin to UNIX, so paths
   starting with double-slash will no longer normalize to paths starting with
   a single slash.

	 > **POTENTIAL INCOMPATIBILITY**

 * As **//** becomes a special prefix, the **file split** will return
   **//** as its first list element when the original path starts with a
   double slash.

# Compatibility

On UNIX, this means that paths like **//usr/bin/tclsh** might no longer do
what it did earlier, if a VFS exists which uses **//** as path prefix. If no
such VFS exists, it will probably still work, only comparing normalized paths
will no longer regard **//<foo>** as equal to **/<foo>**.

Handling of multiple slashes in other locations of the string will not
change. So normalizing **/foo//bar** will still give **/foo/bar**.  The
most likely cause of multiple slashes appearing in a path is because of
appending a file name to a path which already ends with a slash, e.g.

	set dir "somedir/"
	set path $dir/filename

Of course, the **file join** command does not have this danger:

	set dir "somedir/"
	set path [file join $dir filename]

On Windows and Cygwin, there is no change in behavior at all.

# Alternatives

Variations are possible in the handling of paths starting with 3 or more
slashes. The current TIP implementation collapes more than 2 slashes to
exactly 2 slashes, as the current Windows and Cygwin implementations do.

# Reference Implementation

A reference implementation is available at <http://core.tcl.tk/tcl> in branch
_jn-unc-vfs_.

# Copyright

This document has been placed in the public domain.

Name change from tip/403.tip to tip/403.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

TIP:            403
Title:          Web Colors for Tk
Version:        $Revision: 1.3 $
Author:         Jan Nijtmans <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        17-Jul-2011
Post-History:   
Discussions-To: Tcl Core list
Keywords:       Tk
Tcl-Version:    8.6


~ Abstract

This TIP proposes some modifications in the RGB values of various colors as
used in Tk, bringing those colors more in line with various W3C standards.

~ Rationale

There is a difference between the color definitions in X11 and the color
definitions in Web standards like html and css. For example HTML4 defines the
basic color names '''aqua''', '''fuchsia''', '''lime''', '''olive''',
'''silver''' and '''teal''', which are currently not known to Tk. Making
things worse, some colors like '''green''' and '''gray''' have a different RGB
value in X11 compared to the html4 specification. See:
http://www.w3.org/TR/css3-color/#html4

~ Specification

This document proposes:

 * Add the colors '''aqua''', '''crimson''', '''fuchsia''', '''indigo''',
   '''lime''', '''olive''', '''silver''' and '''teal''' to the list of
   recognised colors, both for win32 and X11. For X11 it will be built in the
   wrapper function ''TkParseColor'', which is a thin wrapper around
   ''XParseColor''. The RGB values used are those from the above mentioned
   html4 specification (6 from the basic colors, 2 from the extended colors).
 
 * Modify the RGB values of '''gray/grey''', '''green''', '''maroon''' and
   '''purple''' matching the html4 specification. Those 4 colors are the only
   ones that differ in X11. Applications using those colors will change in
   visible appearance.

 > '''POTENTIAL INCOMPATIBILITY'''

~ Compatibility

On the script level nothing changes, only applications one or more colors from
the list '''gray''', '''grey''', '''green''', '''maroon''' and '''purple'''
will change in visible appearance. A side-by-side visible difference between
those 4 colors can be seen at:
http://en.wikipedia.org/wiki/X11_color_names#Color_name_clashes

~ Alternatives

None

~ Reference Implementation

A reference implementation is available at http://core.tcl.tk/tk in branch
''jn-web-colors''. It contains a test-case ''color-1.5'', which checkes the
RGB values of all known X11 colors with the above modifications. This test is
marked ''nonPortable'', simply because I don't know how many older X11 color
lists are still in use. On win32, mac and any reasonable recent X11 package,
this test passes.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|




|



|
|
|

|

|



|
|

|
|
|

|
|



|

|


|


|

|



|

|
|

|



|


>

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

# TIP 403: Web Colors for Tk

	Author:         Jan Nijtmans <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        17-Jul-2011
	Post-History:   
	Discussions-To: Tcl Core list
	Keywords:       Tk
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes some modifications in the RGB values of various colors as
used in Tk, bringing those colors more in line with various W3C standards.

# Rationale

There is a difference between the color definitions in X11 and the color
definitions in Web standards like html and css. For example HTML4 defines the
basic color names **aqua**, **fuchsia**, **lime**, **olive**,
**silver** and **teal**, which are currently not known to Tk. Making
things worse, some colors like **green** and **gray** have a different RGB
value in X11 compared to the html4 specification. See:
<http://www.w3.org/TR/css3-color/\#html4>

# Specification

This document proposes:

 * Add the colors **aqua**, **crimson**, **fuchsia**, **indigo**,
   **lime**, **olive**, **silver** and **teal** to the list of
   recognised colors, both for win32 and X11. For X11 it will be built in the
   wrapper function _TkParseColor_, which is a thin wrapper around
   _XParseColor_. The RGB values used are those from the above mentioned
   html4 specification \(6 from the basic colors, 2 from the extended colors\).
 
 * Modify the RGB values of **gray/grey**, **green**, **maroon** and
   **purple** matching the html4 specification. Those 4 colors are the only
   ones that differ in X11. Applications using those colors will change in
   visible appearance.

	 > **POTENTIAL INCOMPATIBILITY**

# Compatibility

On the script level nothing changes, only applications one or more colors from
the list **gray**, **grey**, **green**, **maroon** and **purple**
will change in visible appearance. A side-by-side visible difference between
those 4 colors can be seen at:
<http://en.wikipedia.org/wiki/X11\_color\_names\#Color\_name\_clashes>

# Alternatives

None

# Reference Implementation

A reference implementation is available at <http://core.tcl.tk/tk> in branch
_jn-web-colors_. It contains a test-case _color-1.5_, which checkes the
RGB values of all known X11 colors with the above modifications. This test is
marked _nonPortable_, simply because I don't know how many older X11 color
lists are still in use. On win32, mac and any reasonable recent X11 package,
this test passes.

# Copyright

This document has been placed in the public domain.

Name change from tip/404.tip to tip/404.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

TIP:            404
Title:          Let Message Catalogs get the Locale from their File Name
Version:        $Revision: 1.9 $
Author:         Harald Oehlmann <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        17-Jul-2011
Post-History:   
Discussions-To: Tcl Core list
Keywords:       msgcat, convention
Tcl-Version:    8.6


~ Abstract

This TIP proposes a mechanism for coupling locales more strongly to the names
of the files that define them, an already-recommended practice, so as to make
it less error-prone to produce message catalogs.

~ Rationale

Current message catalog files are as follows:

 * Catalog file
   name: ''<locale>'' '''.msg'''

 * Catalog
   folder: technically any, recommended: msgs in package main folder. Must be
   specified to the command '''mcload'''.

 * Catalog file
   contents: one command per translated item:

|        msgcat::mcset locale ori ?translation?

Example with <locale> equal "de":

|-de.msg-
|::msgcat::mcset de Open �ffnen
|::msgcat::mcset de Close Schliessen
|-eof-

The same locale value (de) is contained in the file name and in each
'''mcset''' command.

This is technically unnecessary and error-prone.  I found myself often copying
message file contents from one language to the next and not setting the right
locale in each '''mcset''' command.

The scope of this TIP is a new command similar to '''mcset''' which determines
the locale from the file name.

IMHO it makes no sense to specify the locale of '''mcset''' commands and the
locale in the file name different and thus separately.

~ Specification

~~ mc file locale

The '''mc file locale''' is a locale specified by the file name of a message
file.

Example:

 > Message catalogue
   file name: '''de_ch.msg'''

 > mc
   file locale: de_ch

The package '''msgcat''' maintains one value, '''mc file locale''', with the
following properties:

 * Its initial value is "" (the root locale).

 * Before a message catalog file is sourced by the procedure
   '''::msgcat::mcload''', the '''mc file locale''' is extracted from the
   message file name and stored as the current value.

 * The '''mc file locale''' may be querried by the command
   '''::msgcat::mcconfig -mcfilelocale'''.

 * The '''mc file locale''' may also be set by the command
   '''::msgcat::mcconfig -mcfilelocale value'''.

 * The original message filename may ''not'' be reconstructed
   by: '''[::msgcat::mcconfig -mcfilelocale].msg'''; there can be case
   differences.

The command '''::msgcat::mcconfig''' is shared with [399].  It has a new
option '''-mcfilelocale'''.

~~ New Commands

There are two new commands:

 * '''::msgcat::mcflset''' ''source'' ?''translation''?

 * '''::msgcat::mcflmset''' ''list''

These work as:

|   ::msgcat::mcset [::msgcat::mcconfig -mcfilelocale] source ?translation?
|   ::msgcat::mcmset [::msgcat::mcconfig -mcfilelocale] list

The command name '''mcflset''' is an abreviation of: "'''m'''essage
'''c'atalogue with '''f'''ile '''l'''ocale '''set'''".

~ Example Usages

The example of the Rationale section above may now be written as:

|-de.msg-
|::msgcat::mcflset Open �ffnen
|::msgcat::mcflset Close Schliessen
|-eof-

The locale value '''de''' only appears in the file name.

Further examples are in the tcl wiki msgcat page: [http://wiki.tcl.tk/msgcat]

~ Reference Implementation

See Tcl Feature Request 3544988.
[http://sourceforge.net/support/tracker.php/?aid=3544988]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|





|




|



|




|



|
|
|
|

|
|



|

|


|


|

|

|





|


|

|


|


|


|
|

|
|

|
|


|
|

|



|

|



|
|

|
|

|



|
|
|
|

|

|

|


|

|


>

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

# TIP 404: Let Message Catalogs get the Locale from their File Name

	Author:         Harald Oehlmann <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        17-Jul-2011
	Post-History:   
	Discussions-To: Tcl Core list
	Keywords:       msgcat, convention
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes a mechanism for coupling locales more strongly to the names
of the files that define them, an already-recommended practice, so as to make
it less error-prone to produce message catalogs.

# Rationale

Current message catalog files are as follows:

 * Catalog file
   name: _<locale>_ **.msg**

 * Catalog
   folder: technically any, recommended: msgs in package main folder. Must be
   specified to the command **mcload**.

 * Catalog file
   contents: one command per translated item:

		        msgcat::mcset locale ori ?translation?

Example with <locale> equal "de":

	-de.msg-
	::msgcat::mcset de Open Öffnen
	::msgcat::mcset de Close Schliessen
	-eof-

The same locale value \(de\) is contained in the file name and in each
**mcset** command.

This is technically unnecessary and error-prone.  I found myself often copying
message file contents from one language to the next and not setting the right
locale in each **mcset** command.

The scope of this TIP is a new command similar to **mcset** which determines
the locale from the file name.

IMHO it makes no sense to specify the locale of **mcset** commands and the
locale in the file name different and thus separately.

# Specification

## mc file locale

The **mc file locale** is a locale specified by the file name of a message
file.

Example:

 > Message catalogue
   file name: **de\_ch.msg**

 > mc
   file locale: de\_ch

The package **msgcat** maintains one value, **mc file locale**, with the
following properties:

 * Its initial value is "" \(the root locale\).

 * Before a message catalog file is sourced by the procedure
   **::msgcat::mcload**, the **mc file locale** is extracted from the
   message file name and stored as the current value.

 * The **mc file locale** may be querried by the command
   **::msgcat::mcconfig -mcfilelocale**.

 * The **mc file locale** may also be set by the command
   **::msgcat::mcconfig -mcfilelocale value**.

 * The original message filename may _not_ be reconstructed
   by: **[::msgcat::mcconfig -mcfilelocale].msg**; there can be case
   differences.

The command **::msgcat::mcconfig** is shared with [[399]](399.md).  It has a new
option **-mcfilelocale**.

## New Commands

There are two new commands:

 * **::msgcat::mcflset** _source_ ?_translation_?

 * **::msgcat::mcflmset** _list_

These work as:

	   ::msgcat::mcset [::msgcat::mcconfig -mcfilelocale] source ?translation?
	   ::msgcat::mcmset [::msgcat::mcconfig -mcfilelocale] list

The command name **mcflset** is an abreviation of: "**m**essage
**c'atalogue with **f**ile **l**ocale **set**".

# Example Usages

The example of the Rationale section above may now be written as:

	-de.msg-
	::msgcat::mcflset Open Öffnen
	::msgcat::mcflset Close Schliessen
	-eof-

The locale value **de** only appears in the file name.

Further examples are in the tcl wiki msgcat page: <http://wiki.tcl.tk/msgcat> 

# Reference Implementation

See Tcl Feature Request 3544988.
<http://sourceforge.net/support/tracker.php/?aid=3544988> 

# Copyright

This document has been placed in the public domain.

Name change from tip/405.tip to tip/405.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

TIP:            405
Title:          Add Collecting Loops, the 'lmap' and 'dict map' Commands
Version:        $Revision: 1.10 $
Author:         Trevor Davel <[email protected]>
Author:		Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        31-Jul-2012
Post-History:   
Keywords:       Tcl,mapeach,loop,accumulator
Tcl-Version:    8.6


~ Abstract

The '''lmap''' command is a collecting loop with the semantics of
'''foreach'''.  When the loop begins an accumulator is set to an empty list.
In any iteration where the body of the loop completes normally, the result of
the body is appended to the accumulator list.  The return value for '''lmap'''
is the contents of the accumulator.  The '''dict map''' command is an
equivalent collecting loop with the semantics based off '''dict for'''.

~ Rationale

'''lmap''' arises from a Tcler's Wiki discussion on higher order functions
[http://wiki.tcl.tk/26013].  The construct combines the capabilities of the
higher order functions ''map'' and ''filter'' with the familiarity and
expressive power of Tcl's '''foreach'''.

While '''lmap''' can be implemented in pure Tcl using '''uplevel''' (see the
Wiki for examples), substantial performance gains are possible with a bytecode
implementation.

'''dict map''' was suggested by DKF on tcl-core (2012-08-01) as native
dictionary iteration is more efficient that a '''lmap''' with two variables).

~ Proposed Changes

A new command '''lmap''' will be created, with arguments are intentionally
very similar to those to '''foreach''':

 > '''lmap''' ''varname list body''

 > '''lmap''' ''varlist1 list1'' ?''varlist2 list2 ...''? ''body''

The '''dict''' ensemble will be extended with a new sub-command '''map''':

 > '''dict map''' {''keyVar valueVar''} ''dictionary script''

~~ The "lmap" Command

The '''lmap''' command implements a loop where the loop variable(s) take on
values from one or more lists, and the loop returns a list of results
collected from each iteration.

In the simplest case there is one loop variable, ''varname'', and one list,
''list'', that is a list of values to assign to ''varname''. The ''body''
argument is a Tcl script. For each element of list (in order from first to
last), '''lmap''' assigns the contents of the element to ''varname'' as if
the '''lindex''' command had been used to extract the element, then calls the
Tcl interpreter to execute body.  If execution of the body completes normally
then the result of the body is appended to an accumulator list.  '''lmap'''
returns the accumulator list.

In the general case there can be more than one value list (e.g., ''list1'' and
''list2''), and each value list can be associated with a list of loop
variables (e.g., ''varlist1'' and ''varlist2''). During each iteration of the
loop the variables of each varlist are assigned consecutive values from the
corresponding list. Values in each list are used in order from first to last,
and each value is used exactly once. The total number of loop iterations is
large enough to use up all the values from all the value lists. If a value
list does not contain enough elements for each of its loop variables in each
iteration, empty values are used for the missing elements.

The '''break''' and '''continue''' statements may be invoked inside body, with
the same effect as in the '''for''' and '''foreach''' commands.  In these
cases the body does not complete "normally" and the result is not appended to
the accumulator list.

~~ The "dict map" Command

The '''dict map''' command takes three arguments, the first a two-element list
of variable names (for the key and value respectively of each mapping in the
dictionary), the second the dictionary value to iterate across, and the third
a script to be evaluated for each mapping with the key and value variables set
appropriately (in the manner of '''lmap''').  In an iteration where the
evaluated script completes normally (''TCL_OK''), the script result is put
into an accumulator dictionary using the current value of the key variable at
that point (having an unset key variable at that point is an error); the
result of the '''dict map''' command is that accumulator dictionary. Note that
it is a deliberate consequence of the above specification that you can change
what key a value is mapped to by altering the key variable during the body of
the loop.

If any evaluation of the body generates a ''TCL_BREAK'' result, no further
pairs from the dictionary will be iterated over and the '''dict map''' command
will terminate successfully immediately. If any evaluation of the body
generates a ''TCL_CONTINUE'' result, the current iteration is aborted and the
accumulator dictionary is not modified.  The order of iteration is the order
in which the keys were inserted into the dictionary (the "natural" iteration
order).

(Note that you can view '''dict map''' as being to '''dict for''' what
'''lmap''' is to '''foreach'''.)

~ Examples

Square the values of a list:

| set squares [lmap a $list {expr {$a ** 2}}]

Zip lists together:

| set zipped [lmap a $list1 b $list2 {list $a $b}] 

Consume several values at once:

| set sums [lmap {a b} $values {+ $a $b}] 

Filter a list:

| set goodOnes [lmap x $values {expr {[isGood $x] ? $x : [continue]}}] 

Take a prefix from a list:

| set prefix [lmap x $values {expr {[isGood $x] ? $x : [break]}}] 

Comparative performance figures:

| for {set i 0} {$i < 1000000} {incr i} {
|   lappend input [expr { int(rand() * 1000000) }] 
| }

| # Test the performance of [lmap]
| time { apply {{} { 
|   set accum 0
|   foreach val [lmap i $::input {expr { $i * 5}}] { incr accum $val }
|   puts $accum 
| }} } 10
| # Pure Tcl 'Approach #2' implementation from [http://wiki.tcl.tk/26013]
| #   1259118.1 microseconds per iteration
| # C implementation (not bytecode compiled)
| #   1107894.4 microseconds per iteration
| # Bytecode compiled
| #    375085.5 microseconds per iteration

Finding the square root of each of the values in a dictionary, filtering out
everything that is not a non-negative number (i.e., outside the domain of the
square root operation):

| set roots [dict map {k num} $someDict {
|     try {
|         expr {$num ** 0.5}
|     } on error {} {
|         continue
|     }

| }]

Adjusting the global '''env''' array so that all keys are also present as
upper-case keys and lower-case values (a not-particularly-useful operation):

| array set env [dict map {key val} [dict get env] {
|     set key [string toupper $key]
|     string tolower $val
| }]

~ Alternatives

The name '''mapeach''' was originally proposed instead of '''lmap'''.
However, since Jim Tcl already supports '''lmap''' with the same semantics as
this TIP proposes, and a pure-Tcl implementation with similar semantics
appears on the Wiki [http://wiki.tcl.tk/13920], this TIP was updated with the
change of name.  The TIP author favours '''lmap'''.

~ Reference Implementation

A reference implementation is provided as branch ''tip-405-impl-td''. Older
revisions are attached to Patch #3163961
[https://sourceforge.net/support/tracker.php?aid=3163961].  The implementation
leverages the existing '''foreach''' infrastructure to provide bytecode
support.  A test suite is provided.

~ Thanks

Thanks to Donal Fellows for suggesting a collecting '''foreach''' and
providing examples, and to Steve Bennett for suggesting the name '''lmap'''.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|
|

|
|
|

|

|
|
|
|

|
|


|
|

|

|
|

|

|

|

|

|

|



|
|
|
|
|

|


|
|
|







|
|



|

|
|
|

|
|

|
|




|
|

|

|
|

|
|

|



|



|



|



|



|



|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|


|
|

|
|
|
|
|
<
>
|

|
|

|
|
|
|

|

|
|

|
|

|

|
|
|
|


|

|
|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

# TIP 405: Add Collecting Loops, the 'lmap' and 'dict map' Commands

	Author:         Trevor Davel <[email protected]>
	Author:		Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        31-Jul-2012
	Post-History:   
	Keywords:       Tcl,mapeach,loop,accumulator
	Tcl-Version:    8.6
-----

# Abstract

The **lmap** command is a collecting loop with the semantics of
**foreach**.  When the loop begins an accumulator is set to an empty list.
In any iteration where the body of the loop completes normally, the result of
the body is appended to the accumulator list.  The return value for **lmap**
is the contents of the accumulator.  The **dict map** command is an
equivalent collecting loop with the semantics based off **dict for**.

# Rationale

**lmap** arises from a Tcler's Wiki discussion on higher order functions
<http://wiki.tcl.tk/26013> .  The construct combines the capabilities of the
higher order functions _map_ and _filter_ with the familiarity and
expressive power of Tcl's **foreach**.

While **lmap** can be implemented in pure Tcl using **uplevel** \(see the
Wiki for examples\), substantial performance gains are possible with a bytecode
implementation.

**dict map** was suggested by DKF on tcl-core \(2012-08-01\) as native
dictionary iteration is more efficient that a **lmap** with two variables\).

# Proposed Changes

A new command **lmap** will be created, with arguments are intentionally
very similar to those to **foreach**:

 > **lmap** _varname list body_

 > **lmap** _varlist1 list1_ ?_varlist2 list2 ..._? _body_

The **dict** ensemble will be extended with a new sub-command **map**:

 > **dict map** \{_keyVar valueVar_\} _dictionary script_

## The "lmap" Command

The **lmap** command implements a loop where the loop variable\(s\) take on
values from one or more lists, and the loop returns a list of results
collected from each iteration.

In the simplest case there is one loop variable, _varname_, and one list,
_list_, that is a list of values to assign to _varname_. The _body_
argument is a Tcl script. For each element of list \(in order from first to
last\), **lmap** assigns the contents of the element to _varname_ as if
the **lindex** command had been used to extract the element, then calls the
Tcl interpreter to execute body.  If execution of the body completes normally
then the result of the body is appended to an accumulator list.  **lmap**
returns the accumulator list.

In the general case there can be more than one value list \(e.g., _list1_ and
_list2_\), and each value list can be associated with a list of loop
variables \(e.g., _varlist1_ and _varlist2_\). During each iteration of the
loop the variables of each varlist are assigned consecutive values from the
corresponding list. Values in each list are used in order from first to last,
and each value is used exactly once. The total number of loop iterations is
large enough to use up all the values from all the value lists. If a value
list does not contain enough elements for each of its loop variables in each
iteration, empty values are used for the missing elements.

The **break** and **continue** statements may be invoked inside body, with
the same effect as in the **for** and **foreach** commands.  In these
cases the body does not complete "normally" and the result is not appended to
the accumulator list.

## The "dict map" Command

The **dict map** command takes three arguments, the first a two-element list
of variable names \(for the key and value respectively of each mapping in the
dictionary\), the second the dictionary value to iterate across, and the third
a script to be evaluated for each mapping with the key and value variables set
appropriately \(in the manner of **lmap**\).  In an iteration where the
evaluated script completes normally \(_TCL\_OK_\), the script result is put
into an accumulator dictionary using the current value of the key variable at
that point \(having an unset key variable at that point is an error\); the
result of the **dict map** command is that accumulator dictionary. Note that
it is a deliberate consequence of the above specification that you can change
what key a value is mapped to by altering the key variable during the body of
the loop.

If any evaluation of the body generates a _TCL\_BREAK_ result, no further
pairs from the dictionary will be iterated over and the **dict map** command
will terminate successfully immediately. If any evaluation of the body
generates a _TCL\_CONTINUE_ result, the current iteration is aborted and the
accumulator dictionary is not modified.  The order of iteration is the order
in which the keys were inserted into the dictionary \(the "natural" iteration
order\).

\(Note that you can view **dict map** as being to **dict for** what
**lmap** is to **foreach**.\)

# Examples

Square the values of a list:

	 set squares [lmap a $list {expr {$a ** 2}}]

Zip lists together:

	 set zipped [lmap a $list1 b $list2 {list $a $b}] 

Consume several values at once:

	 set sums [lmap {a b} $values {+ $a $b}] 

Filter a list:

	 set goodOnes [lmap x $values {expr {[isGood $x] ? $x : [continue]}}] 

Take a prefix from a list:

	 set prefix [lmap x $values {expr {[isGood $x] ? $x : [break]}}] 

Comparative performance figures:

	 for {set i 0} {$i < 1000000} {incr i} {
	   lappend input [expr { int(rand() * 1000000) }] 

	 }
	 # Test the performance of [lmap]
	 time { apply {{} { 
	   set accum 0
	   foreach val [lmap i $::input {expr { $i * 5}}] { incr accum $val }
	   puts $accum 
	 }} } 10
	 # Pure Tcl 'Approach #2' implementation from [http://wiki.tcl.tk/26013]
	 #   1259118.1 microseconds per iteration
	 # C implementation (not bytecode compiled)
	 #   1107894.4 microseconds per iteration
	 # Bytecode compiled
	 #    375085.5 microseconds per iteration

Finding the square root of each of the values in a dictionary, filtering out
everything that is not a non-negative number \(i.e., outside the domain of the
square root operation\):

	 set roots [dict map {k num} $someDict {
	     try {
	         expr {$num ** 0.5}
	     } on error {} {
	         continue

	     }
	 }]

Adjusting the global **env** array so that all keys are also present as
upper-case keys and lower-case values \(a not-particularly-useful operation\):

	 array set env [dict map {key val} [dict get env] {
	     set key [string toupper $key]
	     string tolower $val
	 }]

# Alternatives

The name **mapeach** was originally proposed instead of **lmap**.
However, since Jim Tcl already supports **lmap** with the same semantics as
this TIP proposes, and a pure-Tcl implementation with similar semantics
appears on the Wiki <http://wiki.tcl.tk/13920> , this TIP was updated with the
change of name.  The TIP author favours **lmap**.

# Reference Implementation

A reference implementation is provided as branch _tip-405-impl-td_. Older
revisions are attached to Patch \#3163961
<https://sourceforge.net/support/tracker.php?aid=3163961> .  The implementation
leverages the existing **foreach** infrastructure to provide bytecode
support.  A test suite is provided.

# Thanks

Thanks to Donal Fellows for suggesting a collecting **foreach** and
providing examples, and to Steve Bennett for suggesting the name **lmap**.

# Copyright

This document has been placed in the public domain.

Name change from tip/406.tip to tip/406.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

TIP:		406
Title:		"C" is for Cookie
State:		Draft
Type:		Project
Tcl-Version:	8.6
Vote:		Pending
Post-History:	
Version:	$Revision: 1.4 $
Author:		Donal K. Fellows <[email protected]>
Created:	01-Aug-2012


~ Abstract

The "http" package needs cookie support, especially to support complex modern
web authentication protocols. This TIP defines a pluggable interface and a
TclOO class that implements that interface so that Tcl programmers can control
just what is shared and stored, and where.

~ Rationale and Design Constraints

Cookies are a feature of many modern web applications. They're short strings
stored in HTTP clients on behalf of servers, and which are then sent back to
those servers with further requests to those servers. Often (but not
universally) these short strings are IDs that are used as database keys to
look up a "session object" in a server-side database that holds relevant
information; such information can include whether the user has logged in, what
color scheme to use in the stylesheet, etc. Of particular relevance to Tcl
programmers is the fact that they are often now associated with login
information; this means that it is not practical to leave Tcl code without
cookie support.

Currently, Tcl programs that handle cookies have to do so manually, examining
the otherwise-unparsed HTTP headers to see if anything relevant has been set.
As the cookie protocol [http://tools.ietf.org/html/rfc6265] is quite complex,
it is highly desirable to have a centralized implementation of at least the
basic parsing and injection code.

The main down-side of adding cookie handling is that definitely increases the
ability of web servers to track clients written in Tcl. In particular, there
is a danger of cross-application tracking. It is therefore necessary to ensure
that the cookie handling mechanism is off by default, and that the locations
used to store the cookies are controllable by the Tcl application.

~ Proposed Change to 'http' Package

I propose to add a new configuration option to the ''http'' package:

 > '''-cookiejar''' ''commandPrefixList''

This option (configurable via '''http::config'''), can either be an empty
string (the default), or it can be a list of words that is a command prefix.
An empty string will disable cookie handling: the current ''http'' package
behavior in relation to cookies (i.e., ignoring them) will prevail. However,
if a non-empty list of words is supplied, they will be used as if they were a
command (or rather a prefix to be expanded) in the following ways:

~~ For Each Cookie Provided by an HTTP Server

When a cookie is supplied by an HTTP server, it will be reported to the cookie
jar command like this:

 > {*}''$commandPrefixList'' '''storeCookie''' ''cookieName cookieValue optionDictionary''

The ''cookieName'' and ''cookieValue'' are relatively self-explanatory; they
represent the name/value pair to store. The ''optionDictionary'' contains the
parsed cookie options, being at least these:

 hostonly: Boolean; whether the cookie should only ever be returned to the
 originating host (if not, it should be sent according to the domain). This
 property is always present.

 httponly: Boolean; whether the cookie ought to be only used with HTTP
 connections. (NB: This is unlikely to be something we enforce.) This property
 is always present.

 persistent: Boolean; whether the HTTP server wishes the cookie to persist for
 longer than the current "session". This property is always present.
 Non-persistent cookies are expected to never be committed to permanent
 storage.

 secure: Boolean; whether the cookie should only be sent on "secure"
 connections to the HTTP server. (This typically means "HTTPS is required",
 but the various cookie specifications are less-than-clear in this area.) This
 property is always present.

 expires: Timestamp; when a persistent cookie will cease to be interesting to
 the HTTP server that issued it. (NB: If this is in the past, any matching
 cookie should be deleted.) This property is only present if the "persistent"
 property is true.

 domain: String; what domains should this cookie be sent to. This property is
 always present, but may sometimes be the same as the "origin" property; see
 the "hostonly" property for how to treat this.

 origin: String; what host did we send the request to that caused this cookie
 to be generated. This property is always present.

 path: String; what resource paths within the relevant HTTP servers should a
 cookie be sent to. This property is always present.

The result of this command will be ignored (so long as it is non-exceptional).

~~ When Making an HTTP Request

Each time an HTTP request is made, the cookie store is consulted (prior to the
connection being opened) to find out what cookies should be sent as part of
the request, like this:

 > {*}''$commandPrefixList'' '''getCookies''' ''protocol host path''

The ''protocol'' is the name of the protocol scheme that will be used to
contact the HTTP server (typically '''http''' or '''https'''), the ''host'' is
the server's hostname, and the ''path'' is the resource path on that server.
The query and fragment parts of the URL are ''never'' supplied to the cookie
store as part of this request, nor is the port, nor are any user
identification credentials (the cookie specification specifically states that
it is a known problem that cookies have ''always'' ignored the service port
number for the purposes of whether to send the cookie; we therefore duplicate
this failure).

The result is treated as a list of keys and values (i.e., it is expected to be
a list with an even number of items in it, with the first key at index 0 and
the first value at index 1) and describes the collection of cookies to send.
The ''http'' package will manage the formatting of the cookies as part of the
request to send.

~ A Cookie Jar Implementation

To go with the above specification, this TIP also describes a TclOO class that
will be provided to implement the cookie store side of the protocol. This
class will be provided in the '''cookiejar''' package.

The name of the class will be '''::http::cookiejar''', and its instances will
be cookie stores that participate in the above protocol. The constructor of
the class will take an optional argument that names an SQLite database that
will be used to store the cookies; if no name is provided, an in-memory
database will be used and all cookies will be treated like pure session
cookies.

The result is that it will be possible to enable cookie handling in a Tcl
script using this:

| package require http
| package require cookiejar
|
| http::config -cookiejar [http::cookiejar new ~/mycookies.db]

The '''::http::cookiejar''' class will also allow configuration of its logging
level via the '''loglevel''' method on the class (which takes a single
argument, the new logging level, or which returns the current logging level if
called with no arguments). Permitted log levels are '''error''', '''warn''',
'''info''' and '''debug'''. Log messages will be written by a call to
'''::http::Log''' (which does nothing by default anyway).

An example of setting the logging level to the (substantially more verbose)
'''debug''' level:

| http::cookiejar loglevel debug

The instances of the '''::http::cookiejar''' class will additionally support
the method '''forceLoadDomainData''' and the method '''lookup'''.

 > ''instance'' '''forceLoadDomainData'''

This instructs the instance to load (or reload) its definitions of what
domains may not have cookies set for them. It takes no extra arguments and
produces an empty result (unless an error occurs).

 > ''instance'' '''lookup''' ?''host''? ?''key''?

This looks up cookies in the store. If neither ''host'' nor ''key'' are
specified, this returns the list hosts for which cookies are defined. If
''host'' is specified but ''key'' is not, this returns the list of cookie keys
for the host (note that these may be session cookies or durable cookies; this
interface does not distinguish). If both ''host'' and ''key'' are specified,
the value for the particular cookie is returned (with it being an error if no
such cookie is defined). This method provides no mechanism for setting the
value of a cookie or creating a new one.

~~ Implementation Notes

It is worth noting that the current cookiejar package will download a list of
"bad" domains (i.e., domains that correspond to super-registries, such as
'''com''', '''ac.uk''' or '''tk''') when a new database is constructed
(provided the cookiejar instance is backed by a database file; in-memory
databases never have this part populated by default). This extensive list of
domains
[http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1]
is a security feature that prevents the setting of cookies for large numbers
of hosts at once, but it is belived sufficiently long that it is excessive for
supplying as part of the package directly.

The degree to which it is necessary to update cookie stores from that list has
not yet been studied.

The underlying SQLite database is forwarded to the cookiejar instance's
interface as the (default non-exported) method '''Database'''; this takes all
the normal subcommands of an SQLite ''dbcmd'', as documented in
[http://www.sqlite.org/tclsqlite.html].

The cookiejar package handles conversion of host names into and out of
punycode so that lookups are always performed on canonical names. This is
important because there is no guarantee that the encoding of host names will
be the same as they are referred to in another context; for example, the list
of forbidden domains above is in UTF-8 and not using the IDNA scheme.

~ Privacy

Cookies are often associated in the public mind with problems with privacy.
There are two principal mechanisms provided here to mitigate these (beyond the
proposed domain restrictions, which follow recommended Best Practice):

 1. No Tcl interpreter will ever have cookie handling enabled by default.
 There will always need to be an explicit action taken to turn it on.

 2. Applications have to pick the name of their cookie stores when creating
 and installing them; there is no default.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
>

|






|



|
|









|









|

|

|

|
|
|
|

|

|




|

|
|



|



|








|
|



|
|












|

|

|
|


|

|
|
|
|

|
|

|

|

|
|


|



|

|









|
|
|
|

|
|

|
|
|

|
|

|

|
|

|

|

|

|

|

|
|
|
|
|


|


|
|
|
|

|








|
|
|







|


|
|







|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

# TIP 406: "C" is for Cookie
	State:		Draft
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Pending
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	01-Aug-2012
-----

# Abstract

The "http" package needs cookie support, especially to support complex modern
web authentication protocols. This TIP defines a pluggable interface and a
TclOO class that implements that interface so that Tcl programmers can control
just what is shared and stored, and where.

# Rationale and Design Constraints

Cookies are a feature of many modern web applications. They're short strings
stored in HTTP clients on behalf of servers, and which are then sent back to
those servers with further requests to those servers. Often \(but not
universally\) these short strings are IDs that are used as database keys to
look up a "session object" in a server-side database that holds relevant
information; such information can include whether the user has logged in, what
color scheme to use in the stylesheet, etc. Of particular relevance to Tcl
programmers is the fact that they are often now associated with login
information; this means that it is not practical to leave Tcl code without
cookie support.

Currently, Tcl programs that handle cookies have to do so manually, examining
the otherwise-unparsed HTTP headers to see if anything relevant has been set.
As the cookie protocol <http://tools.ietf.org/html/rfc6265>  is quite complex,
it is highly desirable to have a centralized implementation of at least the
basic parsing and injection code.

The main down-side of adding cookie handling is that definitely increases the
ability of web servers to track clients written in Tcl. In particular, there
is a danger of cross-application tracking. It is therefore necessary to ensure
that the cookie handling mechanism is off by default, and that the locations
used to store the cookies are controllable by the Tcl application.

# Proposed Change to 'http' Package

I propose to add a new configuration option to the _http_ package:

 > **-cookiejar** _commandPrefixList_

This option \(configurable via **http::config**\), can either be an empty
string \(the default\), or it can be a list of words that is a command prefix.
An empty string will disable cookie handling: the current _http_ package
behavior in relation to cookies \(i.e., ignoring them\) will prevail. However,
if a non-empty list of words is supplied, they will be used as if they were a
command \(or rather a prefix to be expanded\) in the following ways:

## For Each Cookie Provided by an HTTP Server

When a cookie is supplied by an HTTP server, it will be reported to the cookie
jar command like this:

 > \{\*\}_$commandPrefixList_ **storeCookie** _cookieName cookieValue optionDictionary_

The _cookieName_ and _cookieValue_ are relatively self-explanatory; they
represent the name/value pair to store. The _optionDictionary_ contains the
parsed cookie options, being at least these:

 hostonly: Boolean; whether the cookie should only ever be returned to the
 originating host \(if not, it should be sent according to the domain\). This
 property is always present.

 httponly: Boolean; whether the cookie ought to be only used with HTTP
 connections. \(NB: This is unlikely to be something we enforce.\) This property
 is always present.

 persistent: Boolean; whether the HTTP server wishes the cookie to persist for
 longer than the current "session". This property is always present.
 Non-persistent cookies are expected to never be committed to permanent
 storage.

 secure: Boolean; whether the cookie should only be sent on "secure"
 connections to the HTTP server. \(This typically means "HTTPS is required",
 but the various cookie specifications are less-than-clear in this area.\) This
 property is always present.

 expires: Timestamp; when a persistent cookie will cease to be interesting to
 the HTTP server that issued it. \(NB: If this is in the past, any matching
 cookie should be deleted.\) This property is only present if the "persistent"
 property is true.

 domain: String; what domains should this cookie be sent to. This property is
 always present, but may sometimes be the same as the "origin" property; see
 the "hostonly" property for how to treat this.

 origin: String; what host did we send the request to that caused this cookie
 to be generated. This property is always present.

 path: String; what resource paths within the relevant HTTP servers should a
 cookie be sent to. This property is always present.

The result of this command will be ignored \(so long as it is non-exceptional\).

## When Making an HTTP Request

Each time an HTTP request is made, the cookie store is consulted \(prior to the
connection being opened\) to find out what cookies should be sent as part of
the request, like this:

 > \{\*\}_$commandPrefixList_ **getCookies** _protocol host path_

The _protocol_ is the name of the protocol scheme that will be used to
contact the HTTP server \(typically **http** or **https**\), the _host_ is
the server's hostname, and the _path_ is the resource path on that server.
The query and fragment parts of the URL are _never_ supplied to the cookie
store as part of this request, nor is the port, nor are any user
identification credentials \(the cookie specification specifically states that
it is a known problem that cookies have _always_ ignored the service port
number for the purposes of whether to send the cookie; we therefore duplicate
this failure\).

The result is treated as a list of keys and values \(i.e., it is expected to be
a list with an even number of items in it, with the first key at index 0 and
the first value at index 1\) and describes the collection of cookies to send.
The _http_ package will manage the formatting of the cookies as part of the
request to send.

# A Cookie Jar Implementation

To go with the above specification, this TIP also describes a TclOO class that
will be provided to implement the cookie store side of the protocol. This
class will be provided in the **cookiejar** package.

The name of the class will be **::http::cookiejar**, and its instances will
be cookie stores that participate in the above protocol. The constructor of
the class will take an optional argument that names an SQLite database that
will be used to store the cookies; if no name is provided, an in-memory
database will be used and all cookies will be treated like pure session
cookies.

The result is that it will be possible to enable cookie handling in a Tcl
script using this:

	 package require http
	 package require cookiejar
	
	 http::config -cookiejar [http::cookiejar new ~/mycookies.db]

The **::http::cookiejar** class will also allow configuration of its logging
level via the **loglevel** method on the class \(which takes a single
argument, the new logging level, or which returns the current logging level if
called with no arguments\). Permitted log levels are **error**, **warn**,
**info** and **debug**. Log messages will be written by a call to
**::http::Log** \(which does nothing by default anyway\).

An example of setting the logging level to the \(substantially more verbose\)
**debug** level:

	 http::cookiejar loglevel debug

The instances of the **::http::cookiejar** class will additionally support
the method **forceLoadDomainData** and the method **lookup**.

 > _instance_ **forceLoadDomainData**

This instructs the instance to load \(or reload\) its definitions of what
domains may not have cookies set for them. It takes no extra arguments and
produces an empty result \(unless an error occurs\).

 > _instance_ **lookup** ?_host_? ?_key_?

This looks up cookies in the store. If neither _host_ nor _key_ are
specified, this returns the list hosts for which cookies are defined. If
_host_ is specified but _key_ is not, this returns the list of cookie keys
for the host \(note that these may be session cookies or durable cookies; this
interface does not distinguish\). If both _host_ and _key_ are specified,
the value for the particular cookie is returned \(with it being an error if no
such cookie is defined\). This method provides no mechanism for setting the
value of a cookie or creating a new one.

## Implementation Notes

It is worth noting that the current cookiejar package will download a list of
"bad" domains \(i.e., domains that correspond to super-registries, such as
**com**, **ac.uk** or **tk**\) when a new database is constructed
\(provided the cookiejar instance is backed by a database file; in-memory
databases never have this part populated by default\). This extensive list of
domains
<http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1> 
is a security feature that prevents the setting of cookies for large numbers
of hosts at once, but it is belived sufficiently long that it is excessive for
supplying as part of the package directly.

The degree to which it is necessary to update cookie stores from that list has
not yet been studied.

The underlying SQLite database is forwarded to the cookiejar instance's
interface as the \(default non-exported\) method **Database**; this takes all
the normal subcommands of an SQLite _dbcmd_, as documented in
<http://www.sqlite.org/tclsqlite.html> .

The cookiejar package handles conversion of host names into and out of
punycode so that lookups are always performed on canonical names. This is
important because there is no guarantee that the encoding of host names will
be the same as they are referred to in another context; for example, the list
of forbidden domains above is in UTF-8 and not using the IDNA scheme.

# Privacy

Cookies are often associated in the public mind with problems with privacy.
There are two principal mechanisms provided here to mitigate these \(beyond the
proposed domain restrictions, which follow recommended Best Practice\):

 1. No Tcl interpreter will ever have cookie handling enabled by default.
 There will always need to be an explicit action taken to turn it on.

 2. Applications have to pick the name of their cookie stores when creating
 and installing them; there is no default.

# Copyright

This document has been placed in the public domain.

Name change from tip/407.tip to tip/407.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282

TIP:            407
Title:          The String Representation of Tcl Lists: the Gory Details
Version:        $Revision: 1.7 $
Author:         Donal K. Fellows <[email protected]>
Author:         Kevin Kenny <[email protected]>
Author:		Don Porter <[email protected]>
State:          Draft
Type:           Informative
Vote:           No voting
Created:        06-Aug-2012
Post-History:   


~ Abstract

This document explains some of the details behind Tcl lists; it is there to
expose documentation that was previously only present as comments in Tcl's
source code.

~ String Representation of Lists

The routines [[in tclUtil.c]] implement the conversions of strings to and from
Tcl lists. To understand their operation, the rules of parsing and generating
the string representation of lists must be known.  Here we describe them in
one place.

A list is made up of zero or more elements. Any string is a list if it is made
up of alternating substrings of element-separating ASCII whitespace and
properly formatted elements.

The ASCII characters which can make up the whitespace between list elements
are:

|    \u0009    \t    TAB
|    \u000A    \n    NEWLINE
|    \u000B    \v    VERTICAL TAB
|    \u000C    \f    FORM FEED
|    \u000D    \r    CARRIAGE RETURN
|    \u0020          SPACE

'''NOTE:''' differences between this and other places where Tcl defines a role
for "whitespace".

 * Unlike command parsing, here NEWLINE is just another whitespace character;
   its role as a command terminator in a script has no importance here.

 * Unlike command parsing, the BACKSLASH NEWLINE sequence is not considered to
   be a whitespace character.

 * Other Unicode whitespace characters (recognized by '''string is space''' or
   ''Tcl_UniCharIsSpace()'') do not play any role as element separators in Tcl
   lists.

 * The NUL byte ought not appear, as it is not in strings properly encoded for
   Tcl, but if it is present, it is not treated as separating whitespace, or a
   string terminator. It is just another character in a list element.

The interpretaton of a formatted substring as a list element follows rules
similar to the parsing of the words of a command in a Tcl script. Backslash
substitution plays a key role, and is defined exactly as it is in command
parsing. The same routine, ''TclParseBackslash()'' is used in both command
parsing and list parsing.

'''NOTE:''' This means that if and when backslash substitution rules ever
change for command parsing, the interpretation of strings as lists also
changes.

Backslash substitution replaces an "escape sequence" of one or more
characters starting with

|    \u005c    \    BACKSLASH

with a single character. The one character escape sequent case happens only
when BACKSLASH is the last character in the string. In all other cases, the
escape sequence is at least two characters long.

The formatted substrings are interpreted as element values according to the
following cases:

 * If the first character of a formatted substring is

|    \u007b    {    OPEN BRACE

 > then the end of the substring is the matching 

|    \u007d    }    CLOSE BRACE

 > character, where matching is determined by counting nesting levels, and not
   including any brace characters that are contained within a backslash escape
   sequence in the nesting count. Having found the matching brace, all
   characters between the braces are the string value of the element.  If no
   matching close brace is found before the end of the string, the string is
   not a Tcl list. If the character following the close brace is not an
   element separating whitespace character, or the end of the string, then the
   string is not a Tcl list.

 > '''NOTE:''' this differs from a brace-quoted word in the parsing of a Tcl
   command only in its treatment of the backslash-newline sequence. In a list
   element, the literal characters in the backslash-newline sequence become
   part of the element value. In a script word, conversion to a single SPACE
   character is done.

 > '''NOTE:''' Most list element values can be represented by a formatted
   substring using brace quoting. The exceptions are any element value that
   includes an unbalanced brace not in a backslash escape sequence, and any
   value that ends with a backslash not itself in a backslash escape sequence.

 * If the first character of a formatted substring is

|    \u0022    "    QUOTE

 > then the end of the substring is the next QUOTE character, not counting any
   QUOTE characters that are contained within a backslash escape sequence. If
   no next QUOTE is found before the end of the string, the string is not a
   Tcl list. If the character following the closing QUOTE is not an element
   separating whitespace character, or the end of the string, then the string
   is not a Tcl list. Having found the limits of the substring, the element
   value is produced by performing backslash substitution on the character
   sequence between the open and close QUOTEs.

 > '''NOTE:''' Any element value can be represented by this style of
   formatting, given suitable choice of backslash escape sequences.

 * All other formatted substrings are terminated by the next element
   separating whitespace character in the string.  Having found the limits of
   the substring, the element value is produced by performing backslash
   substitution on it.

 > '''NOTE:''' Any element value can be represented by this style of
   formatting, given suitable choice of backslash escape sequences, with one
   exception.  The empty string cannot be represented as a list element
   without the use of either braces or quotes to delimit it.

This collection of parsing rules is implemented in the routine
''TclFindElement()''.

In order to produce lists that can be parsed by these rules, we need the
ability to distinguish between characters that are part of a list element
value from characters providing syntax that define the structure of the list.
This means that our code that generates lists must at a minimum be able to
produce escape sequences for the 10 characters identified above that have
significance to a list parser.

~ Canonical Lists

In addition to the basic rules for parsing strings into Tcl lists, there are
additional properties to be met by the set of list values that are generated
by Tcl. Such list values are often said to be in "canonical form":

 * When any canonical list is evaluated as a Tcl script, it is a script of
   either zero commands (an empty list) or exactly one command. The command
   word is exactly the first element of the list, and each argument word is
   exactly one of the following elements of the list. This means that any
   characters that have special meaning during script evaluation need special
   treatment when canonical lists are produced:

 > * Whitespace between elements may not include NEWLINE.

 > * The command terminating character,

|    \u003b    ;    SEMICOLON

 > > must be BRACEd, QUOTEd, or escaped so that it does not terminate the
     command prematurely.

 > * Any of the characters that begin substitutions in scripts,

|    \u0024    $    DOLLAR
|    \u005b    [    OPEN BRACKET
|    \u005c    \    BACKSLASH

 > > need to be BRACEd or escaped.

 > * In any list where the first character of the first element is

|    \u0023    #    HASH

 > > that HASH character must be BRACEd, QUOTEd, or escaped so that it does
     not convert the command into a comment.

 > * Any list element that contains the character sequence BACKSLASH NEWLINE
     cannot be formatted with BRACEs. The BACKSLASH character must be
     represented by an escape sequence, and unless QUOTEs are used, the
     NEWLINE must be as well.

 * It is also guaranteed that one can use a canonical list as a building block
   of a larger script within command substitution, as in this example:

|        set script "puts \[[list $cmd $arg]]"; eval $script

 > To support this usage, any appearance of the character

|    \u005d    ]    CLOSE BRACKET

 > in a list element must be BRACEd, QUOTEd, or escaped.

 * Finally it is guaranteed that enclosing a canonical list in braces produces
   a new value that is also a canonical list.  This new list has length 1, and
   its only element is the original canonical list.  This same guarantee also
   makes it possible to construct scripts where an argument word is given a
   list value by enclosing the canonical form of that list in braces:

|        set script "puts {[list $one $two $three]}"; eval $script

 > This sort of coding was once fairly common, though it's become more
   idiomatic to see the following instead:

|        set script [list puts [list $one $two $three]]; eval $script

 > In order to support this guarantee, every canonical list must have balance
   when counting those braces that are not in escape sequences.

Within these constraints, the canonical list generation routines
''TclScanElement()'' and ''TclConvertElement()'' attempt to generate the
string for any list that is easiest to read. When an element value is itself
acceptable as the formatted substring, it is usually used (CONVERT_NONE).
When some quoting or escaping is required, use of BRACEs (CONVERT_BRACE) is
usually preferred over the use of escape sequences (CONVERT_ESCAPE). There are
some exceptions to both of these preferences for reasons of code simplicity,
efficiency, and continuation of historical habits. Canonical lists never use
the QUOTE formatting to delimit their elements because that form of quoting
does not nest, which makes construction of nested lists far too much trouble.
Canonical lists always use only a single SPACE character for
element-separating whitespace.

~ Future Considerations

When a list element requires quoting or escaping due to a CLOSE BRACKET
character or an internal QUOTE character, a strange formatting mode is
recommended. For example, if the value "'''a{b]]c}d'''" is converted by the
usual modes:

|    CONVERT_BRACE:    a{b]c}d    => {a{b]c}d}
|    CONVERT_ESCAPE:   a{b]c}d    => a\{b\]c\}d

we get perfectly usable formatted list elements. However, this is not what Tcl
releases have been producing. Instead, we have:

|    CONVERT_MASK:     a{b]c}d    => a{b\]c}d

where the CLOSE BRACKET is escaped, but the BRACEs are not. The same effect
can be seen replacing ''']]''' with '''"''' in this example. There does not
appear to be any functional or aesthetic purpose for this strange additional
mode. The sole purpose I can see for preserving it is to keep generating the
same formatted lists programmers have become accustomed to, and perhaps
written tests to expect. That is, compatibility only. The additional code
complexity required to support this mode is significant. The lines of code
supporting it are delimited in the routines marked with '''#if COMPAT'''
directives. This makes it easy to experiment with eliminating this formatting
mode simply with "'''#define COMPAT 0'''" above. I believe this is worth
considering.

Another consideration is the treatment of QUOTE characters in list elements.
''TclConvertElement()'' must have the ability to produce the escape sequence
'''\"''' so that when a list element begins with a QUOTE we do not confuse
that first character with a QUOTE used as list syntax to define list
structure.  However, that is the only place where QUOTE characters need
quoting. In this way, handling QUOTE could really be much more like the way we
handle HASH which also needs quoting and escaping only in particular
situations. Following up this could increase the set of list elements that can
use the CONVERT_NONE formatting mode.

More speculative is that the demands of canonical list form require brace
balance for the list as a whole, while the current implementation achieves
this by establishing brace balance for every element.

Finally, a reminder that the rules for parsing and formatting lists are
closely tied together with the rules for parsing and evaluating scripts, and
will need to evolve in sync.

~ Origin of Document and Copyright Notice

This document is based "near-verbatim" on comments in ''generic/tclUtil.c'' in
the Tcl source code distribution.
[http://core.tcl.tk/tcl/doc/trunk/generic/tclUtil.c]

|Copyright (c) 1987-1993 The Regents of the University of California.
|Copyright (c) 1994-1998 Sun Microsystems, Inc.
|Copyright (c) 2001 by Kevin B. Kenny. All rights reserved.

This document is made available under the same license as Tcl.

[[I, Kevin B. Kenny, dedicate any and all copyright interest in TIP #407 to the public domain. I make this dedication for the benefit of the public at large and to the detriment of my heirs and successors. I intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to TIP #407 under copyright law.]]

<
|
<
|
|
|
|
|
|
|
|
>

|





|

|











|
|
|
|
|
|

|








|
|









|


|






|










|

|

|

|








|





|






|

|








|







|





|








|






|





|

|

|

|


|

|
|
|

|

|

|

|


|







|

|

|

|







|

|


|

|



|

|
|
|







|



|


|
|




|


|





|

|



|
|





|









|

|

|

|
|
|



|
>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282

# TIP 407: The String Representation of Tcl Lists: the Gory Details

	Author:         Donal K. Fellows <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	Author:		Don Porter <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           No voting
	Created:        06-Aug-2012
	Post-History:   
-----

# Abstract

This document explains some of the details behind Tcl lists; it is there to
expose documentation that was previously only present as comments in Tcl's
source code.

# String Representation of Lists

The routines [in tclUtil.c] implement the conversions of strings to and from
Tcl lists. To understand their operation, the rules of parsing and generating
the string representation of lists must be known.  Here we describe them in
one place.

A list is made up of zero or more elements. Any string is a list if it is made
up of alternating substrings of element-separating ASCII whitespace and
properly formatted elements.

The ASCII characters which can make up the whitespace between list elements
are:

	    \u0009    \t    TAB
	    \u000A    \n    NEWLINE
	    \u000B    \v    VERTICAL TAB
	    \u000C    \f    FORM FEED
	    \u000D    \r    CARRIAGE RETURN
	    \u0020          SPACE

**NOTE:** differences between this and other places where Tcl defines a role
for "whitespace".

 * Unlike command parsing, here NEWLINE is just another whitespace character;
   its role as a command terminator in a script has no importance here.

 * Unlike command parsing, the BACKSLASH NEWLINE sequence is not considered to
   be a whitespace character.

 * Other Unicode whitespace characters \(recognized by **string is space** or
   _Tcl\_UniCharIsSpace\(\)_\) do not play any role as element separators in Tcl
   lists.

 * The NUL byte ought not appear, as it is not in strings properly encoded for
   Tcl, but if it is present, it is not treated as separating whitespace, or a
   string terminator. It is just another character in a list element.

The interpretaton of a formatted substring as a list element follows rules
similar to the parsing of the words of a command in a Tcl script. Backslash
substitution plays a key role, and is defined exactly as it is in command
parsing. The same routine, _TclParseBackslash\(\)_ is used in both command
parsing and list parsing.

**NOTE:** This means that if and when backslash substitution rules ever
change for command parsing, the interpretation of strings as lists also
changes.

Backslash substitution replaces an "escape sequence" of one or more
characters starting with

	    \u005c    \    BACKSLASH

with a single character. The one character escape sequent case happens only
when BACKSLASH is the last character in the string. In all other cases, the
escape sequence is at least two characters long.

The formatted substrings are interpreted as element values according to the
following cases:

 * If the first character of a formatted substring is

		    \u007b    {    OPEN BRACE

	 > then the end of the substring is the matching 

		    \u007d    }    CLOSE BRACE

	 > character, where matching is determined by counting nesting levels, and not
   including any brace characters that are contained within a backslash escape
   sequence in the nesting count. Having found the matching brace, all
   characters between the braces are the string value of the element.  If no
   matching close brace is found before the end of the string, the string is
   not a Tcl list. If the character following the close brace is not an
   element separating whitespace character, or the end of the string, then the
   string is not a Tcl list.

	 > **NOTE:** this differs from a brace-quoted word in the parsing of a Tcl
   command only in its treatment of the backslash-newline sequence. In a list
   element, the literal characters in the backslash-newline sequence become
   part of the element value. In a script word, conversion to a single SPACE
   character is done.

	 > **NOTE:** Most list element values can be represented by a formatted
   substring using brace quoting. The exceptions are any element value that
   includes an unbalanced brace not in a backslash escape sequence, and any
   value that ends with a backslash not itself in a backslash escape sequence.

 * If the first character of a formatted substring is

		    \u0022    "    QUOTE

	 > then the end of the substring is the next QUOTE character, not counting any
   QUOTE characters that are contained within a backslash escape sequence. If
   no next QUOTE is found before the end of the string, the string is not a
   Tcl list. If the character following the closing QUOTE is not an element
   separating whitespace character, or the end of the string, then the string
   is not a Tcl list. Having found the limits of the substring, the element
   value is produced by performing backslash substitution on the character
   sequence between the open and close QUOTEs.

	 > **NOTE:** Any element value can be represented by this style of
   formatting, given suitable choice of backslash escape sequences.

 * All other formatted substrings are terminated by the next element
   separating whitespace character in the string.  Having found the limits of
   the substring, the element value is produced by performing backslash
   substitution on it.

	 > **NOTE:** Any element value can be represented by this style of
   formatting, given suitable choice of backslash escape sequences, with one
   exception.  The empty string cannot be represented as a list element
   without the use of either braces or quotes to delimit it.

This collection of parsing rules is implemented in the routine
_TclFindElement\(\)_.

In order to produce lists that can be parsed by these rules, we need the
ability to distinguish between characters that are part of a list element
value from characters providing syntax that define the structure of the list.
This means that our code that generates lists must at a minimum be able to
produce escape sequences for the 10 characters identified above that have
significance to a list parser.

# Canonical Lists

In addition to the basic rules for parsing strings into Tcl lists, there are
additional properties to be met by the set of list values that are generated
by Tcl. Such list values are often said to be in "canonical form":

 * When any canonical list is evaluated as a Tcl script, it is a script of
   either zero commands \(an empty list\) or exactly one command. The command
   word is exactly the first element of the list, and each argument word is
   exactly one of the following elements of the list. This means that any
   characters that have special meaning during script evaluation need special
   treatment when canonical lists are produced:

	 > \* Whitespace between elements may not include NEWLINE.

	 > \* The command terminating character,

		    \u003b    ;    SEMICOLON

	 > > must be BRACEd, QUOTEd, or escaped so that it does not terminate the
     command prematurely.

	 > \* Any of the characters that begin substitutions in scripts,

		    \u0024    $    DOLLAR
		    \u005b    [    OPEN BRACKET
		    \u005c    \    BACKSLASH

	 > > need to be BRACEd or escaped.

	 > \* In any list where the first character of the first element is

		    \u0023    #    HASH

	 > > that HASH character must be BRACEd, QUOTEd, or escaped so that it does
     not convert the command into a comment.

	 > \* Any list element that contains the character sequence BACKSLASH NEWLINE
     cannot be formatted with BRACEs. The BACKSLASH character must be
     represented by an escape sequence, and unless QUOTEs are used, the
     NEWLINE must be as well.

 * It is also guaranteed that one can use a canonical list as a building block
   of a larger script within command substitution, as in this example:

		        set script "puts \[[list $cmd $arg]]"; eval $script

	 > To support this usage, any appearance of the character

		    \u005d    ]    CLOSE BRACKET

	 > in a list element must be BRACEd, QUOTEd, or escaped.

 * Finally it is guaranteed that enclosing a canonical list in braces produces
   a new value that is also a canonical list.  This new list has length 1, and
   its only element is the original canonical list.  This same guarantee also
   makes it possible to construct scripts where an argument word is given a
   list value by enclosing the canonical form of that list in braces:

		        set script "puts {[list $one $two $three]}"; eval $script

	 > This sort of coding was once fairly common, though it's become more
   idiomatic to see the following instead:

		        set script [list puts [list $one $two $three]]; eval $script

	 > In order to support this guarantee, every canonical list must have balance
   when counting those braces that are not in escape sequences.

Within these constraints, the canonical list generation routines
_TclScanElement\(\)_ and _TclConvertElement\(\)_ attempt to generate the
string for any list that is easiest to read. When an element value is itself
acceptable as the formatted substring, it is usually used \(CONVERT\_NONE\).
When some quoting or escaping is required, use of BRACEs \(CONVERT\_BRACE\) is
usually preferred over the use of escape sequences \(CONVERT\_ESCAPE\). There are
some exceptions to both of these preferences for reasons of code simplicity,
efficiency, and continuation of historical habits. Canonical lists never use
the QUOTE formatting to delimit their elements because that form of quoting
does not nest, which makes construction of nested lists far too much trouble.
Canonical lists always use only a single SPACE character for
element-separating whitespace.

# Future Considerations

When a list element requires quoting or escaping due to a CLOSE BRACKET
character or an internal QUOTE character, a strange formatting mode is
recommended. For example, if the value "**a\{b]c\}d**" is converted by the
usual modes:

	    CONVERT_BRACE:    a{b]c}d    => {a{b]c}d}
	    CONVERT_ESCAPE:   a{b]c}d    => a\{b\]c\}d

we get perfectly usable formatted list elements. However, this is not what Tcl
releases have been producing. Instead, we have:

	    CONVERT_MASK:     a{b]c}d    => a{b\]c}d

where the CLOSE BRACKET is escaped, but the BRACEs are not. The same effect
can be seen replacing **]** with **"** in this example. There does not
appear to be any functional or aesthetic purpose for this strange additional
mode. The sole purpose I can see for preserving it is to keep generating the
same formatted lists programmers have become accustomed to, and perhaps
written tests to expect. That is, compatibility only. The additional code
complexity required to support this mode is significant. The lines of code
supporting it are delimited in the routines marked with **\#if COMPAT**
directives. This makes it easy to experiment with eliminating this formatting
mode simply with "**\#define COMPAT 0**" above. I believe this is worth
considering.

Another consideration is the treatment of QUOTE characters in list elements.
_TclConvertElement\(\)_ must have the ability to produce the escape sequence
**\\"** so that when a list element begins with a QUOTE we do not confuse
that first character with a QUOTE used as list syntax to define list
structure.  However, that is the only place where QUOTE characters need
quoting. In this way, handling QUOTE could really be much more like the way we
handle HASH which also needs quoting and escaping only in particular
situations. Following up this could increase the set of list elements that can
use the CONVERT\_NONE formatting mode.

More speculative is that the demands of canonical list form require brace
balance for the list as a whole, while the current implementation achieves
this by establishing brace balance for every element.

Finally, a reminder that the rules for parsing and formatting lists are
closely tied together with the rules for parsing and evaluating scripts, and
will need to evolve in sync.

# Origin of Document and Copyright Notice

This document is based "near-verbatim" on comments in _generic/tclUtil.c_ in
the Tcl source code distribution.
<http://core.tcl.tk/tcl/doc/trunk/generic/tclUtil.c> 

	Copyright (c) 1987-1993 The Regents of the University of California.
	Copyright (c) 1994-1998 Sun Microsystems, Inc.
	Copyright (c) 2001 by Kevin B. Kenny. All rights reserved.

This document is made available under the same license as Tcl.

[I, Kevin B. Kenny, dedicate any and all copyright interest in TIP #407 to the public domain. I make this dedication for the benefit of the public at large and to the detriment of my heirs and successors. I intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to TIP #407 under copyright law.]

Name change from tip/408.tip to tip/408.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

TIP:		408
Title:		Allow Any Command for expr Functions
Version:	$Revision: 1.1 $
Author:		Brian Griffin <[email protected]>
State:		Draft
Type:		Project
Vote:		Pending
Created:	17-Aug-2012
Post-History:	
Tcl-Version:	8.7


~ Abstract

Proposed expansion of what constitutes a function in an '''expr''' expression.

~ Rationale: Nested expr Calls

The '''expr''' command in Tcl is the only way to perform math and comparison
operations.  Tcl's variable and command substitution rules allow for great
flexibility, although the syntax does not lead to great readability,
especially due to the ordering imposed on substitutions. For example, in the
expression:

| expr {[lindex $data $start] > 4}

the command substitution ([[...]]) is performed before the expression can be
parsed for evaluation, and, in order for the command substitution to be
parsed, the variable substitution ($) must be performed. The consequences of
this ordering means that arguments to commands cannot themselves be
expressions unless the argument is itself a command substitution involving
'''expr'''. This means, for example, that to compute an index value,
'''expr''' must be recursively called:

| expr {[lindex $data [expr {$start + 2}]] > 4}

However, when using a math function, the command substitution ordering does
not apply since the function is part of the expression syntax:

| expr {pow($x + 2, 2)}

It seems reasonable and useful if any Tcl command can be called using function
syntax:

| expr {lindex($data, $start + 2) > 4}

The common command substitution pattern has lead many developers to end up
writing things like:

| if {[expr {$a+$b}] > 7} ...

In hindsight, such statements look ridiculous, but it works and it follows the
same pattern as the '''lindex''' case above.  If subexpressions could be
evaluated directly by the enclosing '''expr''' operations, this would greatly
simplify the overall expression and make it more readable and thereby more
maintainable, and hopefully, less error prone.

The goal here is to reduce the instances of recursive '''expr''' calls in an
expression.  It seems overly complex and confusing to read, and to have to use
command substitution syntax inside what is already an '''expr''' operation.

~ Proposed Changes

The proposal is to simply apply normal Tcl command resolution rules to
'''expr''' functions.  The one caveat is that '''tcl::mathfunc''' namespace is
always searched first.

I see this as a continuation to [232].

~ Rejected Alternatives

This can already be accomplished today by creating alias functions in the
'''tcl::mathfunc''' namespace, but this mechanism is awkward in that:

 1. It must be defined beforehand for the set of commands used or intended to
    be used in expressions,

 2. For OO and namespace code, some specialized duplication is also required,
    and

 3. It can lead to confusion when it's not clear why some commands work as
    functions and others don't.

~ Proof of Concept

(Thanks and credit to Fr�d�ric Bonnet)

A quick & dirty proof of concept with unknown handlers:

|proc mathproc {cmd args} {
|    if {[namespace qualifiers $cmd] eq "tcl::mathfunc"} {
|        return [uplevel [list [namespace tail $cmd]] $args]
|    }

|    uplevel [list ::unknown $cmd] $args
|}

|namespace unknown mathproc
|
|set l [expr {list(1,2,3)}]
|=> 1 2 3
|
|expr {lindex($l,2)}
|=> 3
|
|expr {expr(join($l,"+"))}
|=> 6

~ Reference Implementation

None currently

~ Copyright

Copyright (c) 2012 by GriffinTk

This document is licensed under a Creative Commons Attribution-ShareAlike 3.0
Unported License [http://creativecommons.org/licenses/by-sa/3.0/deed.en_US].

<
|
<
|
|
|
|
|
|
|
>

|

|

|

|





|

|

|


|
|

|




|




|




|


|
|



|

|

|


|


|

|


|










|

|



|
|
|
<
>
|
<
>
|
|
|
|
|
|
|
|
|
|

|



|

|


|
>

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

# TIP 408: Allow Any Command for expr Functions

	Author:		Brian Griffin <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		Pending
	Created:	17-Aug-2012
	Post-History:	
	Tcl-Version:	8.7
-----

# Abstract

Proposed expansion of what constitutes a function in an **expr** expression.

# Rationale: Nested expr Calls

The **expr** command in Tcl is the only way to perform math and comparison
operations.  Tcl's variable and command substitution rules allow for great
flexibility, although the syntax does not lead to great readability,
especially due to the ordering imposed on substitutions. For example, in the
expression:

	 expr {[lindex $data $start] > 4}

the command substitution \([...]\) is performed before the expression can be
parsed for evaluation, and, in order for the command substitution to be
parsed, the variable substitution \($\) must be performed. The consequences of
this ordering means that arguments to commands cannot themselves be
expressions unless the argument is itself a command substitution involving
**expr**. This means, for example, that to compute an index value,
**expr** must be recursively called:

	 expr {[lindex $data [expr {$start + 2}]] > 4}

However, when using a math function, the command substitution ordering does
not apply since the function is part of the expression syntax:

	 expr {pow($x + 2, 2)}

It seems reasonable and useful if any Tcl command can be called using function
syntax:

	 expr {lindex($data, $start + 2) > 4}

The common command substitution pattern has lead many developers to end up
writing things like:

	 if {[expr {$a+$b}] > 7} ...

In hindsight, such statements look ridiculous, but it works and it follows the
same pattern as the **lindex** case above.  If subexpressions could be
evaluated directly by the enclosing **expr** operations, this would greatly
simplify the overall expression and make it more readable and thereby more
maintainable, and hopefully, less error prone.

The goal here is to reduce the instances of recursive **expr** calls in an
expression.  It seems overly complex and confusing to read, and to have to use
command substitution syntax inside what is already an **expr** operation.

# Proposed Changes

The proposal is to simply apply normal Tcl command resolution rules to
**expr** functions.  The one caveat is that **tcl::mathfunc** namespace is
always searched first.

I see this as a continuation to [[232]](232.md).

# Rejected Alternatives

This can already be accomplished today by creating alias functions in the
**tcl::mathfunc** namespace, but this mechanism is awkward in that:

 1. It must be defined beforehand for the set of commands used or intended to
    be used in expressions,

 2. For OO and namespace code, some specialized duplication is also required,
    and

 3. It can lead to confusion when it's not clear why some commands work as
    functions and others don't.

# Proof of Concept

\(Thanks and credit to Frédéric Bonnet\)

A quick & dirty proof of concept with unknown handlers:

	proc mathproc {cmd args} {
	    if {[namespace qualifiers $cmd] eq "tcl::mathfunc"} {
	        return [uplevel [list [namespace tail $cmd]] $args]

	    }
	    uplevel [list ::unknown $cmd] $args

	}
	namespace unknown mathproc
	
	set l [expr {list(1,2,3)}]
	=> 1 2 3
	
	expr {lindex($l,2)}
	=> 3
	
	expr {expr(join($l,"+"))}
	=> 6

# Reference Implementation

None currently

# Copyright

Copyright \(c\) 2012 by GriffinTk

This document is licensed under a Creative Commons Attribution-ShareAlike 3.0
Unported License <http://creativecommons.org/licenses/by-sa/3.0/deed.en_US> .

Name change from tip/409.tip to tip/409.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271

TIP:            409
Title:          UDP in Tcl
Version:        $Revision: 1.19 $
Author:         Alexandre Ferrieux <[email protected]>
Author:         Colin McCormack <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        17-Aug-2012
Post-History:   
Keywords:       udp,datagram,message
Obsoletes:      391
Tcl-Version:    8.7


~ Abstract

This TIP  adds support for UDP in  Tcl, with a pure  event approach to
packet  reception  (as  opposed  to  hijacking  the  existing  channel
infrastructure).

~ Rationale

UDP support  is a  long-awaited feature in  Tcl. Some  extensions have
traditionally supported it through the channel abstraction. This is of
course doable, but  there is a non-negligible cost  in both complexity
and  performance due  to the  impedance mismatch  between  the "fluid"
model  behind channels and  the "granular"  world of  datagrams (where
boundaries are significant).  Another  discrepancy is the existence of
(per-packet) metadata, like the source address  and port of an incoming UDP
packet, which do not fit nicely in the (per-connection) options of the
channel API (via '''fconfigure''').

Once this  mismatch is acknowledged, it  is easy to  identify a better
home for UDP in Tcl: let it  be a direct event source (for the receive
side), just like Tk or Snack.

Indeed, hooking a callback for  packet reception is a natural fit with
Tcl's event-driven  tradition, while preserving  packet boundaries and
easily exposing per-packet metadata.

Sending  is trivially  handled by  a direct  per-packet call  (but not
disguised as a '''puts''').  Again, this naturally allows for boundary
preservation and metadata specification.

This TIP asks for UDP-in-the core for two strong reasons:

 - it   enables   another   important   core
   feature:   asynchronous 
   (event-driven) DNS lookups

 - the C runtime supports it without extra libraries (unlike USB or 
   Bluetooth)

We then believe that the ubiquity of the need and the lack of external
dependencies justify  for UDP the  first-class status that  TCP enjoys
(regardless of the channel vs event models). Note that an acceptable compromise would be a bundled extension, ie distributed-with-the-core (in "pkgs/").

~ Specification

The new  '''udp''' ensemble hosts three subcommands: '''new''', '''create''', and '''names'''

 > '''udp new''' ?''options''?

 > '''udp create''' ''name'' ?''options''?

both create an UDP endpoint ;

 > '''udp names'''

returns the list of existing such endpoints.

~~ Lifecycle

Following the  traditions of  Tk and Snack,  '''udp new'''  and '''udp
create''' return  a Tcl command, which  takes subcommands implementing
the  needed  verbs.  By analogy  with the  corresponding  TclOO  constructors,

 * '''new'''   generates   the    command   name   internally,   in   the '''::tcl::udp''' namespace

 * '''create''' takes an extra ''name'' argument providing the target command name, either fully qualified, or relative to the current namespace.

 An UDP endpoint is thus created by:

|   set u [udp new ...]

or

|   udp create foo ...

 Once created, its configuration can be tweaked by:

 >  $u '''configure''' ''-option'' ''value''

and retrieved with

 >   set value [$u '''configure''' -''option'']

or 

 >   set fullconf [$u '''configure''']

To destroy the endpoint, use:

 >   $u '''destroy'''

or, as in Tk, destroy the command:

 >   '''rename''' $u {}

or the whole namespace.

~~ Status of options

Among options, a few may only be specified on creation:

 > - local interface+port

 > - (optional) connect() target's address+port

 > - reuse flag (described in Advanced Features)

while all the  other options may be specified  ''both'' on creation or
through [[$u configure]].

~~ Addresses and Ports

The first two creation-only options have the following syntax:

 > set u [['''udp new''' ?'''-local''' ''address_port''? ]]

 > set u [['''udp new''' ?'''-remote''' ''address_port''? ]]

where ''address_port'' pairs are represented as 2-element Tcl lists.

 > set address_port [[list $address $port]]

Addresses can be  given either as numeric IP (v4  or v6) addresses, or
as  hostnames; in  the latter  case, a  synchronous DNS  resolution is
performed before actual use, just like for '''socket'''.

In the case of '''-local''', $address can be specified as "*", meaning
INADDR_ANY, and  $port can be  0, asking for  the OS to select  a free
port. Thus a dynamic port on all interfaces can be requested with

|   set u [udp new -local [list * 0]]

In case of port 0, after creation of the endpoint, the actual port
chosen by the OS can be retrieved with [[$u configure]]:

|   puts "Local port is: [lindex [$u configure -local] 1]"

In  the case of  '''-remote''', both  address and  port must  be fully
specified.  The semantics, as is well known, is to tell the kernel (a)
to forbid  sending to  any other destination,  and (b) to  discard all
incoming packets sent by another source.

~~ Sending a Message

Sending is done, unsurprisingly, with the '''send''' verb:

 > $u '''send''' ''payload'' ?''dest_addr_port''?

where ''dest_addr_port'' is a pair as above.

Its  blocking  semantics is  that  of  the underlying  send()/sendto()
system calls:  it typically  returns immediately, though  the hardware
may buffer the data for some time, and delivery is not guaranteed. The
''payload''  is interpreted  as a  byte  array that  holds the  entire
content of the UDP message to send.

The destination parameter can be omitted if the endpoint has been created
with the '''-remote''' option (connected mode).

~~ Receiving a message asynchronously

Asynchronous (i.e. event-driven) message reception is done by specifying a listener callback to '''new/create''' or '''configure''':

 > $u '''configure -listener''' ''command_prefix''

Subsequently, when an incoming packet hits Tcl in the event loop, the
''command_prefix'' is called with the endpoint identifier, payload and
metadata:

 > {*}''command_prefix'' $u ''payload'' ''metadata_dict''

where  ''payload''  is   the  byte  array  of  the   UDP  payload  and ''metadata_dict'' is a dict containing at least two options:

 >   '''-remote''' ''address_port''

 >   '''-local''' ''address_port''

When read from options or  metadata, all address components apart from
"*" are returned in numeric form; no reverse DNS is ever performed.

Note  that ''-local''  may carry  more information  than  a configured
''-local'' where the address part  is "*", by identifying which of the
system's several interfaces was targeted.

Also note  that  ''command_prefix''  is  a single  command,  possibly  with
arguments, that  will be  expanded on invocation  (hence it must  be a
proper list);  it is  *not* an arbitrary  script as in  Tk's '''bind''
tradition.

When ''command_prefix'' is the empty  list (which is the default), the
notifier gives up  interest in the underlying UDP  socket; this allows
to  keep the  port  bound while  letting  the OS  buffer any  incoming
packets  (up  to  a   configurable  limit)  without  any  script-level
handling, while  leaving the  event loop active.   This is  similar to
setting a '''fileevent''' on a channel to the empty string.

~~ Receiving a message synchronously

Synchronous message reception is done with the '''recv''' verb:

 > set payload [$u '''recv''' ''metadata_dict_var'']

The payload is returned as a byte array, and the variable passed as argument receives the metadata dict just described.

~~ Advanced features

The following few verbs and options control extra IP features that are
typically useful in popular UDP applications like media streaming:

 > $u '''configure -sendbuffer''' ''buffersize''

 > $u '''configure -receivebuffer''' ''buffersize''

Set the OS's send (resp. receive) buffer sizes to the given values (in bytes).

 > $u '''join''' ''multiaddr'' ?'''-source''' ''sourceaddr''?

Joins the multicast group ''multiaddr'', optionally using IGMPv3's source
membership target ''sourceaddr''.

 > $u '''leave''' ''multiaddr'' ?'''-source''' ''sourceaddr''?

Leaves the same multicast group with or without source membership.

 > set u ['''udp new -reuse 1''']

Sets the SO_REUSEADDR socket option, so that multiple processes may bind to the same local port and interface, and receive the same packets. Creation-time only.

 > $u '''configure -ttl''' ''ttl''

Sets the TTL of subsequent outgoing packets. Some operating systems typically reduce the default TTL to one for multicast packets; this override may thus come in handy.

~ Rejected Alternatives

 * Token-based API (like for channels) instead of
   commands: would need  
   extra machinery (a new Tcl_ObjType). Moreover, the command style 
   gives reflection for free: a simple proc can emulate an UDP endpoint,   
   and is compatible with all OO schemes.

 * Address+Port pairs as dicts or
   urls: would hamper performance for no 
   added value

 * Listener as specific subcommand instead of
   option: R/W semantics is 
   actually that of an option; a subcommand would preclude the direct 
   specification of the listener on creation ; analogy with the -command 
   of '''fcopy''', '''http''', or Tk widgets. 

~ Sources of Inspiration

This TIP builds on experience with previous attempts at UDP extensions: TclUDP, ceptcl, Duft, along with intensive practice with unpublished work, and borrows ideas from all of them.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|


|
|

|





|
|
|
|
|


|
|





|
|






|

|
|



|

|

|

|

|



|



|

|
|


|

|



|



|



|



|



|



|



|



|



|

|

|

|
|

|



|

|

|

|

|

|

|
|


|


|

|

|
|
|


|

|

|

|

|


|



|

|

|

|


|


|

|

|

|


|

|
|


|
|
|


|


|

|

|

|

|



|




|

|

|

|

|
|

|



|

|

|



|

|

|



|







|

|



|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271

# TIP 409: UDP in Tcl

	Author:         Alexandre Ferrieux <[email protected]>
	Author:         Colin McCormack <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        17-Aug-2012
	Post-History:   
	Keywords:       udp,datagram,message
	Obsoletes:      391
	Tcl-Version:    8.7
-----

# Abstract

This TIP  adds support for UDP in  Tcl, with a pure  event approach to
packet  reception  \(as  opposed  to  hijacking  the  existing  channel
infrastructure\).

# Rationale

UDP support  is a  long-awaited feature in  Tcl. Some  extensions have
traditionally supported it through the channel abstraction. This is of
course doable, but  there is a non-negligible cost  in both complexity
and  performance due  to the  impedance mismatch  between  the "fluid"
model  behind channels and  the "granular"  world of  datagrams \(where
boundaries are significant\).  Another  discrepancy is the existence of
\(per-packet\) metadata, like the source address  and port of an incoming UDP
packet, which do not fit nicely in the \(per-connection\) options of the
channel API \(via **fconfigure**\).

Once this  mismatch is acknowledged, it  is easy to  identify a better
home for UDP in Tcl: let it  be a direct event source \(for the receive
side\), just like Tk or Snack.

Indeed, hooking a callback for  packet reception is a natural fit with
Tcl's event-driven  tradition, while preserving  packet boundaries and
easily exposing per-packet metadata.

Sending  is trivially  handled by  a direct  per-packet call  \(but not
disguised as a **puts**\).  Again, this naturally allows for boundary
preservation and metadata specification.

This TIP asks for UDP-in-the core for two strong reasons:

 - it   enables   another   important   core
   feature:   asynchronous 
   \(event-driven\) DNS lookups

 - the C runtime supports it without extra libraries \(unlike USB or 
   Bluetooth\)

We then believe that the ubiquity of the need and the lack of external
dependencies justify  for UDP the  first-class status that  TCP enjoys
\(regardless of the channel vs event models\). Note that an acceptable compromise would be a bundled extension, ie distributed-with-the-core \(in "pkgs/"\).

# Specification

The new  **udp** ensemble hosts three subcommands: **new**, **create**, and **names**

 > **udp new** ?_options_?

 > **udp create** _name_ ?_options_?

both create an UDP endpoint ;

 > **udp names**

returns the list of existing such endpoints.

## Lifecycle

Following the  traditions of  Tk and Snack,  **udp new**  and **udp
create** return  a Tcl command, which  takes subcommands implementing
the  needed  verbs.  By analogy  with the  corresponding  TclOO  constructors,

 * **new**   generates   the    command   name   internally,   in   the **::tcl::udp** namespace

 * **create** takes an extra _name_ argument providing the target command name, either fully qualified, or relative to the current namespace.

 An UDP endpoint is thus created by:

		   set u [udp new ...]

or

	   udp create foo ...

 Once created, its configuration can be tweaked by:

 >  $u **configure** _-option_ _value_

and retrieved with

 >   set value [$u **configure** -_option_]

or 

 >   set fullconf [$u **configure**]

To destroy the endpoint, use:

 >   $u **destroy**

or, as in Tk, destroy the command:

 >   **rename** $u \{\}

or the whole namespace.

## Status of options

Among options, a few may only be specified on creation:

 > - local interface\+port

 > - \(optional\) connect\(\) target's address\+port

 > - reuse flag \(described in Advanced Features\)

while all the  other options may be specified  _both_ on creation or
through [$u configure].

## Addresses and Ports

The first two creation-only options have the following syntax:

 > set u [**udp new** ?**-local** _address_port_? ]

 > set u [**udp new** ?**-remote** _address_port_? ]

where _address\_port_ pairs are represented as 2-element Tcl lists.

 > set address\_port [list $address $port]

Addresses can be  given either as numeric IP \(v4  or v6\) addresses, or
as  hostnames; in  the latter  case, a  synchronous DNS  resolution is
performed before actual use, just like for **socket**.

In the case of **-local**, $address can be specified as "\*", meaning
INADDR\_ANY, and  $port can be  0, asking for  the OS to select  a free
port. Thus a dynamic port on all interfaces can be requested with

	   set u [udp new -local [list * 0]]

In case of port 0, after creation of the endpoint, the actual port
chosen by the OS can be retrieved with [$u configure]:

	   puts "Local port is: [lindex [$u configure -local] 1]"

In  the case of  **-remote**, both  address and  port must  be fully
specified.  The semantics, as is well known, is to tell the kernel \(a\)
to forbid  sending to  any other destination,  and \(b\) to  discard all
incoming packets sent by another source.

## Sending a Message

Sending is done, unsurprisingly, with the **send** verb:

 > $u **send** _payload_ ?_dest\_addr\_port_?

where _dest\_addr\_port_ is a pair as above.

Its  blocking  semantics is  that  of  the underlying  send\(\)/sendto\(\)
system calls:  it typically  returns immediately, though  the hardware
may buffer the data for some time, and delivery is not guaranteed. The
_payload_  is interpreted  as a  byte  array that  holds the  entire
content of the UDP message to send.

The destination parameter can be omitted if the endpoint has been created
with the **-remote** option \(connected mode\).

## Receiving a message asynchronously

Asynchronous \(i.e. event-driven\) message reception is done by specifying a listener callback to **new/create** or **configure**:

 > $u **configure -listener** _command\_prefix_

Subsequently, when an incoming packet hits Tcl in the event loop, the
_command\_prefix_ is called with the endpoint identifier, payload and
metadata:

 > \{\*\}_command\_prefix_ $u _payload_ _metadata\_dict_

where  _payload_  is   the  byte  array  of  the   UDP  payload  and _metadata\_dict_ is a dict containing at least two options:

 >   **-remote** _address\_port_

 >   **-local** _address\_port_

When read from options or  metadata, all address components apart from
"\*" are returned in numeric form; no reverse DNS is ever performed.

Note  that _-local_  may carry  more information  than  a configured
_-local_ where the address part  is "\*", by identifying which of the
system's several interfaces was targeted.

Also note  that  _command\_prefix_  is  a single  command,  possibly  with
arguments, that  will be  expanded on invocation  \(hence it must  be a
proper list\);  it is  \*not\* an arbitrary  script as in  Tk's **bind_
tradition.

When _command\_prefix_ is the empty  list \(which is the default\), the
notifier gives up  interest in the underlying UDP  socket; this allows
to  keep the  port  bound while  letting  the OS  buffer any  incoming
packets  \(up  to  a   configurable  limit\)  without  any  script-level
handling, while  leaving the  event loop active.   This is  similar to
setting a **fileevent** on a channel to the empty string.

## Receiving a message synchronously

Synchronous message reception is done with the **recv** verb:

 > set payload [$u **recv** _metadata_dict_var_]

The payload is returned as a byte array, and the variable passed as argument receives the metadata dict just described.

## Advanced features

The following few verbs and options control extra IP features that are
typically useful in popular UDP applications like media streaming:

 > $u **configure -sendbuffer** _buffersize_

 > $u **configure -receivebuffer** _buffersize_

Set the OS's send \(resp. receive\) buffer sizes to the given values \(in bytes\).

 > $u **join** _multiaddr_ ?**-source** _sourceaddr_?

Joins the multicast group _multiaddr_, optionally using IGMPv3's source
membership target _sourceaddr_.

 > $u **leave** _multiaddr_ ?**-source** _sourceaddr_?

Leaves the same multicast group with or without source membership.

 > set u [**udp new -reuse 1**]

Sets the SO\_REUSEADDR socket option, so that multiple processes may bind to the same local port and interface, and receive the same packets. Creation-time only.

 > $u **configure -ttl** _ttl_

Sets the TTL of subsequent outgoing packets. Some operating systems typically reduce the default TTL to one for multicast packets; this override may thus come in handy.

# Rejected Alternatives

 * Token-based API \(like for channels\) instead of
   commands: would need  
   extra machinery \(a new Tcl\_ObjType\). Moreover, the command style 
   gives reflection for free: a simple proc can emulate an UDP endpoint,   
   and is compatible with all OO schemes.

 * Address\+Port pairs as dicts or
   urls: would hamper performance for no 
   added value

 * Listener as specific subcommand instead of
   option: R/W semantics is 
   actually that of an option; a subcommand would preclude the direct 
   specification of the listener on creation ; analogy with the -command 
   of **fcopy**, **http**, or Tk widgets. 

# Sources of Inspiration

This TIP builds on experience with previous attempts at UDP extensions: TclUDP, ceptcl, Duft, along with intensive practice with unpublished work, and borrows ideas from all of them.

# Copyright

This document has been placed in the public domain.

Name change from tip/41.tip to tip/41.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
TIP:            41
Title:          Paned Window Tk Widget
Version:        $Revision: 1.13 $
Author:         Eric Melski <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        04-Jul-2001
Post-History:   
Keywords:       widget,tk,panedwindow
Tcl-Version:    8.4a2


~ Abstract

This TIP proposes a C-based paned window widget for inclusion in the
Tk core.  A paned window consists of one or more vertical or
horizontal "panes", each pair separated by a movable "sash" and each
containing one widget, called a "slave".  Paned windows are common in
modern graphical user interfaces and should therefore be provided
directly by the Tk core.  Examples of the widget can be found in
Windows Explorer; Netscape Messenger; many email clients; and
virtually every graphical World Wide Web browser.

~ Rationale

Tk has long lagged other graphical toolkits in terms of the selection
of widgets provided by the toolkit.  In order to keep Tk vibrant,
useful, and relevant, it is imperative that the widget set be enhanced
with widgets which have become commonplace in modern graphical user
interfaces.  One such widget is the paned window widget.  A widget
that makes it easy to create robust paned windows should be included
with Tk.

This paned window widget could be implemented in C or in Tcl; in fact,
several Tcl-based paned window widgets already exist.  However, these
each have quirks, mostly caused by the inability to completely manage
the geometry of Tk windows from Tcl (i.e. there is no way to make
calls to things like ''Tk_MaintainGeometry'' or
''Tk_ManageGeometry'').  This issue could possibly be addressed by the
creation of a proper megawidget system for Tk, but that goal seems
very far from reality right now.  If we wait for that system before
creating new widgets, it may be too late.  In addition, megawidget
implementations suffer from "widget bloat" - each paned window widget
corresponds to, typically two widgets, plus two or more widgets for
each pane after the first.  For a Motif-style paned window with two
panes, this means five widgets are created (one frame for the paned
window container widget; one frame for each pane; one frame for the
sash; one frame for the sash handle).  Even assuming the existence of
a proper megawidget system, we may not be able to address the widget
bloat issue with a megawidget.

A C-based paned window implementation will be able to address both of
these issues, and should be more robust, reliable, and lightweight.  A
C implementation will be able to access Tk's geometry management
functions.  Also, it will require only one widget for each paned window,
<
|
<
|
|
|
|
|
|
|
|
>

|










|












|
|
|






|

|








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

# TIP 41: Paned Window Tk Widget

	Author:         Eric Melski <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        04-Jul-2001
	Post-History:   
	Keywords:       widget,tk,panedwindow
	Tcl-Version:    8.4a2
-----

# Abstract

This TIP proposes a C-based paned window widget for inclusion in the
Tk core.  A paned window consists of one or more vertical or
horizontal "panes", each pair separated by a movable "sash" and each
containing one widget, called a "slave".  Paned windows are common in
modern graphical user interfaces and should therefore be provided
directly by the Tk core.  Examples of the widget can be found in
Windows Explorer; Netscape Messenger; many email clients; and
virtually every graphical World Wide Web browser.

# Rationale

Tk has long lagged other graphical toolkits in terms of the selection
of widgets provided by the toolkit.  In order to keep Tk vibrant,
useful, and relevant, it is imperative that the widget set be enhanced
with widgets which have become commonplace in modern graphical user
interfaces.  One such widget is the paned window widget.  A widget
that makes it easy to create robust paned windows should be included
with Tk.

This paned window widget could be implemented in C or in Tcl; in fact,
several Tcl-based paned window widgets already exist.  However, these
each have quirks, mostly caused by the inability to completely manage
the geometry of Tk windows from Tcl \(i.e. there is no way to make
calls to things like _Tk\_MaintainGeometry_ or
_Tk\_ManageGeometry_\).  This issue could possibly be addressed by the
creation of a proper megawidget system for Tk, but that goal seems
very far from reality right now.  If we wait for that system before
creating new widgets, it may be too late.  In addition, megawidget
implementations suffer from "widget bloat" - each paned window widget
corresponds to, typically two widgets, plus two or more widgets for
each pane after the first.  For a Motif-style paned window with two
panes, this means five widgets are created \(one frame for the paned
window container widget; one frame for each pane; one frame for the
sash; one frame for the sash handle\).  Even assuming the existence of
a proper megawidget system, we may not be able to address the widget
bloat issue with a megawidget.

A C-based paned window implementation will be able to address both of
these issues, and should be more robust, reliable, and lightweight.  A
C implementation will be able to access Tk's geometry management
functions.  Also, it will require only one widget for each paned window,
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418

introduction of a proper "Batteries Included" distribution, but like
the proper megawidget system, this seems like a goal far from reality
at this time.

Another possibility is to distribute the widget with the core, but have it placed in a separate package and namespace.  This provides the same level of availability as direct inclusion in the core, but does not actually make the widget part of Tk directly.  There are two possible arguments in favor of this approach.  First, since this widget will be in its own namespace, future panedwindow widgets could be included without name conflicts.  However, if each widget is put in its own namespace, the name conflict has not actually been resolved.  The point of contention has simply been moved from the global command space to the global namespace space.  Namespaces make sense when grouping blocks of related functions and data, but widgets have only one command.  It's just as easy to pick a unique command name as a unique namespace name.  The second possible advantage is that the widget could be loaded on demand, rather than automatically being pulled in with Tk.  However, most machines that Tk runs on use a virtual memory system.  Thus, 
only those pages/widgets that are actually used will be resident in memory.  The benefit of incorporating this widget into the Tk distribution in this manner seem marginal.

#image:41example Example Panedwindow Widget

~ Specification

The manual entry for the paned window widget is included here:

|NAME
|       panedwindow - Create and manipulate panedwindow widgets
|
|SYNOPSIS
|       panedwindow pathName ?options?
|
|STANDARD OPTIONS
|       -background           -height              -width
|       -borderwidth          -orient
|       -cursor               -relief
|
|       See  the  options manual entry for details on the standard
|       options.
|
|WIDGET-SPECIFIC OPTIONS
|       Command-Line Name:-handlepad
|       Database Name:  handlePad
|       Database Class: HandlePad
|
|              When sash handles are drawn, specifies the distance
|              from  the top or left end of the sash (depending on
|              the orientation of the widget) at which to draw the
|              handle.  May be any value accepted by Tk_GetPixels.
|
|       Command-Line Name:-handlesize
|       Database Name:  handleSize
|       Database Class: HandleSize
|
|              Specifies the side length of a sash  handle.   Han-
|              dles are always drawn as squares.  May be any value
|              accepted by Tk_GetPixels.
|
|       Command-Line Name:-opaqueresize
|       Database Name:  opaqueResize
|       Database Class: OpaqueResize
|
|              Specifies whether panes should be resized as a sash
|              is  moved (true), or if resizing should be deferred
|              until the sash is placed (false).
|
|       Command-Line Name:-sashcursor
|       Database Name:  sashCursor
|       Database Class: SashCursor
|
|              Mouse cursor to use when over  a  sash.   If  null,
|              sb_h_double_arrow   will  be  used  for  horizontal
|              panedwindows, and sb_v_double_arrow  will  be  used
|              for vertical panedwindows.
|
|       Command-Line Name:-sashpad
|       Database Name:  sashPad
|       Database Class: SashPad
|
|              Specifies  the  amount  of padding to leave of each
|              side of a sash.   May  be  any  value  accepted  by
|              Tk_GetPixels.
|
|       Command-Line Name:-sashrelief
|       Database Name:  sashRelief
|       Database Class: SashRelief
|
|              Relief  to  use when drawing a sash.  May be any of
|              the standard Tk relief values.
|
|       Command-Line Name:-sashwidth
|       Database Name:  sashWidth
|       Database Class: SashWidth
|
|              Specifies the width of each sash.  May be any value
|              accepted by Tk_GetPixels.
|
|       Command-Line Name:-showhandle
|       Database Name:  showHandle
|       Database Class: ShowHandle
|
|              Specifies whether or not sash handles should be shown.
|              May be any valid Tcl boolean value.
|
|DESCRIPTION
|       The panedwindow command creates a new window (given by the
|       pathName argument) and makes it into a panedwindow widget.
|       Additional  options,  described above, may be specified on
|       the command line or in the option  database  to  configure
|       aspects  of the panedwindow such as its default background
|       color and relief.  The  panedwindow  command  returns  the
|       path name of the new window.
|
|       A   panedwindow  widget  contains  any  number  of  panes,
|       arranged horizontally  or  vertically,  according  to  the
|       value  of the -orient option.  Each pane contains one wid-
|       get, and each pair of panes is  separated  by  a  moveable
|       (via mouse movements) sash.  Moving a sash causes the wid-
|       gets on either side of the sash to be resized.
|
|WIDGET COMMAND
|       The panedwindow command creates a new  Tcl  command  whose
|       name  is  the  same  as the path name of the panedwindow's
|       window.  This command may be used to invoke various opera-
|       tions on the widget.  It has the following general form:
|              pathName option ?arg arg ...?
|       PathName  is the name of the command, which is the same as
|       the panedwindow widget's path name.  Option and  the  args
|       determine  the exact behavior of the command.  The follow-
|       ing commands are possible for panedwindow widgets:
|
|       pathName add slave ?slave ...? ?option value ...?
|              Add one or more slaves to the panedwindow, each  in
|              a  separate  pane.   The  arguments  consist of the
|              names of one or  more  slave  windows  followed  by
|              pairs  of  arguments that specify how to manage the
|              slaves.  Option may have any of the values accepted
|              by the configure subcommand.
|
|       pathName cget option
|              Returns  the  current  value  of  the configuration
|              option given by option.  Option may have any of the
|              values accepted by the panedwindow command.
|
|       pathName configure ?option? ?value option value ...?
|              Query  or  modify  the configuration options of the
|              widget.  If no option is specified, returns a  list
|              describing  all  of the available options for path-
|              Name (see Tk_ConfigureInfo for information  on  the
|              format  of this list).  If option is specified with
|              no value, then the command returns a list  describ-
|              ing the one named option (this list will be identi-
|              cal to  the  corresponding  sublist  of  the  value
|              returned  if  no  option  is specified).  If one or
|              more option-value pairs  are  specified,  then  the
|              command modifies the given widget option(s) to have
|              the given  value(s);   in  this  case  the  command
|              returns an empty string. Option may have any of the
|              values accepted by the panedwindow command.
|
|       pathName forget slave ?slave ...?
|              Remove the pane containing slave from the panedwin-
|              dow.   All  geometry  management  options for slave
|              will be forgotten.
|
|       pathName identify x y
|              Identify the panedwindow component  underneath  the
|              point  given by x and y, in window coordinates.  If
|              the point is over a sash  or  a  sash  handle,  the
|              result  is  a two element list containing the index
|              of the  sash  or  handle,  and  a  word  indicating
|              whether  it  is over a sash or a handle, such as {0
|              sash} or {2 handle}.  If  the  point  is  over  any
|              other  part  of  the  panedwindow, the result is an
|              empty list.
|
|       pathName proxy ?args?
|              This command is used to query and change the  posi-
|              tion  of  the sash proxy, used for rubberband-style
|              pane resizing. It can take  any  of  the  following
|              forms:
|
|              pathName proxy coord
|                     Return a list containing the x and y coordi-
|                     nates of the most recent proxy location.
|
|              pathname proxy forget
|                     Remove the proxy from the display.
|
|              pathName proxy place x y
|                     Place  the  proxy  at  the  given  x  and  y
|                     coordinates.
|
|       pathName sash ?args?
|              This  command is used to query and change the posi-
|              tion of sashes in the panedwindow.  It can take any
|              of the following forms:
|
|              pathName sash coord index
|                     Return  the  current x and y coordinate pair
|                     for the sash given by index.  Index must  be
|                     an  integer  between  0  and 1 less than the
|                     number of slaves in  the  panedwindow.   The
|                     coordinates  given are those of the top left
|                     corner of the region  containing  the  sash.
|                     pathName  sash dragto index x y This command
|                     computes the difference  between  the  given
|                     coordinates and the coordinates given to the
|                     last sash coord command for the given  sash.
|                     It then moves that sash the computed differ-
|                     ence.  The return value is the empty string.
|
|              pathName sash mark index x y
|                     Records x and y for the sash given by index;
|                     used in conjunction with later  dragto  com-
|                     mands to move the sash.
|
|              pathName sash place index x y
|                     Place  the  sash given by index at the given
|                     coordinates.
|
|       pathName slavecget slave option
|              Query a management option for slave.  Option may be
|              any value allowed by the slaveconfigure subcommand.
|
|       pathName slaveconfigure slave ?option? ?value option value
|       ...?
|              Query  or  modify the management options for slave.
|              If no option is specified, returns a list  describ-
|              ing  all of the available options for pathName (see
|              Tk_ConfigureInfo for information on the  format  of
|              this  list).  If option is specified with no value,
|              then the command returns a list describing the  one
|              named  option  (this  list will be identical to the
|              corresponding sublist of the value returned  if  no
|              option  is specified).  If one or more option-value
|              pairs are specified, then the command modifies  the
|              given  widget option(s) to have the given value(s);
|              in this case the command returns an  empty  string.
|              The following options are supported:
|
|              -after slave
|                     Insert  the slave after the slave specified.
|                     slave should be the name of a window already
|                     managed by pathName.
|
|              -before slave
|                     Insert the slave before the slave specified.
|                     slave should be the name of a window already
|                     managed by pathName.
|
|              -height size
|                     Specify  a height for the slave.  The height
|                     will be the outer  dimension  of  the  slave
|                     including its border, if any.  If size is an
|                     empty string, or if -height  is  not  speci-
|                     fied,  then  the height requested internally
|                     by the slave will  be  used  initially;  the
|                     height may later be adjusted by the movement
|                     of sashes in the panedwindow.  Size  may  be
|                     any value accepted by Tk_GetPixels.
|
|              -minsize n
|                     Specifies  that the size of the slave cannot
|                     be made less than n.  This  constraint  only
|                     affects  the size of the widget in the paned
|                     dimension -- the x dimension for  horizontal
|                     panedwindows,  the  y dimension for vertical
|                     panedwindows.  May be any value accepted  by
|                     Tk_GetPixels.
|
|              -padx n
|                     Specifies  a  non-negative  value indicating
|                     how much extra space to leave on  each  side
|                     of  the slave in the X-direction.  The value
|                     may  have  any  of  the  forms  accepted  by
|                     Tk_GetPixels.
|
|              -pady n
|                     Specifies  a  non-negative  value indicating
|                     how much extra space to leave on  each  side
|                     of  the slave in the Y-direction.  The value
|                     may  have  any  of  the  forms  accepted  by
|                     Tk_GetPixels.
|
|              -sticky style
|                     If   a  slave's  pane  is  larger  than  the
|                     requested  dimensions  of  the  slave,  this
|                     option  may be used to position (or stretch)
|                     the slave within  its  pane.   Style   is  a
|                     string  that  contains  zero  or more of the
|                     characters n, s, e or  w.   The  string  can
|                     optionally  contains  spaces  or commas, but
|                     they are ignored.  Each letter refers  to  a
|                     side  (north, south, east, or west) that the
|                     slave will "stick" to.  If both n and s  (or
|                     e  and  w)  are specified, the slave will be
|                     stretched to  fill  the  entire  height  (or
|                     width) of its cavity.
|
|              -width size
|                     Specify  a  width  for the slave.  The width
|                     will be the outer  dimension  of  the  slave
|                     including its border, if any.  If size is an
|                     empty string, or if -width is not specified,
|                     then  the  width requested internally by the
|                     slave will be used initially; the width  may
|                     later  be adjusted by the movement of sashes
|                     in the panedwindow.  Size may be  any  value
|                     accepted by Tk_GetPixels.
|
|       pathName slaves
|              Returns  an  ordered list of the widgets managed by
|              pathName.
|
|
|RESIZING PANES
|       A pane is resized by grabbing the sash (or sash handle  if
|       present)  and  dragging  with  the  mouse.  This is accom-
|       plished via mouse motion bindings on the widget.   When  a
|       sash  is moved, the sizes of the panes on each side of the
|       sash, and thus the widgets in those panes, are adjusted.
|
|       When a pane is resized from outside (eg, it is  packed  to
|       expand  and fill, and the containing toplevel is resized),
|       space is added to the final (rightmost or bottommost) pane
|       in the window.

~ Reference Implementation

The widget described here has already been implemented, with
documentation and a full test suite.  The widget is included with the
Vu widget extension, part of the ''tktable'' SourceForge project at
http://tktable.sourceforge.net

~ Notes

Suggestions for possible future enhancements:

 * Allow specification of a weight for each pane, similar to the -weight option supported by
grid, to be used when allocating space from a resize to panes in the
widget.

 * Allow a bindable image to be placed on the window sash, a la 
Netscape's Messenger, or Java Swing, to allow one-click expand and
collapse of the pane.

 * Integrate with the -setgrid option such that if a pane contains
a -setgrided widget, the sash can only be moved in grid size steps.

None of these are prohibited by the current design, and could be 
implemented at a later date as enhancements to the widget.

~ Copyright

This document has been placed in the public domain.








|

|



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|



|
|

|

















|


>
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
introduction of a proper "Batteries Included" distribution, but like
the proper megawidget system, this seems like a goal far from reality
at this time.

Another possibility is to distribute the widget with the core, but have it placed in a separate package and namespace.  This provides the same level of availability as direct inclusion in the core, but does not actually make the widget part of Tk directly.  There are two possible arguments in favor of this approach.  First, since this widget will be in its own namespace, future panedwindow widgets could be included without name conflicts.  However, if each widget is put in its own namespace, the name conflict has not actually been resolved.  The point of contention has simply been moved from the global command space to the global namespace space.  Namespaces make sense when grouping blocks of related functions and data, but widgets have only one command.  It's just as easy to pick a unique command name as a unique namespace name.  The second possible advantage is that the widget could be loaded on demand, rather than automatically being pulled in with Tk.  However, most machines that Tk runs on use a virtual memory system.  Thus, 
only those pages/widgets that are actually used will be resident in memory.  The benefit of incorporating this widget into the Tk distribution in this manner seem marginal.

![Example Panedwindow Widget](../assets/41example.png)

# Specification

The manual entry for the paned window widget is included here:

	NAME
	       panedwindow - Create and manipulate panedwindow widgets
	
	SYNOPSIS
	       panedwindow pathName ?options?
	
	STANDARD OPTIONS
	       -background           -height              -width
	       -borderwidth          -orient
	       -cursor               -relief
	
	       See  the  options manual entry for details on the standard
	       options.
	
	WIDGET-SPECIFIC OPTIONS
	       Command-Line Name:-handlepad
	       Database Name:  handlePad
	       Database Class: HandlePad
	
	              When sash handles are drawn, specifies the distance
	              from  the top or left end of the sash (depending on
	              the orientation of the widget) at which to draw the
	              handle.  May be any value accepted by Tk_GetPixels.
	
	       Command-Line Name:-handlesize
	       Database Name:  handleSize
	       Database Class: HandleSize
	
	              Specifies the side length of a sash  handle.   Han-
	              dles are always drawn as squares.  May be any value
	              accepted by Tk_GetPixels.
	
	       Command-Line Name:-opaqueresize
	       Database Name:  opaqueResize
	       Database Class: OpaqueResize
	
	              Specifies whether panes should be resized as a sash
	              is  moved (true), or if resizing should be deferred
	              until the sash is placed (false).
	
	       Command-Line Name:-sashcursor
	       Database Name:  sashCursor
	       Database Class: SashCursor
	
	              Mouse cursor to use when over  a  sash.   If  null,
	              sb_h_double_arrow   will  be  used  for  horizontal
	              panedwindows, and sb_v_double_arrow  will  be  used
	              for vertical panedwindows.
	
	       Command-Line Name:-sashpad
	       Database Name:  sashPad
	       Database Class: SashPad
	
	              Specifies  the  amount  of padding to leave of each
	              side of a sash.   May  be  any  value  accepted  by
	              Tk_GetPixels.
	
	       Command-Line Name:-sashrelief
	       Database Name:  sashRelief
	       Database Class: SashRelief
	
	              Relief  to  use when drawing a sash.  May be any of
	              the standard Tk relief values.
	
	       Command-Line Name:-sashwidth
	       Database Name:  sashWidth
	       Database Class: SashWidth
	
	              Specifies the width of each sash.  May be any value
	              accepted by Tk_GetPixels.
	
	       Command-Line Name:-showhandle
	       Database Name:  showHandle
	       Database Class: ShowHandle
	
	              Specifies whether or not sash handles should be shown.
	              May be any valid Tcl boolean value.
	
	DESCRIPTION
	       The panedwindow command creates a new window (given by the
	       pathName argument) and makes it into a panedwindow widget.
	       Additional  options,  described above, may be specified on
	       the command line or in the option  database  to  configure
	       aspects  of the panedwindow such as its default background
	       color and relief.  The  panedwindow  command  returns  the
	       path name of the new window.
	
	       A   panedwindow  widget  contains  any  number  of  panes,
	       arranged horizontally  or  vertically,  according  to  the
	       value  of the -orient option.  Each pane contains one wid-
	       get, and each pair of panes is  separated  by  a  moveable
	       (via mouse movements) sash.  Moving a sash causes the wid-
	       gets on either side of the sash to be resized.
	
	WIDGET COMMAND
	       The panedwindow command creates a new  Tcl  command  whose
	       name  is  the  same  as the path name of the panedwindow's
	       window.  This command may be used to invoke various opera-
	       tions on the widget.  It has the following general form:
	              pathName option ?arg arg ...?
	       PathName  is the name of the command, which is the same as
	       the panedwindow widget's path name.  Option and  the  args
	       determine  the exact behavior of the command.  The follow-
	       ing commands are possible for panedwindow widgets:
	
	       pathName add slave ?slave ...? ?option value ...?
	              Add one or more slaves to the panedwindow, each  in
	              a  separate  pane.   The  arguments  consist of the
	              names of one or  more  slave  windows  followed  by
	              pairs  of  arguments that specify how to manage the
	              slaves.  Option may have any of the values accepted
	              by the configure subcommand.
	
	       pathName cget option
	              Returns  the  current  value  of  the configuration
	              option given by option.  Option may have any of the
	              values accepted by the panedwindow command.
	
	       pathName configure ?option? ?value option value ...?
	              Query  or  modify  the configuration options of the
	              widget.  If no option is specified, returns a  list
	              describing  all  of the available options for path-
	              Name (see Tk_ConfigureInfo for information  on  the
	              format  of this list).  If option is specified with
	              no value, then the command returns a list  describ-
	              ing the one named option (this list will be identi-
	              cal to  the  corresponding  sublist  of  the  value
	              returned  if  no  option  is specified).  If one or
	              more option-value pairs  are  specified,  then  the
	              command modifies the given widget option(s) to have
	              the given  value(s);   in  this  case  the  command
	              returns an empty string. Option may have any of the
	              values accepted by the panedwindow command.
	
	       pathName forget slave ?slave ...?
	              Remove the pane containing slave from the panedwin-
	              dow.   All  geometry  management  options for slave
	              will be forgotten.
	
	       pathName identify x y
	              Identify the panedwindow component  underneath  the
	              point  given by x and y, in window coordinates.  If
	              the point is over a sash  or  a  sash  handle,  the
	              result  is  a two element list containing the index
	              of the  sash  or  handle,  and  a  word  indicating
	              whether  it  is over a sash or a handle, such as {0
	              sash} or {2 handle}.  If  the  point  is  over  any
	              other  part  of  the  panedwindow, the result is an
	              empty list.
	
	       pathName proxy ?args?
	              This command is used to query and change the  posi-
	              tion  of  the sash proxy, used for rubberband-style
	              pane resizing. It can take  any  of  the  following
	              forms:
	
	              pathName proxy coord
	                     Return a list containing the x and y coordi-
	                     nates of the most recent proxy location.
	
	              pathname proxy forget
	                     Remove the proxy from the display.
	
	              pathName proxy place x y
	                     Place  the  proxy  at  the  given  x  and  y
	                     coordinates.
	
	       pathName sash ?args?
	              This  command is used to query and change the posi-
	              tion of sashes in the panedwindow.  It can take any
	              of the following forms:
	
	              pathName sash coord index
	                     Return  the  current x and y coordinate pair
	                     for the sash given by index.  Index must  be
	                     an  integer  between  0  and 1 less than the
	                     number of slaves in  the  panedwindow.   The
	                     coordinates  given are those of the top left
	                     corner of the region  containing  the  sash.
	                     pathName  sash dragto index x y This command
	                     computes the difference  between  the  given
	                     coordinates and the coordinates given to the
	                     last sash coord command for the given  sash.
	                     It then moves that sash the computed differ-
	                     ence.  The return value is the empty string.
	
	              pathName sash mark index x y
	                     Records x and y for the sash given by index;
	                     used in conjunction with later  dragto  com-
	                     mands to move the sash.
	
	              pathName sash place index x y
	                     Place  the  sash given by index at the given
	                     coordinates.
	
	       pathName slavecget slave option
	              Query a management option for slave.  Option may be
	              any value allowed by the slaveconfigure subcommand.
	
	       pathName slaveconfigure slave ?option? ?value option value
	       ...?
	              Query  or  modify the management options for slave.
	              If no option is specified, returns a list  describ-
	              ing  all of the available options for pathName (see
	              Tk_ConfigureInfo for information on the  format  of
	              this  list).  If option is specified with no value,
	              then the command returns a list describing the  one
	              named  option  (this  list will be identical to the
	              corresponding sublist of the value returned  if  no
	              option  is specified).  If one or more option-value
	              pairs are specified, then the command modifies  the
	              given  widget option(s) to have the given value(s);
	              in this case the command returns an  empty  string.
	              The following options are supported:
	
	              -after slave
	                     Insert  the slave after the slave specified.
	                     slave should be the name of a window already
	                     managed by pathName.
	
	              -before slave
	                     Insert the slave before the slave specified.
	                     slave should be the name of a window already
	                     managed by pathName.
	
	              -height size
	                     Specify  a height for the slave.  The height
	                     will be the outer  dimension  of  the  slave
	                     including its border, if any.  If size is an
	                     empty string, or if -height  is  not  speci-
	                     fied,  then  the height requested internally
	                     by the slave will  be  used  initially;  the
	                     height may later be adjusted by the movement
	                     of sashes in the panedwindow.  Size  may  be
	                     any value accepted by Tk_GetPixels.
	
	              -minsize n
	                     Specifies  that the size of the slave cannot
	                     be made less than n.  This  constraint  only
	                     affects  the size of the widget in the paned
	                     dimension -- the x dimension for  horizontal
	                     panedwindows,  the  y dimension for vertical
	                     panedwindows.  May be any value accepted  by
	                     Tk_GetPixels.
	
	              -padx n
	                     Specifies  a  non-negative  value indicating
	                     how much extra space to leave on  each  side
	                     of  the slave in the X-direction.  The value
	                     may  have  any  of  the  forms  accepted  by
	                     Tk_GetPixels.
	
	              -pady n
	                     Specifies  a  non-negative  value indicating
	                     how much extra space to leave on  each  side
	                     of  the slave in the Y-direction.  The value
	                     may  have  any  of  the  forms  accepted  by
	                     Tk_GetPixels.
	
	              -sticky style
	                     If   a  slave's  pane  is  larger  than  the
	                     requested  dimensions  of  the  slave,  this
	                     option  may be used to position (or stretch)
	                     the slave within  its  pane.   Style   is  a
	                     string  that  contains  zero  or more of the
	                     characters n, s, e or  w.   The  string  can
	                     optionally  contains  spaces  or commas, but
	                     they are ignored.  Each letter refers  to  a
	                     side  (north, south, east, or west) that the
	                     slave will "stick" to.  If both n and s  (or
	                     e  and  w)  are specified, the slave will be
	                     stretched to  fill  the  entire  height  (or
	                     width) of its cavity.
	
	              -width size
	                     Specify  a  width  for the slave.  The width
	                     will be the outer  dimension  of  the  slave
	                     including its border, if any.  If size is an
	                     empty string, or if -width is not specified,
	                     then  the  width requested internally by the
	                     slave will be used initially; the width  may
	                     later  be adjusted by the movement of sashes
	                     in the panedwindow.  Size may be  any  value
	                     accepted by Tk_GetPixels.
	
	       pathName slaves
	              Returns  an  ordered list of the widgets managed by
	              pathName.
	
	
	RESIZING PANES
	       A pane is resized by grabbing the sash (or sash handle  if
	       present)  and  dragging  with  the  mouse.  This is accom-
	       plished via mouse motion bindings on the widget.   When  a
	       sash  is moved, the sizes of the panes on each side of the
	       sash, and thus the widgets in those panes, are adjusted.
	
	       When a pane is resized from outside (eg, it is  packed  to
	       expand  and fill, and the containing toplevel is resized),
	       space is added to the final (rightmost or bottommost) pane
	       in the window.

# Reference Implementation

The widget described here has already been implemented, with
documentation and a full test suite.  The widget is included with the
Vu widget extension, part of the _tktable_ SourceForge project at
<http://tktable.sourceforge.net>

# Notes

Suggestions for possible future enhancements:

 * Allow specification of a weight for each pane, similar to the -weight option supported by
grid, to be used when allocating space from a resize to panes in the
widget.

 * Allow a bindable image to be placed on the window sash, a la 
Netscape's Messenger, or Java Swing, to allow one-click expand and
collapse of the pane.

 * Integrate with the -setgrid option such that if a pane contains
a -setgrided widget, the sash can only be moved in grid size steps.

None of these are prohibited by the current design, and could be 
implemented at a later date as enhancements to the widget.

# Copyright

This document has been placed in the public domain.

Name change from tip/410.tip to tip/410.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

TIP:            410
Title:          Three Features of scan Adapted for binary scan/format
Version:        $Revision: 1.2 $
Author:         Andreas Leitgeb <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        26-Aug-2012
Post-History:   
Tcl-Version:    8.7


~ Abstract

This proposal specifies three new features for '''binary scan''' and '''binary
format''' that already exist similarly for '''scan''', namely: '''#''' for
consuming a count-value from the parameter list (like "'''scan %*'''"),
'''p''' for writing current position to a consumed parameter variable (like
"'''scan %n'''") and returning a single parsed value if no parameter is left.

~ Rationale

Experience with '''binary format''' and '''binary scan''' indicates that there
are some features of '''scan''' which it would be highly desirable to have. In
particular, the ability to take an item length as a separate parameter, to
store the current location, and to return a '''single matched value''' when
last variable is not supplied would all be highly desirable.

Different symbols for some of the operations have had to be chosen, as both
"*" and "n" already exist and have a different meaning for '''binary scan'''
and '''binary format'''. Also, unlike with ''scan''. no list of values shall
be returned (except for a single counted conversion), but instead only one
extra conversion character allowed. Experience with scan shows that people
tend to forget about the list-layer and use ''[scan "08" %d]'' directly as
a number, which, while safe for integers, is just the wrong thing to do.

The TIP-Author believes that these are all rather
"low hanging fruit". If this turns out not to be the case, then any
controversial one of these features shall be moved to its own TIP.

~ Proposal

A "'''#'''" (number sign) at a place in the format-string where a number or a
"'''*'''" is currently allowed, shall consume one item from the parameter list
and interpret it as a number. It shall only occur after a conversion specifier
that accepts trailing numbers. The parameter consumed for "'''#'''" is the one
''after'' the parameter used for the conversion specifier itself, as the
"'''#'''" follows that specifier.

A new conversion specifier "'''p'''" shall not accept a trailing count and
consume one item from parameter list and interpret it as the name of a local
variable into which to store the current cursor-position. No data is consumed
for '''binary scan''' and no data produced for '''binary format'''.

A '''binary scan''' with a format-string that contains '''one''' data
conversion specifier '''more''' than variable parameters shall return
the remaining converted value (or an empty string if the last conversion
wasn't successful).

~~ Details

A "'''p'''"-conversion is not counted. In classic usage with variable
parameters, the return value of '''binary scan''' gives only the number of
real data conversions, thus not counting "'''@'''", "'''x'''", "'''X'''" or
"'''p'''".

A "'''#'''" given as count will always imply a list of values written to the
variable, even if the value is "1" and the list is of length 1. A negative
value could change the direction for relative movements "'''x'''" and
"'''X'''", and is treated as 0 in all other cases. A non-numeric value
(including the empty string!) given for a "'''#'''" causes the '''binary'''
command to return an error, just like garbage in the format string would. It
is explicitly not intended to get single-value behaviour with "'''#'''" and
empty string, nor have the separate count-value contain an asterisk or further
conversion characters.

~ Further Ideas

Eventually, as a special case for '''binary scan''', the following idiom shall
be allowed outside of the basic specification:

|  binary scan "\0\0\0\x2A" "I p" pos

returns 42 and then writes 4 to variable pos.

While the idiom would be quite practical, there is a risk of reader's
confusion about which value would be written and which returned, despite
unambiguous definition. Also, this one might turn out to be less than trivial
to implement, as it would require some lookahead to reserve the remaining
parameter for "p", not for "I" that is currently at hand.

~ Examples

|   # pad out 12 nuls, then set cursor to 0, write an 
|   #   int, record position, then write another int.
|   set data [binary format "x# @0 I p I" 12 1 pos 42]
|   --> data: "\0\0\0\1\0\0\0\x2A\0\0\0\0"  pos: 4
|
|   # set cursor position from value of first param, scan 
|   # three items from the data and write them to the
|   # next three parameter variables, then write new cursor
|   # position to next parameter variable.
|   binary scan $data "@# Iss p" $pos beI leS1 leS2 pos
|   --> beI: 42  leS1:0 leS2:0 pos:12
|
|   # 4 is value for "#", no further param, thus return 
|   # result for "I"
|   set val [binary scan $data "@# I" 4]
|   --> val: 42
|
|   # error case: more than one conversion to return
|   set val [binary scan $data "@# II" 4]
|   --> error: "not enough arguments for all format specifiers"
|
|   # extra "further ideas" feature:
|   set val [binary scan $data "@# I p" 4 pos]
|   --> val: 42 pos: 8

~ Rejected Alternatives

For a format string "'''a#'''", one could have argued to use first parameter
for the count and second for the conversion target, as that would be the order
of relevance (count is needed before the resulting value is even generated). I
think, this is a bikeshedding issue, and any choice is a good choice, so I
went with order of occurrence, thus "'''a#'''" expects the target variable
first, and the count second.

It would be possible to use "'''@'''" without a count instead of "'''p'''",
but I consider it dangerous, when a previous error turns into overwriting of
variables. I consider a typo "'''@ 42 ...'''" to be common enough to not want
to give it a new unexpected meaning and side-effect.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|
|
|
|

|

|
|

|



|
|
|

|






|

|
|

|
|
|

|


|

|
|
|
|

|

|
|
|
|

|

|
|
|

|



|

|


|









|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|

|

|

|


|

|


|


>

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

# TIP 410: Three Features of scan Adapted for binary scan/format

	Author:         Andreas Leitgeb <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        26-Aug-2012
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This proposal specifies three new features for **binary scan** and **binary
format** that already exist similarly for **scan**, namely: **\#** for
consuming a count-value from the parameter list \(like "**scan %\***"\),
**p** for writing current position to a consumed parameter variable \(like
"**scan %n**"\) and returning a single parsed value if no parameter is left.

# Rationale

Experience with **binary format** and **binary scan** indicates that there
are some features of **scan** which it would be highly desirable to have. In
particular, the ability to take an item length as a separate parameter, to
store the current location, and to return a **single matched value** when
last variable is not supplied would all be highly desirable.

Different symbols for some of the operations have had to be chosen, as both
"\*" and "n" already exist and have a different meaning for **binary scan**
and **binary format**. Also, unlike with _scan_. no list of values shall
be returned \(except for a single counted conversion\), but instead only one
extra conversion character allowed. Experience with scan shows that people
tend to forget about the list-layer and use _[scan "08" %d]_ directly as
a number, which, while safe for integers, is just the wrong thing to do.

The TIP-Author believes that these are all rather
"low hanging fruit". If this turns out not to be the case, then any
controversial one of these features shall be moved to its own TIP.

# Proposal

A "**\#**" \(number sign\) at a place in the format-string where a number or a
"**\***" is currently allowed, shall consume one item from the parameter list
and interpret it as a number. It shall only occur after a conversion specifier
that accepts trailing numbers. The parameter consumed for "**\#**" is the one
_after_ the parameter used for the conversion specifier itself, as the
"**\#**" follows that specifier.

A new conversion specifier "**p**" shall not accept a trailing count and
consume one item from parameter list and interpret it as the name of a local
variable into which to store the current cursor-position. No data is consumed
for **binary scan** and no data produced for **binary format**.

A **binary scan** with a format-string that contains **one** data
conversion specifier **more** than variable parameters shall return
the remaining converted value \(or an empty string if the last conversion
wasn't successful\).

## Details

A "**p**"-conversion is not counted. In classic usage with variable
parameters, the return value of **binary scan** gives only the number of
real data conversions, thus not counting "**@**", "**x**", "**X**" or
"**p**".

A "**\#**" given as count will always imply a list of values written to the
variable, even if the value is "1" and the list is of length 1. A negative
value could change the direction for relative movements "**x**" and
"**X**", and is treated as 0 in all other cases. A non-numeric value
\(including the empty string!\) given for a "**\#**" causes the **binary**
command to return an error, just like garbage in the format string would. It
is explicitly not intended to get single-value behaviour with "**\#**" and
empty string, nor have the separate count-value contain an asterisk or further
conversion characters.

# Further Ideas

Eventually, as a special case for **binary scan**, the following idiom shall
be allowed outside of the basic specification:

	  binary scan "\0\0\0\x2A" "I p" pos

returns 42 and then writes 4 to variable pos.

While the idiom would be quite practical, there is a risk of reader's
confusion about which value would be written and which returned, despite
unambiguous definition. Also, this one might turn out to be less than trivial
to implement, as it would require some lookahead to reserve the remaining
parameter for "p", not for "I" that is currently at hand.

# Examples

	   # pad out 12 nuls, then set cursor to 0, write an 
	   #   int, record position, then write another int.
	   set data [binary format "x# @0 I p I" 12 1 pos 42]
	   --> data: "\0\0\0\1\0\0\0\x2A\0\0\0\0"  pos: 4
	
	   # set cursor position from value of first param, scan 
	   # three items from the data and write them to the
	   # next three parameter variables, then write new cursor
	   # position to next parameter variable.
	   binary scan $data "@# Iss p" $pos beI leS1 leS2 pos
	   --> beI: 42  leS1:0 leS2:0 pos:12
	
	   # 4 is value for "#", no further param, thus return 
	   # result for "I"
	   set val [binary scan $data "@# I" 4]
	   --> val: 42
	
	   # error case: more than one conversion to return
	   set val [binary scan $data "@# II" 4]
	   --> error: "not enough arguments for all format specifiers"
	
	   # extra "further ideas" feature:
	   set val [binary scan $data "@# I p" 4 pos]
	   --> val: 42 pos: 8

# Rejected Alternatives

For a format string "**a\#**", one could have argued to use first parameter
for the count and second for the conversion target, as that would be the order
of relevance \(count is needed before the resulting value is even generated\). I
think, this is a bikeshedding issue, and any choice is a good choice, so I
went with order of occurrence, thus "**a\#**" expects the target variable
first, and the count second.

It would be possible to use "**@**" without a count instead of "**p**",
but I consider it dangerous, when a previous error turns into overwriting of
variables. I consider a typo "**@ 42 ...**" to be common enough to not want
to give it a new unexpected meaning and side-effect.

# Copyright

This document has been placed in the public domain.

Name change from tip/411.tip to tip/411.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
136
137



138
139
140
141
142

143
144
145
146
147

148
149
150
151
152


153
154
155
156
157
158

159
160
161
162
163
164
165
166
167
168
169
170
171
172

TIP:            411
Title:          Improved Channel Introspection via "chan info"
Version:        $Revision: 1.4 $
Author:         Pawel Salawa <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        31-Aug-2012
Post-History:   
Tcl-Version:    8.7


~ Abstract

This document describes new subcommand for '''chan''', '''chan info''', that
provides a unified interface to deeper introspection of information about a
particular channel.

~ Rationale

When working with Tcl channels sometimes it happens that we got the channel,
but we don't know if it's a file channel, socket, or reflected channel. This
information can be very useful. Also some additional information, depending of
the channel type, like file path for file channel, host and port for sockets
(it's already available, but could get unified within new '''chan'''
subcommand), or any metadata provided by reflected channels.

An example where it could be used is the package with an API that accepts just
a channel on input call and the inside routines need to do something with the
file (in file system), so they have to learn the name of the file related to
given channel.

~ Specification

A new subcommand for '''chan''' is introduced:

 > '''chan info''' ''channelId''

Also a new optional command is introduced for reflected channels API:

 > ''cmdPrefix'' '''chaninfo''' ''channelId''

~~ The info Subcommand of chan

The '''chan info''' command will take a single mandatory argument,
''channelId'', which will be the name of a channel to retrieve information
about. This operation will always fail in a safe interpreter. The result of
the new '''chan info''' command would be a dictionary with following keys
always present:

 type: indicating a type of channel. Possible values are "'''file'''",
   "'''socket'''", "'''process'''" (result of [['''open''' "|..."]]), empty
   string (in case of channel that doesn't support this information), or any
   custom type, depending of refchan implementations. This is a mandatory key.

The remainder of the keys are optional and depend on the type.

For '''file''' channels, the dictionary shall include these:

 path: full, normalized path to the file, including the file name.

 new: boolean value indicating whether file already existed while opening, or
   it was created.

For '''socket''' channels, the dictionary shall include these:

 host: peer hostname, or local hostname for listening socket. This is
   partially equivalent to getting the first value returned by [['''chan
   configure''' ''channelId'' '''-peername''']] for connected sockets.

 port: peer port, or listening port (for listening socket). This is partially
   equivalent to getting the third value returned by [['''chan configure'''
   ''channelId'' '''-peername''']] for connected sockets.

 side: one of the
 following: "'''client'''", "'''accepted'''", or "'''listening'''".

For '''process''' channels, the dictionary shall include these:

 cmdline: copy of the command passed to '''open'''.

 pid: PID of a spawned process, as produced by '''pid'''.

Any key could be produced by other channel types, notably including reflected channels.

~~ The chaninfo Operation of Reflected Channel Implementations

The '''chaninfo''' subcommand of a reflected channel implementation command
returns a dict that is provided in response to a '''chan info''' request. If
the dictionary does not include the mandatory '''type''' member, the reflected
channel baseline implementation will add it and set it to '''refchan'''. It is
an error to return a non-dictionary.

Since reflected channels are free to set the type to anything, they can
simulate standard channels, like "'''file'''", as well as create completely
new types.

If the operation is not supported, the baseline implementation will treat it
the same as if the operation returned an empty dictionary.

~ Internals

Channel structure in Tcl core would require another API level indicating
channels that have a function returning an "info" dict. All core channels are
expected to migrate to this level, although it's possible to stay at current
API version - it will just cause the '''type''' in '''chan info''' dict to be
the ''typeName'' field of the channel's ''Tcl_ChannelType'' structure, with no
additional keys in the dict.

~ Examples

This is a a pure Tcl implementation of file type channel, so it supports new
information in '''chan info''':

|oo::class create filechan {
|    variable path fd created filemode
|    constructor {fpath mode} {
|        set filemode $mode
|        set path $fpath
|    }

|
|    method initialize {ch mode} {
|        set exists [file exists $path]
|        set fd [open $path $filemode]
|        set created [expr { [file exists $path] && !$exists}]
|        return "initialize finalize watch read seek chaninfo"
|    }

|    method finalize {ch} {
|        ::close $fd
|        my destroy
|    }

|    method watch {ch events} {
|        foreach event [list read write] method [list readable writable] {
|            if {$event in $events} {
|                fileevent $fd $method [list chan postevent $ch $event]
|            }
|        }
|    }



|
|    # Must be present on a readable channel
|    method read {ch count} {
|        ::read $fd $count
|    }

|
|    # This method is optional, but useful for the example below
|    method seek {ch offset base} {
|        ::seek $fd $offset $base
|    }

|
|    method chaninfo {ch} {
|        dict create type file path $path new $created
|    }
|}


|
|proc openfile {file mode} {
|    # lets not bother of what modes should be passed to [chan create],
|    # it's just an example...
|    chan create [list read write] [filechan new $file $mode]
|}

|
|set fd [openfile "myfile.txt" r]
|puts [chan info $fd]
|close $fd

~ Reference Implementation

http://sqlitestudio.pl/tcl/patches/tip-411-chan_info.patch

Patch made against 8.6.0 (just before final release).

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|



|





|
|



|


|

|

|



|

|

|
|

|


|
|
|




|






|


|
|

|
|
|


|

|

|

|



|

|
|
|
|



|





|




|
|


|


|

|
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
<
<
<
>
>
>
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
<
<
>
>
|
|
|
|
|
<
>
|
|
|
|

|

|

|

|


>

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
136
137
138
139
140

141
142
143
144
145

146
147
148
149


150
151
152
153
154
155
156

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

# TIP 411: Improved Channel Introspection via "chan info"

	Author:         Pawel Salawa <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        31-Aug-2012
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This document describes new subcommand for **chan**, **chan info**, that
provides a unified interface to deeper introspection of information about a
particular channel.

# Rationale

When working with Tcl channels sometimes it happens that we got the channel,
but we don't know if it's a file channel, socket, or reflected channel. This
information can be very useful. Also some additional information, depending of
the channel type, like file path for file channel, host and port for sockets
\(it's already available, but could get unified within new **chan**
subcommand\), or any metadata provided by reflected channels.

An example where it could be used is the package with an API that accepts just
a channel on input call and the inside routines need to do something with the
file \(in file system\), so they have to learn the name of the file related to
given channel.

# Specification

A new subcommand for **chan** is introduced:

 > **chan info** _channelId_

Also a new optional command is introduced for reflected channels API:

 > _cmdPrefix_ **chaninfo** _channelId_

## The info Subcommand of chan

The **chan info** command will take a single mandatory argument,
_channelId_, which will be the name of a channel to retrieve information
about. This operation will always fail in a safe interpreter. The result of
the new **chan info** command would be a dictionary with following keys
always present:

 type: indicating a type of channel. Possible values are "**file**",
   "**socket**", "**process**" \(result of [**open** "\|..."]\), empty
   string \(in case of channel that doesn't support this information\), or any
   custom type, depending of refchan implementations. This is a mandatory key.

The remainder of the keys are optional and depend on the type.

For **file** channels, the dictionary shall include these:

 path: full, normalized path to the file, including the file name.

 new: boolean value indicating whether file already existed while opening, or
   it was created.

For **socket** channels, the dictionary shall include these:

 host: peer hostname, or local hostname for listening socket. This is
   partially equivalent to getting the first value returned by [**chan
   configure** _channelId_ **-peername**] for connected sockets.

 port: peer port, or listening port \(for listening socket\). This is partially
   equivalent to getting the third value returned by [**chan configure**
   _channelId_ **-peername**] for connected sockets.

 side: one of the
 following: "**client**", "**accepted**", or "**listening**".

For **process** channels, the dictionary shall include these:

 cmdline: copy of the command passed to **open**.

 pid: PID of a spawned process, as produced by **pid**.

Any key could be produced by other channel types, notably including reflected channels.

## The chaninfo Operation of Reflected Channel Implementations

The **chaninfo** subcommand of a reflected channel implementation command
returns a dict that is provided in response to a **chan info** request. If
the dictionary does not include the mandatory **type** member, the reflected
channel baseline implementation will add it and set it to **refchan**. It is
an error to return a non-dictionary.

Since reflected channels are free to set the type to anything, they can
simulate standard channels, like "**file**", as well as create completely
new types.

If the operation is not supported, the baseline implementation will treat it
the same as if the operation returned an empty dictionary.

# Internals

Channel structure in Tcl core would require another API level indicating
channels that have a function returning an "info" dict. All core channels are
expected to migrate to this level, although it's possible to stay at current
API version - it will just cause the **type** in **chan info** dict to be
the _typeName_ field of the channel's _Tcl\_ChannelType_ structure, with no
additional keys in the dict.

# Examples

This is a a pure Tcl implementation of file type channel, so it supports new
information in **chan info**:

	oo::class create filechan {
	    variable path fd created filemode
	    constructor {fpath mode} {
	        set filemode $mode
	        set path $fpath

	    }
	
	    method initialize {ch mode} {
	        set exists [file exists $path]
	        set fd [open $path $filemode]
	        set created [expr { [file exists $path] && !$exists}]
	        return "initialize finalize watch read seek chaninfo"

	    }
	    method finalize {ch} {
	        ::close $fd
	        my destroy

	    }
	    method watch {ch events} {
	        foreach event [list read write] method [list readable writable] {
	            if {$event in $events} {
	                fileevent $fd $method [list chan postevent $ch $event]



	            }
	        }
	    }
	
	    # Must be present on a readable channel
	    method read {ch count} {
	        ::read $fd $count

	    }
	
	    # This method is optional, but useful for the example below
	    method seek {ch offset base} {
	        ::seek $fd $offset $base

	    }
	
	    method chaninfo {ch} {
	        dict create type file path $path new $created


	    }
	}
	
	proc openfile {file mode} {
	    # lets not bother of what modes should be passed to [chan create],
	    # it's just an example...
	    chan create [list read write] [filechan new $file $mode]

	}
	
	set fd [openfile "myfile.txt" r]
	puts [chan info $fd]
	close $fd

# Reference Implementation

<http://sqlitestudio.pl/tcl/patches/tip-411-chan\_info.patch>

Patch made against 8.6.0 \(just before final release\).

# Copyright

This document has been placed in the public domain.

Name change from tip/412.tip to tip/412.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354


355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377




378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403

404
405
406
407
408

409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475

TIP:            412
Title:          Dynamic Locale Changing for msgcat with On-Demand File Load
Version:        $Revision: 1.9 $
Author:         Harald Oehlmann <[email protected]>
Author:         Harald Oehlmann <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        27-Mar-2012
Post-History:   
Keywords:       Tcl,localization,msgcat
Obsoletes:      399
Tcl-Version:    8.6


~ Abstract

This TIP adds dynamic locale switching capabilities to the '''msgcat'''
package.

~ Rationale

~~ Dynamic Locale Switching

Within a multi-language application like a web-server, one may change the locale quite frequently, for example if users with different locales are requesting pages. Unfortunately, this does not fit well with the model adopted by the msgcat package, which assumes that all code follows this sequence:

 1.
 Set locale list: '''mclocale''' ''locale''

 2.
 Load language files with other package load: '''mcload''' ''msg-folder''

 3.
 Translate strings: '''mc''' ''key args...''

Note that if the locale should be changed after other packages are loaded, one must restart at step 2. This requires reloading all packages which is mostly not practical.

The aim of this TIP is to extend the package by dynamic locale change capabilities.

msgcat will reload any missing message catalog files of all currently loaded packages on a locale change. In addition, any package may register to get informed to a locale change. Other packages may do changes to reflect the locale change like rebuilding the GUI.

This TIP compares to [399] that the package is able to load message catalog files on demand, e.g. specially on a locale change.

~~ package locale

If the clock command gets called with the argument "-locale", the locale is changed using msgcat::mclocale. After processing, the initial value is restored. The package keeps track, which locales where already used and calls msgcat::mcload for any new locale. The locale is restored after processing.

This is an implementation of dynamic locales but conflicts with the new features described above. Other packages may be informed to change the locale and may trigger expensive operations like a rebuild of the GUI.

In consequence, each package may define a package locale which is independent of the default locale.

~ Overview of the proposed solution

Proposed changes in brief:

~~ Dynamically load message catalog files

if the locale is changed by mclocale locale, the message file load process is executed for every present package.

~~ Package locale

A package may install a package local locale which is independent to the global locale.

~~ Locale change callback

A callback may be registered to get informed about the change of locale. A use case is to refresh a GUI if the locale changed.

~~ Non message file operation

A program may use message files to issue mcset commands or may issue them by other means, if the message catalogs are, for example, stored in a data base.

Each package may register a callback to get informed that a certain locale should be loaded and may issue the corresponding mcset commands.

~~ Package mcunknown

A package may have a certain way to provide translations for message keys not included in the message catalog. Thus, it may register an own package message unknown callback to provide a translation.

~ Specification

~~ Package Equals Client Namespace

A client package is a package which uses msgcat. A unique namespace is required for each client package. Within msgcat, namespace and package is always connected.

Up to now, the msgcat package used this namespace as an identifier to store the catalog data of a certain package. This is now extended to additional properties which are stored for a package.

~~ Package locale

A package locale may be used by a package instead the default locale set by msgcat::mclocale. A package may choose to use a package locale or the default locale.

~~ Default and Package State

Some state values (like the locale) are available as default (global) values. In addition, each package may choose to use a package locale state.

The used naming is:

    default

     state: valid for all packages which do not set a package state.

    package

     state: only valid for one package if it has set a package state.

The following state values are present as default state and may be set individually per package:

    The locale like "de_ch".
    The preferences property is a list of locales in their preference order and is automatically computed from locale. Example locale = "de_ch" -> preferences = "de_ch de {}".
    The loadedlocales state value is the list of currently loaded locales.

~~ Default State

The following standard methods exist to get or set the default state:

~~~ msgcat::mclocale

The default locale. It may be read using msgcat::mclocale.

It may be set using msgcat::mclocale locale. This command is extended, that the message catalogs of all missing locales for all packages not having set a package state are loaded.

~~~ msgcat::mcpreferences

Get the default preferences (derived from the default locale).

~~~ msgcat::mcloadedlocales

The following new command may be used to deal with the default state:

 > '''msgcat::mcloadedlocales''' ''subcommand'' ''?locale?''

The parameter locale is mandatory for the subcommand present.

The following subcommands are available:

~~~ Subcommand "get"

Get the list of current loaded locales

~~~ Subcommand "present"

Returns true, if the given locale is loaded

~~~ Subcommand "clear"

The list of currently loaded locales is set to mcpreferences and all message catalog keys of packages without a package locale set and with locales not in mcpreferences are unset.

~~ Package Configuration

The package configuration of the calling package may be changed using the following new command:

 > '''msgcat::mcpackagelocale''' ''subcommand'' ?''locale''?

The parameter locale is mandatory for the subcommands set and present.

Available subcommands are:

~~~ Subcommand "set"

Set or change the package locale.

The global state values are copied, if there were no package locale set before.

The package locale is changed to the optional given new package locale.

~~~ Subcommand "get"

Return the package locale or the default locale, if no package locale set.

~~~ Subcommand "preferences"

Return the package preferences or the default preferences, if no package locale set.

~~~ Subcommand "loaded"

The list of locales loaded for this package is returned.

~~~ Subcommand "isset"

Returns true, if a package locale is set.

~~~ Subcommand "unset"

Unset the package locale and use the default state for the package. Load all message catalog files of the package for locales, which were not present in the package loadedlocales list and are present in the default list.

~~~ Subcommand "present"

Returns true, if the given locale is loaded

~~~ Subcommand "clear"

Set the current loaded locales list of the package to preferences and unset all message catalog keys of the package with locales not included in the package preferences.

~~ Package Configuration Options

Each package may have a set of configuration options set to invoke certain actions. They may be retrieved or changed with the following new command:

 > '''msgcat::mcpackageconfig''' ''subcommand option'' ?''value''?

Available subcommands are:

 get: Get the current value of the option or an error if not set.

 isset: Returns true if option is set.

 set: Set the given value to the option. May have additional consequences and
   return values as described in the option section.

 unset: Unset the option.

Available options are:

~~~ Package Option "mcfolder"

This is the message folder of the package. This option is set by mcload and by the subcommand set. Both are identical and both return the number of loaded message catalog files.

Setting or changing this value will load all locales contained in the preferences valid for the package. This implies also to invoke any set loadcmd (see below).

Unsetting this value will disable message file load for the package.

If the locale valid for this package changes, this value is used to eventually load message catalog files.

Message catalog files are always sourced in the namespace of the package registering the value.

~~~ Package Option "loadcmd"

This callback is invoked before a set of message catalog files are loaded for the package which has this property set.

This callback may be used to do any preparation work for message file load or to get the message data from another source like a data base. In this case, no message files are used (mcfolder is unset).

See chapter callback invocation below. The parameter list appended to this callback is the list of locales to load.

If this callback is changed, it is called with the preferences valid for the package.

~~~ Package Option "changecmd"

This callback is invoked when a default local change was performed. Its purpose is to allow a package to update any dependency on the default locale like showing the GUI in another language.

Tk may be extended to register to this callback and to invoke a virtual event.

See the callback invocation section below. The parameter list appended to this callback is mcpreferences. All registered packages are invoked in no particular order.

~~~ Package Option "unknowncmd"

Use a package locale mcunknown procedure instead of the standard version supplied by the msgcat package (msgcat::mcunknown).

The called procedure must return the formatted message which will finally be returned by msgcat::mc.

A generic unknown handler is used if set to the empty string. This consists in returning the key if no arguments are given. With given arguments, format is used to process the arguments.

See chapter callback invocation below. The appended arguments are identical to mcunknown.

~~~ Callback Invocation

Callbacks are invoked under the following conditions:

    the callback command is set,
    the command is not the empty string,
    the registration namespace exists.

Any error within the callback stops the operation which invoked the callback. This might be surprising, as the error might be in another package.

~~ Test if Message Key is Set

Message catalog keys may be expensive to calculate and thus may be set on demand.

The following new procedure returns false, if mc would call mcunknown for a key:

 > '''msgcat::mcexists''' ''src''

There are two options, to limit the key search to just the current namespace (don't search in parent namespaces) and just the current locale (don't search the preferences but the first item):

 > '''msgcat::mcexists''' ?'''-exactnamespace'''? ?''-exactlocale''? ''src''

~~ forget package

A package may clear all its keys and state using the new command:

 > '''msgcat::mcforgetpackage'''

~~ Locale and Preferences Format

Locales set by mcset may eventually not correspond to the current preferences, as the preferences are treated as follows:

    put to lower case,
    remove any multiple "_" and any "_" at the beginning or at the end of the

     locale.

It is proposed, that:

    the locale and the first preferences element is always identical to the

      lowercase passed locale,

    any multiple "_" are seen as one separator.

Example: preferences of locale "sy__cyrl_win"

    current preferences: "sy_cyrl_win sy_cyrl sy"
    proposed preferences: "sy__cyrl_win sy__cyrl sy".

Alternatively, all locales may normalized using the upper algorithm, which felt heavy in computation with little gain.

~ Example Usage

~~ Example from TIP #399

Imagine an application which supports the current user language and French, German and English. An external package tp is used. The package uses msgcat and installs itself during the package require tp call:

|package require msgcat
|msgcat::mcload [file join [file dirname [info script]] msgs]

An implementation of the application with the current msgcat 1.5.0 would require the following initialization sequence:

|package require msgcat
|package require np

and the following code to change the locale to French:

|package forget np
|msgcat::mclocale fr
|package require np

Using the extension of this TIP, one may load as usual:

|package require msgcat
|package require np

and to change to french locale:

|msgcat::mclocale fr

The first time, a locale is required, all corresponding message files of all packages which use msgcat get loaded. This might be a heavy operation.

If a locale is reactivated (and the message catalog data was not cleared), it is a quick operation.

Without this TIP, it is computational expensive (if possible, as many packages are not reloadable or a reload may disturb current processing, e.g., by forcing the closing of sockets, etc.).

~~ Change with No Need to Come Back

If it is certain that a locale is changed and the then obsolete data is of no use, one may clear unused message catalog items:

|msgcat::mclocale fr
|msgcat::mcloadedlocale clear

~~ Use a Callback to be Notified About a Locale Change

Packages which display a GUI may update their widgets when the locale changes. To register to a callback, use:

|namespace eval gui {
| msgcat::mcpackageconfig changecmd updateGUI
|
| proc updateGui args {
| puts "New locale is '[lindex $args 0]'."
| }
|}


|
|% msgcat::mclocale fr
|fr
|% New locale is 'fr'.

~~ To Use Another Locale Source than Message Catalog Files

If locales (or additional locales) are contained in another source like a data base, a package may use the load callback and not mcload:

|namespace eval db {
| msgcat::mcpackageconfig loadcmd loadMessages
| msgcat::mcconfig loadedpackages\
| [concat [msgcat::mcconfig loadedpackages] namespace current]
|
| proc loadMessages args {
| foreach locale $args {
| if {[LocaleInDB $locale]} {
| msgcat::mcmset $locale [GetLocaleList $locale]
| }
| }
| }
|}





~~ Use a package locale

The reference implementation also contains a changed clock command which uses a package locale. Here are some sketches from the implementation.

First, a package locale is initialized and the generic unknown function is activated:

|msgcat::mcpackagelocale set
|msgcat::mcpackageconfig unknowncmd ""

If the user requires the week day in a certain locale, it is changed:

|clock format clock seconds -format %A -locale fr

and the code:

|msgcat::mcpackagelocale set $locale
|return [lindex [msgcat::mc DAYS_OF_WEEK_FULL] $day]
|### Returns "mercredi"

Some message-catalog items are heavy in computation and thus are dynamically cached using:

|proc ::tcl::clock::LocalizeFormat { locale format } {
| set key FORMAT_$format
| if { [::msgcat::mcexists -exactlocale -exactnamespace $key] } {
| return [mc $key]
| }

| #...expensive computation of format clipped...
| mcset $locale $key $format
| return $format
|}


~ Reference Implementation

See Tcl fossil tag msgcat_dyn_locale [1].

~ Compatibility

Imagined incompatibilities:

    If packages call mcload multiple times with different folders, the

     data was currently appended. This is still the case, but only the last
     folder is used for any reload. The property '''mcfolder''' may be
     transformed to a list to cover this case.

    The return value of mcload (file count) may be much higher as there

     may be loaded much more files. I suppose, this value is only used by the
     test suite to verify functionality and is not for big general use.

    Message files may not be aware, that they may be loaded at any moment and

     not only after their own '''mcload'''. I suppose, this is the biggest
     issue but I think, there is no alternative.

    Message files do not get reloaded any more, if a second mcload is

     issued with the same path argument.

    Package which temporary change the default locale trigger any callback

     and may lead to user visible side effects.

~ Issues

Known issues:

    Packages might not be aware of a locale change and may buffer

     translations outside of '''msgcat'''. Packages should not buffer msgcat
     messages if they are used in a dynamic locale application (like tklib
     tooltip does for example).

    The clock command currently has a small dynamic patch for msgcat

     implemented. This must be removed in favor to new msgcat features due to
     the temporarily change of the default locale.

~ Extensions

    Expose the function to calculate the preference list from a given locale.
    Load a message catalog file for a given locale without changing the

     default/package locale.

    Methods isloaded to check if a locale is currently loaded.
    Access message catalog with specified namespace, locale and search

     behavior.

~ Alternatives

The alternative is the former [399], but that is problematic because the list of locales must be known before any package load. The additional complexity of this TIP is a justifiable trade-off against the greatly improved flexibility in the loading and locale selection order.

~ Copyright

This document has been placed in the public domain.


<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|


|

|




|


|


|







|

|







|



|



|



|



|





|



|

|





|



|

|













|
|


|



|





|

|

|



|





|



|



|



|



|





|







|



|



|



|



|



|



|



|



|














|



|







|



|





|







|

|







|









|





|

|

|

|



|

|




|









|

|

|
|



|

|



|
|



|
|



|
|
|



|
|



|



|

|

|



|
|

|



|
|
|
|
|
<
<
>
>
|
|
|
|

|

|

|
|
|
|
|
|
|
|
|
<
<
<
<
|
>
>
>
>
|





|
|



|



|
|
|



|
|
|
|
<
>
|
|
|
<
|
>
|

|

|






|


|






|










|





|
|
|






|











|

|

|



>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351


352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371




372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401

402
403
404
405

406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475

# TIP 412: Dynamic Locale Changing for msgcat with On-Demand File Load

	Author:         Harald Oehlmann <[email protected]>
	Author:         Harald Oehlmann <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        27-Mar-2012
	Post-History:   
	Keywords:       Tcl,localization,msgcat
	Obsoletes:      399
	Tcl-Version:    8.6
-----

# Abstract

This TIP adds dynamic locale switching capabilities to the **msgcat**
package.

# Rationale

## Dynamic Locale Switching

Within a multi-language application like a web-server, one may change the locale quite frequently, for example if users with different locales are requesting pages. Unfortunately, this does not fit well with the model adopted by the msgcat package, which assumes that all code follows this sequence:

 1.
 Set locale list: **mclocale** _locale_

 2.
 Load language files with other package load: **mcload** _msg-folder_

 3.
 Translate strings: **mc** _key args..._

Note that if the locale should be changed after other packages are loaded, one must restart at step 2. This requires reloading all packages which is mostly not practical.

The aim of this TIP is to extend the package by dynamic locale change capabilities.

msgcat will reload any missing message catalog files of all currently loaded packages on a locale change. In addition, any package may register to get informed to a locale change. Other packages may do changes to reflect the locale change like rebuilding the GUI.

This TIP compares to [[399]](399.md) that the package is able to load message catalog files on demand, e.g. specially on a locale change.

## package locale

If the clock command gets called with the argument "-locale", the locale is changed using msgcat::mclocale. After processing, the initial value is restored. The package keeps track, which locales where already used and calls msgcat::mcload for any new locale. The locale is restored after processing.

This is an implementation of dynamic locales but conflicts with the new features described above. Other packages may be informed to change the locale and may trigger expensive operations like a rebuild of the GUI.

In consequence, each package may define a package locale which is independent of the default locale.

# Overview of the proposed solution

Proposed changes in brief:

## Dynamically load message catalog files

if the locale is changed by mclocale locale, the message file load process is executed for every present package.

## Package locale

A package may install a package local locale which is independent to the global locale.

## Locale change callback

A callback may be registered to get informed about the change of locale. A use case is to refresh a GUI if the locale changed.

## Non message file operation

A program may use message files to issue mcset commands or may issue them by other means, if the message catalogs are, for example, stored in a data base.

Each package may register a callback to get informed that a certain locale should be loaded and may issue the corresponding mcset commands.

## Package mcunknown

A package may have a certain way to provide translations for message keys not included in the message catalog. Thus, it may register an own package message unknown callback to provide a translation.

# Specification

## Package Equals Client Namespace

A client package is a package which uses msgcat. A unique namespace is required for each client package. Within msgcat, namespace and package is always connected.

Up to now, the msgcat package used this namespace as an identifier to store the catalog data of a certain package. This is now extended to additional properties which are stored for a package.

## Package locale

A package locale may be used by a package instead the default locale set by msgcat::mclocale. A package may choose to use a package locale or the default locale.

## Default and Package State

Some state values \(like the locale\) are available as default \(global\) values. In addition, each package may choose to use a package locale state.

The used naming is:

    default

     state: valid for all packages which do not set a package state.

    package

     state: only valid for one package if it has set a package state.

The following state values are present as default state and may be set individually per package:

    The locale like "de\_ch".
    The preferences property is a list of locales in their preference order and is automatically computed from locale. Example locale = "de\_ch" -> preferences = "de\_ch de \{\}".
    The loadedlocales state value is the list of currently loaded locales.

## Default State

The following standard methods exist to get or set the default state:

### msgcat::mclocale

The default locale. It may be read using msgcat::mclocale.

It may be set using msgcat::mclocale locale. This command is extended, that the message catalogs of all missing locales for all packages not having set a package state are loaded.

### msgcat::mcpreferences

Get the default preferences \(derived from the default locale\).

### msgcat::mcloadedlocales

The following new command may be used to deal with the default state:

 > **msgcat::mcloadedlocales** _subcommand_ _?locale?_

The parameter locale is mandatory for the subcommand present.

The following subcommands are available:

### Subcommand "get"

Get the list of current loaded locales

### Subcommand "present"

Returns true, if the given locale is loaded

### Subcommand "clear"

The list of currently loaded locales is set to mcpreferences and all message catalog keys of packages without a package locale set and with locales not in mcpreferences are unset.

## Package Configuration

The package configuration of the calling package may be changed using the following new command:

 > **msgcat::mcpackagelocale** _subcommand_ ?_locale_?

The parameter locale is mandatory for the subcommands set and present.

Available subcommands are:

### Subcommand "set"

Set or change the package locale.

The global state values are copied, if there were no package locale set before.

The package locale is changed to the optional given new package locale.

### Subcommand "get"

Return the package locale or the default locale, if no package locale set.

### Subcommand "preferences"

Return the package preferences or the default preferences, if no package locale set.

### Subcommand "loaded"

The list of locales loaded for this package is returned.

### Subcommand "isset"

Returns true, if a package locale is set.

### Subcommand "unset"

Unset the package locale and use the default state for the package. Load all message catalog files of the package for locales, which were not present in the package loadedlocales list and are present in the default list.

### Subcommand "present"

Returns true, if the given locale is loaded

### Subcommand "clear"

Set the current loaded locales list of the package to preferences and unset all message catalog keys of the package with locales not included in the package preferences.

## Package Configuration Options

Each package may have a set of configuration options set to invoke certain actions. They may be retrieved or changed with the following new command:

 > **msgcat::mcpackageconfig** _subcommand option_ ?_value_?

Available subcommands are:

 get: Get the current value of the option or an error if not set.

 isset: Returns true if option is set.

 set: Set the given value to the option. May have additional consequences and
   return values as described in the option section.

 unset: Unset the option.

Available options are:

### Package Option "mcfolder"

This is the message folder of the package. This option is set by mcload and by the subcommand set. Both are identical and both return the number of loaded message catalog files.

Setting or changing this value will load all locales contained in the preferences valid for the package. This implies also to invoke any set loadcmd \(see below\).

Unsetting this value will disable message file load for the package.

If the locale valid for this package changes, this value is used to eventually load message catalog files.

Message catalog files are always sourced in the namespace of the package registering the value.

### Package Option "loadcmd"

This callback is invoked before a set of message catalog files are loaded for the package which has this property set.

This callback may be used to do any preparation work for message file load or to get the message data from another source like a data base. In this case, no message files are used \(mcfolder is unset\).

See chapter callback invocation below. The parameter list appended to this callback is the list of locales to load.

If this callback is changed, it is called with the preferences valid for the package.

### Package Option "changecmd"

This callback is invoked when a default local change was performed. Its purpose is to allow a package to update any dependency on the default locale like showing the GUI in another language.

Tk may be extended to register to this callback and to invoke a virtual event.

See the callback invocation section below. The parameter list appended to this callback is mcpreferences. All registered packages are invoked in no particular order.

### Package Option "unknowncmd"

Use a package locale mcunknown procedure instead of the standard version supplied by the msgcat package \(msgcat::mcunknown\).

The called procedure must return the formatted message which will finally be returned by msgcat::mc.

A generic unknown handler is used if set to the empty string. This consists in returning the key if no arguments are given. With given arguments, format is used to process the arguments.

See chapter callback invocation below. The appended arguments are identical to mcunknown.

### Callback Invocation

Callbacks are invoked under the following conditions:

    the callback command is set,
    the command is not the empty string,
    the registration namespace exists.

Any error within the callback stops the operation which invoked the callback. This might be surprising, as the error might be in another package.

## Test if Message Key is Set

Message catalog keys may be expensive to calculate and thus may be set on demand.

The following new procedure returns false, if mc would call mcunknown for a key:

 > **msgcat::mcexists** _src_

There are two options, to limit the key search to just the current namespace \(don't search in parent namespaces\) and just the current locale \(don't search the preferences but the first item\):

 > **msgcat::mcexists** ?**-exactnamespace**? ?_-exactlocale_? _src_

## forget package

A package may clear all its keys and state using the new command:

 > **msgcat::mcforgetpackage**

## Locale and Preferences Format

Locales set by mcset may eventually not correspond to the current preferences, as the preferences are treated as follows:

    put to lower case,
    remove any multiple "\_" and any "\_" at the beginning or at the end of the

     locale.

It is proposed, that:

    the locale and the first preferences element is always identical to the

      lowercase passed locale,

    any multiple "\_" are seen as one separator.

Example: preferences of locale "sy\_\_cyrl\_win"

    current preferences: "sy\_cyrl\_win sy\_cyrl sy"
    proposed preferences: "sy\_\_cyrl\_win sy\_\_cyrl sy".

Alternatively, all locales may normalized using the upper algorithm, which felt heavy in computation with little gain.

# Example Usage

## Example from TIP \#399

Imagine an application which supports the current user language and French, German and English. An external package tp is used. The package uses msgcat and installs itself during the package require tp call:

	package require msgcat
	msgcat::mcload [file join [file dirname [info script]] msgs]

An implementation of the application with the current msgcat 1.5.0 would require the following initialization sequence:

	package require msgcat
	package require np

and the following code to change the locale to French:

	package forget np
	msgcat::mclocale fr
	package require np

Using the extension of this TIP, one may load as usual:

	package require msgcat
	package require np

and to change to french locale:

	msgcat::mclocale fr

The first time, a locale is required, all corresponding message files of all packages which use msgcat get loaded. This might be a heavy operation.

If a locale is reactivated \(and the message catalog data was not cleared\), it is a quick operation.

Without this TIP, it is computational expensive \(if possible, as many packages are not reloadable or a reload may disturb current processing, e.g., by forcing the closing of sockets, etc.\).

## Change with No Need to Come Back

If it is certain that a locale is changed and the then obsolete data is of no use, one may clear unused message catalog items:

	msgcat::mclocale fr
	msgcat::mcloadedlocale clear

## Use a Callback to be Notified About a Locale Change

Packages which display a GUI may update their widgets when the locale changes. To register to a callback, use:

	namespace eval gui {
	 msgcat::mcpackageconfig changecmd updateGUI
	
	 proc updateGui args {
	 puts "New locale is '[lindex $args 0]'."


	 }
	}
	
	% msgcat::mclocale fr
	fr
	% New locale is 'fr'.

## To Use Another Locale Source than Message Catalog Files

If locales \(or additional locales\) are contained in another source like a data base, a package may use the load callback and not mcload:

	namespace eval db {
	 msgcat::mcpackageconfig loadcmd loadMessages
	 msgcat::mcconfig loadedpackages\
	 [concat [msgcat::mcconfig loadedpackages] namespace current]
	
	 proc loadMessages args {
	 foreach locale $args {
	 if {[LocaleInDB $locale]} {
	 msgcat::mcmset $locale [GetLocaleList $locale]




	 }
	 }
	 }
	}

## Use a package locale

The reference implementation also contains a changed clock command which uses a package locale. Here are some sketches from the implementation.

First, a package locale is initialized and the generic unknown function is activated:

	msgcat::mcpackagelocale set
	msgcat::mcpackageconfig unknowncmd ""

If the user requires the week day in a certain locale, it is changed:

	clock format clock seconds -format %A -locale fr

and the code:

	msgcat::mcpackagelocale set $locale
	return [lindex [msgcat::mc DAYS_OF_WEEK_FULL] $day]
	### Returns "mercredi"

Some message-catalog items are heavy in computation and thus are dynamically cached using:

	proc ::tcl::clock::LocalizeFormat { locale format } {
	 set key FORMAT_$format
	 if { [::msgcat::mcexists -exactlocale -exactnamespace $key] } {
	 return [mc $key]

	 }
	 #...expensive computation of format clipped...
	 mcset $locale $key $format
	 return $format

	}

# Reference Implementation

See Tcl fossil tag msgcat\_dyn\_locale [[1]](1.md).

# Compatibility

Imagined incompatibilities:

    If packages call mcload multiple times with different folders, the

     data was currently appended. This is still the case, but only the last
     folder is used for any reload. The property **mcfolder** may be
     transformed to a list to cover this case.

    The return value of mcload \(file count\) may be much higher as there

     may be loaded much more files. I suppose, this value is only used by the
     test suite to verify functionality and is not for big general use.

    Message files may not be aware, that they may be loaded at any moment and

     not only after their own **mcload**. I suppose, this is the biggest
     issue but I think, there is no alternative.

    Message files do not get reloaded any more, if a second mcload is

     issued with the same path argument.

    Package which temporary change the default locale trigger any callback

     and may lead to user visible side effects.

# Issues

Known issues:

    Packages might not be aware of a locale change and may buffer

     translations outside of **msgcat**. Packages should not buffer msgcat
     messages if they are used in a dynamic locale application \(like tklib
     tooltip does for example\).

    The clock command currently has a small dynamic patch for msgcat

     implemented. This must be removed in favor to new msgcat features due to
     the temporarily change of the default locale.

# Extensions

    Expose the function to calculate the preference list from a given locale.
    Load a message catalog file for a given locale without changing the

     default/package locale.

    Methods isloaded to check if a locale is currently loaded.
    Access message catalog with specified namespace, locale and search

     behavior.

# Alternatives

The alternative is the former [[399]](399.md), but that is problematic because the list of locales must be known before any package load. The additional complexity of this TIP is a justifiable trade-off against the greatly improved flexibility in the loading and locale selection order.

# Copyright

This document has been placed in the public domain.


Name change from tip/413.tip to tip/413.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

TIP:            413
Title:          Unicode Support for 'string is space' and 'string trim'
Version:        $Revision: 1.5 $
Author:         Jan Nijtmans <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        08-Oct-2012
Post-History:   
Discussions-To: Tcl Core list
Keywords:       Tcl
Tcl-Version:    8.6


~ Abstract

This TIP is in fact a re-consideration of [318], in that it attempts to
define, once and for all, for which characters '''string is space''' should
return 1 and which characters '''string trim''' should trim.

~ Rationale

Intuitively, '''string is space''' and '''string trim''' should treat the same
characters as space, but currently that's not the case, even after the
implementation of [318].  The unicode standard advanced to version 6.2 now (at
the time of this writing), but also Java and .NET have their own views on what
whitespace should be. Let's try to learn from them.

~~ Defining the Tcl Space Set

The NUL character has the function as string separator, which could be
considered in the same group as LINE SEPARATOR (U+2028) and PARAGRAPH
SEPARATOR (U+2029). It's a very useful character to be stripped. It even had
the Whitespace property in Unicode 2.0. The problem with considering this
character as space is that its visible representation is not specified, it
even should not occur in normal text. Therefore, it is not in the "Tcl space
set", but it is very useful to let it be stripped by '''string trim'''.

The Unicode standard changed in time, which resulted in whitespace characters
being removed (deprecated) and added.  The ''String.Trim()'' method in .NET
3.5 stripped zero width space (U+200B) and zero width no-break space (U+FEFF)
from strings, but later .NET versions don't do that any more.  The "Tcl space
set" should not depend on that: If characters are deprecated in future Unicode
versions, and because of that Whitespace properties are changed, they will not
be removed from the "Tcl space set". But if new whitespace characters are
added in future Unicode standards, they will be added to the "Tcl space set"
as well, influencing both '''string is space''' and '''string trim'''.

The 3 characters that are in the "Tcl space set" but not in the current
Unicode whitespace set are discussed now.

Most obvious is zero width no-break space (U+FEFF), which is a very useful
character to be stripped, as it is used now as Byte Order Mark (BOM). It has
no visible representation, and - in fact - no meaning at all within Tcl, as
Tcl is UTF-8 internally already. It should not occur anywhere else in the
string, but in the past it could as being a zero-width no-break space. It had
the ''White_Space'' property in Unicode 2.0, but later versions of Unicode do
not; the use of the BOM as a space was deprecated.

When the use as space was deprecated for (U+FEFF), another character was put
forward as replacement for it: word joiner (U+2060). As this character has no
visible representation, and has no meaning at all when at the start or the end
of a string, it makes sense to include it in the "Tcl space set" as well, the
more because its predecessor had the ''White_Space'' property.

Finally, zero width space (U+200B), had the ''White_Space'' property in
Unicode 3.0. In the current Unicode Charts it is still listed as being a
space, even though the White_Space property was removed later. Therefore it
should be in the "Tcl space set" as well.

~ Specification

This document proposes:

 * For the ASCII set, '''string is space''' stays as is.  '''string trim'''
   will be modified to trim all characters for which '''string is space'''
   returns 1, augmented with the NUL character. This means that NUL, VT and FF
   will be added to the set. This is a '''potential incompatibility'''.

 * For characters outside ASCII, the Unicode '''White_Space'''
   [http://www.unicode.org/Public/6.2.0/ucd/PropList.txt] property forms the
   basis of what '''string is space''' and '''string trim''' consider being
   space. But 3 characters are added to the set: zero with space (U+200B),
   word joiner (U+2060) and zero width no-break space (U+FEFF) (i.e., the
   BOM).

The '''string trimleft''' and '''string trimright''' commands will also be
modified, as they track '''string trim'''.

~ Compatibility

For the ASCII set, the only change is the addition of 3 characters to
'''string trim'''. For Unicode there are more changes, but all added
characters are either rarely used, either intuitively expected to be trimmed
by '''string trim'''.  I don't think that any code will be adversely affected
by this change, it will probably fix more bugs than that it breaks any
existing code.

~ Alternatives

 1. NUL could be added to '''string is space''', but that would
    be in conflict with what POSIX ''isspace()'' function does.

 2. NUL could be left out of the '''string trim''' set.

 3. Additional characters I considered being part of the set:

|    break permitted here (U+0082)
|    no break here (U+0083)
|    zero width joiner (U+200C)
|    zero with non-joiner (U+200D)

  > Those are clearly useful characters to be stripped, as they have no
    meaning and no visible appearance at the beginning or end of a string. But
    they are not spaces, so it would diverge the two commands.

~ Reference Implementation

A reference implementation is available in the Tcl fossil repository on the
''tip-318-update'' branch [https://core.tcl.tk/tcl/timeline?r=tip-318-update].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|
|
|

|

|

|
|


|


|
|



|


|
|





|




|
|



|


|
|


|

|

|


|



|
|

|

|
|
|
|
|
|

|
|

|


|

|



|

|
|

|



|
|
|
|

|



|


|

|


>

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

# TIP 413: Unicode Support for 'string is space' and 'string trim'

	Author:         Jan Nijtmans <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        08-Oct-2012
	Post-History:   
	Discussions-To: Tcl Core list
	Keywords:       Tcl
	Tcl-Version:    8.6
-----

# Abstract

This TIP is in fact a re-consideration of [[318]](318.md), in that it attempts to
define, once and for all, for which characters **string is space** should
return 1 and which characters **string trim** should trim.

# Rationale

Intuitively, **string is space** and **string trim** should treat the same
characters as space, but currently that's not the case, even after the
implementation of [[318]](318.md).  The unicode standard advanced to version 6.2 now \(at
the time of this writing\), but also Java and .NET have their own views on what
whitespace should be. Let's try to learn from them.

## Defining the Tcl Space Set

The NUL character has the function as string separator, which could be
considered in the same group as LINE SEPARATOR \(U\+2028\) and PARAGRAPH
SEPARATOR \(U\+2029\). It's a very useful character to be stripped. It even had
the Whitespace property in Unicode 2.0. The problem with considering this
character as space is that its visible representation is not specified, it
even should not occur in normal text. Therefore, it is not in the "Tcl space
set", but it is very useful to let it be stripped by **string trim**.

The Unicode standard changed in time, which resulted in whitespace characters
being removed \(deprecated\) and added.  The _String.Trim\(\)_ method in .NET
3.5 stripped zero width space \(U\+200B\) and zero width no-break space \(U\+FEFF\)
from strings, but later .NET versions don't do that any more.  The "Tcl space
set" should not depend on that: If characters are deprecated in future Unicode
versions, and because of that Whitespace properties are changed, they will not
be removed from the "Tcl space set". But if new whitespace characters are
added in future Unicode standards, they will be added to the "Tcl space set"
as well, influencing both **string is space** and **string trim**.

The 3 characters that are in the "Tcl space set" but not in the current
Unicode whitespace set are discussed now.

Most obvious is zero width no-break space \(U\+FEFF\), which is a very useful
character to be stripped, as it is used now as Byte Order Mark \(BOM\). It has
no visible representation, and - in fact - no meaning at all within Tcl, as
Tcl is UTF-8 internally already. It should not occur anywhere else in the
string, but in the past it could as being a zero-width no-break space. It had
the _White\_Space_ property in Unicode 2.0, but later versions of Unicode do
not; the use of the BOM as a space was deprecated.

When the use as space was deprecated for \(U\+FEFF\), another character was put
forward as replacement for it: word joiner \(U\+2060\). As this character has no
visible representation, and has no meaning at all when at the start or the end
of a string, it makes sense to include it in the "Tcl space set" as well, the
more because its predecessor had the _White\_Space_ property.

Finally, zero width space \(U\+200B\), had the _White\_Space_ property in
Unicode 3.0. In the current Unicode Charts it is still listed as being a
space, even though the White\_Space property was removed later. Therefore it
should be in the "Tcl space set" as well.

# Specification

This document proposes:

 * For the ASCII set, **string is space** stays as is.  **string trim**
   will be modified to trim all characters for which **string is space**
   returns 1, augmented with the NUL character. This means that NUL, VT and FF
   will be added to the set. This is a **potential incompatibility**.

 * For characters outside ASCII, the Unicode **White\_Space**
   <http://www.unicode.org/Public/6.2.0/ucd/PropList.txt>  property forms the
   basis of what **string is space** and **string trim** consider being
   space. But 3 characters are added to the set: zero with space \(U\+200B\),
   word joiner \(U\+2060\) and zero width no-break space \(U\+FEFF\) \(i.e., the
   BOM\).

The **string trimleft** and **string trimright** commands will also be
modified, as they track **string trim**.

# Compatibility

For the ASCII set, the only change is the addition of 3 characters to
**string trim**. For Unicode there are more changes, but all added
characters are either rarely used, either intuitively expected to be trimmed
by **string trim**.  I don't think that any code will be adversely affected
by this change, it will probably fix more bugs than that it breaks any
existing code.

# Alternatives

 1. NUL could be added to **string is space**, but that would
    be in conflict with what POSIX _isspace\(\)_ function does.

 2. NUL could be left out of the **string trim** set.

 3. Additional characters I considered being part of the set:

		    break permitted here (U+0082)
		    no break here (U+0083)
		    zero width joiner (U+200C)
		    zero with non-joiner (U+200D)

	  > Those are clearly useful characters to be stripped, as they have no
    meaning and no visible appearance at the beginning or end of a string. But
    they are not spaces, so it would diverge the two commands.

# Reference Implementation

A reference implementation is available in the Tcl fossil repository on the
_tip-318-update_ branch <https://core.tcl.tk/tcl/timeline?r=tip-318-update> .

# Copyright

This document has been placed in the public domain.

Name change from tip/414.tip to tip/414.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

TIP:            414
Title:          Add (back) Tcl_InitSubsystems as Public API
Version:        $Revision: 1.25 $
Author:         Brian Griffin <[email protected]>
Author:         Jan Nijtmans <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        15-Oct-2012
Post-History:   
Tcl-Version:    8.7


~ Abstract

The ability to initialize just the lower level Tcl subsystems used to be part
of the public API, now it is no longer exposed. This TIP proposes that it be
re-exposed.

~ Rationale

Some parts of Tcl's API are useful in portable applications even without
creating a Tcl interpreter; examples of this include Tcl_Alloc and (most of)
the Tcl_DString-related functions. In order to use these functions correctly,
the Tcl library ''must'' be initialized, yet the function for doing so -
Tcl_InitSubsystems (currently TclInitSubsystems) - was removed from Tcl's API;
using Tcl_FindExecutable instead feels incorrect as we're not seeking to make
the name of the executable available to Tcl scripts.

~ Proposed Change

A new function Tcl_InitSubsystems, similar to the internal TclInitSubsystems,
should be exposed as alternative to Tcl_FindExecutable in Tcl's C API. This
will ''not'' be a part of the Stub API; it is not intended to ever be used
from an initialized stubbed environment, as it is meant to be used prior to
the stub table being available. It has a single argument, ''panicProc''.
When NULL, the default panic function is used. The full signature is:

 > EXTERN const char *
   '''Tcl_InitSubsystems'''(
       Tcl_PanicProc *''panicProc'');

The return value of ''Tcl_InitSubsystems'' is the Tcl version.

~ Reference Implementation

A reference implementation is available in the '''initsubsystems''' branch.
[http://core.tcl.tk/tcl/info/3c9828933f]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|


|
|
|
|
|


|

|
|
|

|


|
|
|

|

|

|
|

|


>

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

# TIP 414: Add (back) Tcl_InitSubsystems as Public API

	Author:         Brian Griffin <[email protected]>
	Author:         Jan Nijtmans <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        15-Oct-2012
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

The ability to initialize just the lower level Tcl subsystems used to be part
of the public API, now it is no longer exposed. This TIP proposes that it be
re-exposed.

# Rationale

Some parts of Tcl's API are useful in portable applications even without
creating a Tcl interpreter; examples of this include Tcl\_Alloc and \(most of\)
the Tcl\_DString-related functions. In order to use these functions correctly,
the Tcl library _must_ be initialized, yet the function for doing so -
Tcl\_InitSubsystems \(currently TclInitSubsystems\) - was removed from Tcl's API;
using Tcl\_FindExecutable instead feels incorrect as we're not seeking to make
the name of the executable available to Tcl scripts.

# Proposed Change

A new function Tcl\_InitSubsystems, similar to the internal TclInitSubsystems,
should be exposed as alternative to Tcl\_FindExecutable in Tcl's C API. This
will _not_ be a part of the Stub API; it is not intended to ever be used
from an initialized stubbed environment, as it is meant to be used prior to
the stub table being available. It has a single argument, _panicProc_.
When NULL, the default panic function is used. The full signature is:

 > EXTERN const char \*
   **Tcl\_InitSubsystems**\(
       Tcl\_PanicProc \*_panicProc_\);

The return value of _Tcl\_InitSubsystems_ is the Tcl version.

# Reference Implementation

A reference implementation is available in the **initsubsystems** branch.
<http://core.tcl.tk/tcl/info/3c9828933f> 

# Copyright

This document has been placed in the public domain.

Name change from tip/415.tip to tip/415.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

TIP:            415
Title:          Enable Easy Creation of Circular Arc Segments
Version:        $Revision: 1.11 $
Author:         Simon Geard <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        16-Oct-2012
Post-History:   
Keywords:       Tk
Tcl-Version:    8.7


~ Abstract

Creating a segment of a circular arc is unnecessarily difficult using the
'''canvas''' arc. This TIP proposes a simple extension of the syntax to
support the creation of circular arc segments in a natural way. A similar
extension to support the more general elliptical arc segments is outside the
scope of this TIP.

~ Rationale

There is scope to enhance arc creation to make it much more useful as was
shown by a recent discussion on news:comp.lang.tcl. The proposal here is the
simplest enhancement to enable creation of circular arc segments from a single
parameter.

~ Proposal

Enhance arc creation to support a new '''-height''' option

 > ''canvas'' '''create arc''' ''x1 y1 x2 y2'' '''-height''' ''h'' ?''options''?

The new option '''-height''' ''h'' causes the specified coordinates ''x1 y1'' and '' x2 y2'' to be interpreted as the
start and end points of the arc's chord. The value of ''h'' is the (canvas) distance of the arc's
mid-point from the chord with the sign of ''h'' determining the direction of the arc:

''h'' > 0 => clockwise
''h'' < 0 => anticlockwise

If ''h'' != 0 then the options ''-start'' and ''-extent'' are ignored (because they are calculated internally for a given ''h'').

Any non-zero value of ''h'' defines a unique arc.

If ''h'' = 0 (exactly) the option is ignored and the command is processed as if it wasn't present. In addition

 > ''canvas'' '''itemcget''' ''tagOrId'' ''--height'''

will always return 0. This behaviour enables introspection without complications. A consequence is that

 > ''canvas'' '''itemconfigure''' ''tagOrId'' ''--height''' ''0''

 is a no-op.

~ Example

The following code shows the creation of arcs using the new method, copying them onto another canvas
and using a '''scale''' widget to dynamically control the arcs

|# Callback for modifying the arcs' h value
|proc deltaHeight {h} {
|	global c
|	global arcList
|	foreach {i hp hm} $arcList {
|		$c itemconfigure a_$i -height [expr {$h*$hp}]
|		$c itemconfigure b_$i -height [expr {$h*$hm}]
|	}
|}


|
|# Create the canvas and its duplicate
|set c [canvas .c -width 700 -height 700 -bg grey]
|set cc [canvas .cc -width 700 -height 700 -bg grey]
|pack $c $cc -fill both -expand 1 -side left
|
|# Pretty colours
|array set colours {0 red 1 yellow 2 green 3 cyan 4 blue 5 magenta}
|
|# A slider with which to adjust h
|set lh 1; # Initial setting for scale
|set s [scale .s -from 0.1 -to 15 -resolution 0.1 -variable lh -orient vertical -length 700 -command deltaHeight]
|pack $s -side right -fill y
|
|# Create the arcs
|for {set i 1} {$i <= 24} {incr i} {
|	set col [expr {$i % 6}]
|	set hp [expr {$i*10}]
|	set hm [expr {-$i*10}]
|	lappend arcList $i $hp $hm
|	$c create arc 300 200 400 400 -height [expr {$i*10}] -outline $colours($col) -style arc -tags [list aa a_$i]
|	$c create arc 300 200 400 400 -height [expr {-$i*10}] -outline $colours($col) -style arc -tags [list aa b_$i]
|}

|
|# Serialize
|set fh [open "ccopy.tcl" w]
|foreach id [$c find withtag aa] {
|    puts $fh "\$cc create arc [$c coords $id] \
|		-height [$c itemcget $id -height]\
|		-start [$c itemcget $id -start] \
|		-extent [$c itemcget $id -extent] \
|		-outline [$c itemcget $id -outline] \
|		-style [$c itemcget $id -style]"
|}

|close $fh
|
|# Create copy from serialization
|source "ccopy.tcl"

~ Reference Implementation

A reference implementation for the functionality is available.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|




|






|

|

|

|
|
|

|
|

|

|

|

|



|



|


|

|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|

|



|


>

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

# TIP 415: Enable Easy Creation of Circular Arc Segments

	Author:         Simon Geard <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        16-Oct-2012
	Post-History:   
	Keywords:       Tk
	Tcl-Version:    8.7
-----

# Abstract

Creating a segment of a circular arc is unnecessarily difficult using the
**canvas** arc. This TIP proposes a simple extension of the syntax to
support the creation of circular arc segments in a natural way. A similar
extension to support the more general elliptical arc segments is outside the
scope of this TIP.

# Rationale

There is scope to enhance arc creation to make it much more useful as was
shown by a recent discussion on news:comp.lang.tcl. The proposal here is the
simplest enhancement to enable creation of circular arc segments from a single
parameter.

# Proposal

Enhance arc creation to support a new **-height** option

 > _canvas_ **create arc** _x1 y1 x2 y2_ **-height** _h_ ?_options_?

The new option **-height** _h_ causes the specified coordinates _x1 y1_ and _ x2 y2_ to be interpreted as the
start and end points of the arc's chord. The value of _h_ is the \(canvas\) distance of the arc's
mid-point from the chord with the sign of _h_ determining the direction of the arc:

_h_ > 0 => clockwise
_h_ < 0 => anticlockwise

If _h_ != 0 then the options _-start_ and _-extent_ are ignored \(because they are calculated internally for a given _h_\).

Any non-zero value of _h_ defines a unique arc.

If _h_ = 0 \(exactly\) the option is ignored and the command is processed as if it wasn't present. In addition

 > _canvas_ **itemcget** _tagOrId_ _--height**

will always return 0. This behaviour enables introspection without complications. A consequence is that

 > _canvas_ **itemconfigure** _tagOrId_ _--height** _0_

 is a no-op.

# Example

The following code shows the creation of arcs using the new method, copying them onto another canvas
and using a **scale** widget to dynamically control the arcs

	# Callback for modifying the arcs' h value
	proc deltaHeight {h} {
		global c
		global arcList
		foreach {i hp hm} $arcList {
			$c itemconfigure a_$i -height [expr {$h*$hp}]
			$c itemconfigure b_$i -height [expr {$h*$hm}]


		}
	}
	
	# Create the canvas and its duplicate
	set c [canvas .c -width 700 -height 700 -bg grey]
	set cc [canvas .cc -width 700 -height 700 -bg grey]
	pack $c $cc -fill both -expand 1 -side left
	
	# Pretty colours
	array set colours {0 red 1 yellow 2 green 3 cyan 4 blue 5 magenta}
	
	# A slider with which to adjust h
	set lh 1; # Initial setting for scale
	set s [scale .s -from 0.1 -to 15 -resolution 0.1 -variable lh -orient vertical -length 700 -command deltaHeight]
	pack $s -side right -fill y
	
	# Create the arcs
	for {set i 1} {$i <= 24} {incr i} {
		set col [expr {$i % 6}]
		set hp [expr {$i*10}]
		set hm [expr {-$i*10}]
		lappend arcList $i $hp $hm
		$c create arc 300 200 400 400 -height [expr {$i*10}] -outline $colours($col) -style arc -tags [list aa a_$i]
		$c create arc 300 200 400 400 -height [expr {-$i*10}] -outline $colours($col) -style arc -tags [list aa b_$i]

	}
	
	# Serialize
	set fh [open "ccopy.tcl" w]
	foreach id [$c find withtag aa] {
	    puts $fh "\$cc create arc [$c coords $id] \
			-height [$c itemcget $id -height]\
			-start [$c itemcget $id -start] \
			-extent [$c itemcget $id -extent] \
			-outline [$c itemcget $id -outline] \
			-style [$c itemcget $id -style]"

	}
	close $fh
	
	# Create copy from serialization
	source "ccopy.tcl"

# Reference Implementation

A reference implementation for the functionality is available.

# Copyright

This document has been placed in the public domain.

Name change from tip/416.tip to tip/416.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
136

TIP:            416
Title:          New Options for 'load': -global and -lazy
Version:        $Revision: 1.5 $
Author:         Christian Delbaere <[email protected]>
Author:         Jan Nijtmans <[email protected]>
Author:         Jan Nijtmans <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        31-Oct-2012
Post-History:   
Tcl-Version:    8.6


~ Abstract

This TIP proposes enhancing the Tcl '''load''' command with the additional
options '''-global''' and '''-lazy'''. It is implemented on top of [357], by
defining a meaning to the '''flags''' parameter already defined there.

~ Rationale

Platforms that use the ''dlopen()'' function to Tcl '''load''' shared modules
at runtime provide options to control how the library is loaded:

 * global vs. local symbol scoping

 * lazy vs. now symbol resolution

Currently, Tcl's '''load''' command has hard coded defaults for these options
and they cannot be overridden within a Tcl script.  This imposes constraints on
the internal implementation of the modules intended to be loaded into the
interpreter.  This is especially problematic for modules that provide Tcl
scripting bindings for existing C++ APIs.  Often, the C++ APIs make
assumptions about the availability and scoping of their symbols.

Tcl binding packages for C++ APIs are often created by a different development
group than the one that created the original C++ API.  Because the two groups
are independent, the C++ API maintainers will not always be open or able to
change their code to fit the requirements to be loaded into a scripting
language.

A common problem occurs when the same static variable is present in two
different Tcl modules.  For some applications, the variable is meant to be
shared across modules (global scoping), while in other applications, the
variable must have its own value within each module (local scoping).  If the
wrong scoping is chosen, the underlying code will not work correctly; rather
it will yield strange bugs and / or crashes.

Also in the domain of Tcl bindings for C++ APIs: it's convenient for the
binding package maintainers to have binary compatibility between one version
of the Tcl API and several versions of the C++ API.  The '''-lazy''' flag for
Tcl's load command will provides the feature necessary for this flexibility,
since it can be used to defer missing symbol errors.  So, users can often
continue to run their scripts as long as they restrict themselves to calling
only commands where the symbols are available.

Of course, some applications work best when '''load''' is called with
'''-global''' and some work best without it.  The same can be said for
'''-lazy'''.  By providing these options, Tcl will allow programmers to choose
the best fit for their application.

~ Specification

In [357], the ''Tcl_LoadFile'' is given as:

 > EXTERN int
   '''Tcl_LoadFile'''(
       Tcl_Interp *''interp'',
       Tcl_Obj *''pathPtr'',
       const char *''symbols''[],
       int ''flags'',
       void *''procPtrs'',
       Tcl_LoadHandle *''handlePtr'');

The meaning of the ''flags'' parameter is not defined in TIP #357, except
that the current value should be 0. This TIP defines the meaning of the first
two bits of this parameter:

|#define TCL_LOAD_GLOBAL 1
|#define TCL_LOAD_LAZY 2

Any combination (logical or) of those two bits can be given to the ''flags''
parameter. The remaining bits are meant for future extension and are
currently ignored, but should be set to 0.

The '''load''' command will get two new options:

Current specification:

 > '''load''' ''fileName'' ?''packageName'' ?''interp''??

Recommended specification:

 > '''load''' ?'''-global'''? ?'''-lazy'''? ?'''--'''? ''fileName''
   ?''packageName'' ?''interp''??

~ Discussion

Not all platforms may support library loading to a degree required for this
TIP functionality.  In that case, the additional options just act as if they
were not there. The reference implementation works on most modern UNIX systems
and MacOSX, which use ''dlopen()'' or ''NSLinkModule()''. Windows does not allow
lazy symbol resolution or global scoping, so the options have no effect on Windows.

The '''load''' command will determine the use of the new form by checking if
more than one argument is given and the first argument starts with a '''-'''.
This should not affect any existing extensions, as dynamic library filenames
beginning with '''-''' are rare.

Note that use of the '''-global''' or '''-lazy''' option may lead to crashes in your
application later (in case of symbol conflicts resp. missing symbols), which cannot
be detected during the '''load'''. So, only use this when you know what you are doing,
you will not get a nice error message when something is wrong with the loaded library.

~ Examples

Load a module with the defaults (local scoping, "now" resolution)

| load module.so

Load the module with global scoping and "now" resolution

| load -global module.so

Load the module with global scoping and lazy resolution

| load -global -lazy module.so

~ Reference Implementation

A reference implementation is available in the '''frq-3579001''' branch; see
https://core.tcl.tk/tcl/timeline?r=frq-3579001

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|
|
|

|

|






|



|


|
|
|





|
|



|

|





|
|
|


|

|


|
|
|
|
|
|
|

|



|
|

|



|



|



|
|

|




|


|
|

|

|
|
|


|

|

|



|



|

|

|
|

|


>

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
136

# TIP 416: New Options for 'load': -global and -lazy

	Author:         Christian Delbaere <[email protected]>
	Author:         Jan Nijtmans <[email protected]>
	Author:         Jan Nijtmans <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        31-Oct-2012
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes enhancing the Tcl **load** command with the additional
options **-global** and **-lazy**. It is implemented on top of [[357]](357.md), by
defining a meaning to the **flags** parameter already defined there.

# Rationale

Platforms that use the _dlopen\(\)_ function to Tcl **load** shared modules
at runtime provide options to control how the library is loaded:

 * global vs. local symbol scoping

 * lazy vs. now symbol resolution

Currently, Tcl's **load** command has hard coded defaults for these options
and they cannot be overridden within a Tcl script.  This imposes constraints on
the internal implementation of the modules intended to be loaded into the
interpreter.  This is especially problematic for modules that provide Tcl
scripting bindings for existing C\+\+ APIs.  Often, the C\+\+ APIs make
assumptions about the availability and scoping of their symbols.

Tcl binding packages for C\+\+ APIs are often created by a different development
group than the one that created the original C\+\+ API.  Because the two groups
are independent, the C\+\+ API maintainers will not always be open or able to
change their code to fit the requirements to be loaded into a scripting
language.

A common problem occurs when the same static variable is present in two
different Tcl modules.  For some applications, the variable is meant to be
shared across modules \(global scoping\), while in other applications, the
variable must have its own value within each module \(local scoping\).  If the
wrong scoping is chosen, the underlying code will not work correctly; rather
it will yield strange bugs and / or crashes.

Also in the domain of Tcl bindings for C\+\+ APIs: it's convenient for the
binding package maintainers to have binary compatibility between one version
of the Tcl API and several versions of the C\+\+ API.  The **-lazy** flag for
Tcl's load command will provides the feature necessary for this flexibility,
since it can be used to defer missing symbol errors.  So, users can often
continue to run their scripts as long as they restrict themselves to calling
only commands where the symbols are available.

Of course, some applications work best when **load** is called with
**-global** and some work best without it.  The same can be said for
**-lazy**.  By providing these options, Tcl will allow programmers to choose
the best fit for their application.

# Specification

In [[357]](357.md), the _Tcl\_LoadFile_ is given as:

 > EXTERN int
   **Tcl\_LoadFile**\(
       Tcl\_Interp \*_interp_,
       Tcl\_Obj \*_pathPtr_,
       const char \*_symbols_[],
       int _flags_,
       void \*_procPtrs_,
       Tcl\_LoadHandle \*_handlePtr_\);

The meaning of the _flags_ parameter is not defined in TIP \#357, except
that the current value should be 0. This TIP defines the meaning of the first
two bits of this parameter:

	#define TCL_LOAD_GLOBAL 1
	#define TCL_LOAD_LAZY 2

Any combination \(logical or\) of those two bits can be given to the _flags_
parameter. The remaining bits are meant for future extension and are
currently ignored, but should be set to 0.

The **load** command will get two new options:

Current specification:

 > **load** _fileName_ ?_packageName_ ?_interp_??

Recommended specification:

 > **load** ?**-global**? ?**-lazy**? ?**--**? _fileName_
   ?_packageName_ ?_interp_??

# Discussion

Not all platforms may support library loading to a degree required for this
TIP functionality.  In that case, the additional options just act as if they
were not there. The reference implementation works on most modern UNIX systems
and MacOSX, which use _dlopen\(\)_ or _NSLinkModule\(\)_. Windows does not allow
lazy symbol resolution or global scoping, so the options have no effect on Windows.

The **load** command will determine the use of the new form by checking if
more than one argument is given and the first argument starts with a **-**.
This should not affect any existing extensions, as dynamic library filenames
beginning with **-** are rare.

Note that use of the **-global** or **-lazy** option may lead to crashes in your
application later \(in case of symbol conflicts resp. missing symbols\), which cannot
be detected during the **load**. So, only use this when you know what you are doing,
you will not get a nice error message when something is wrong with the loaded library.

# Examples

Load a module with the defaults \(local scoping, "now" resolution\)

	 load module.so

Load the module with global scoping and "now" resolution

	 load -global module.so

Load the module with global scoping and lazy resolution

	 load -global -lazy module.so

# Reference Implementation

A reference implementation is available in the **frq-3579001** branch; see
<https://core.tcl.tk/tcl/timeline?r=frq-3579001>

# Copyright

This document has been placed in the public domain.

Name change from tip/417.tip to tip/417.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

TIP:		417
Title:		Use Explicit Option Names for "file tempfile"
Version:	$Revision: 1.1 $
Author:		Christophe Curis <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Created:	16-Nov-2012
Post-History:
Keywords:	Tcl, future expansion, extensibility


~ Abstract

This TIP proposes altering the way in which optional arguments are specified
to '''file tempfile''' (see [210]) to make them easier to understand and
extend in the future.

~ Rationale

The current documentation for '''file tempfile''' states that there are two
optional arguments using a fixed order. This has some limits:

 * it is not possible to use the second argument without the first

 * being an infrequently-used function, having a fixed order implies that a
   look to the manual page will be obligatory to make sure of the order

 * this inhibits potential for any future expansion of the command.

Switching to option/value format will make the optional arguments easier to
understand.

~ Proposal

The syntax of the command would be changed to:

 > '''file tempfile''' ?''options...''?

with supported ''options'':

 * '''-namevar'''
   ''variable'': Specifies a variable for receiving the file name.

 * '''-template'''
   ''template'': Defines a template for the file name.

This syntax would allow:

 * easy extension in the future, as any option name can be added,

 * ability to use any of the options in any order,

 * an explicit syntax making the code easier to read and understand.

~ Reference Implementation

No implementation is available now, but the change is probably not complex;
the priority have been placed on raising the subject before the release of the
final 8.6 version of Tcl.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|


|

|












|



|

|

|
|

|
|









|





|


>

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

# TIP 417: Use Explicit Option Names for "file tempfile"

	Author:		Christophe Curis <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Created:	16-Nov-2012
	Post-History:
	Keywords:	Tcl, future expansion, extensibility
-----

# Abstract

This TIP proposes altering the way in which optional arguments are specified
to **file tempfile** \(see [[210]](210.md)\) to make them easier to understand and
extend in the future.

# Rationale

The current documentation for **file tempfile** states that there are two
optional arguments using a fixed order. This has some limits:

 * it is not possible to use the second argument without the first

 * being an infrequently-used function, having a fixed order implies that a
   look to the manual page will be obligatory to make sure of the order

 * this inhibits potential for any future expansion of the command.

Switching to option/value format will make the optional arguments easier to
understand.

# Proposal

The syntax of the command would be changed to:

 > **file tempfile** ?_options..._?

with supported _options_:

 * **-namevar**
   _variable_: Specifies a variable for receiving the file name.

 * **-template**
   _template_: Defines a template for the file name.

This syntax would allow:

 * easy extension in the future, as any option name can be added,

 * ability to use any of the options in any order,

 * an explicit syntax making the code easier to read and understand.

# Reference Implementation

No implementation is available now, but the change is probably not complex;
the priority have been placed on raising the subject before the release of the
final 8.6 version of Tcl.

# Copyright

This document has been placed in the public domain.

Name change from tip/418.tip to tip/418.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
136
137
138
139
140
141
142
143
144
145
146

TIP:            418
Title:          Add [binary] Subcommands for In-Place Modification
Version:        $Revision: 1.3 $
Author:         Jeff Rogers <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        27-Aug-2012
Post-History:   
Keywords:       Tcl,binary data
Tcl-Version:    8.7


~ Abstract

This TIP proposes adding new subcommands to the '''binary''' to better enable
parsing and manipulation of binary values.

~ Rationale

The '''binary''' command efficiently deals with creating new objects or
completely parsing existing ones, but it does not handle modifying existing
binary objects or parsing them a little bit at a time.  A few new subcommands
would greatly improve the performance of these operations on large objects.

~~ Variable vs. Value

While it will be possible to implement these modification operations as
standard copy-on-write operations taking a value instead of a variable name, I
believe this would result in copying unless the well-known but still clumsy
technique of unsetting the variable after reading it (i.e., [[K $x [[set x {}]]]]) 
is used. This TIP is intended to fix this by providing a more
convenient and simpler-to-use mechanism which also admits more efficient
implementation.

~ Specification

Two new core subcommands are proposed: '''binary edit''' modifies an existing
byte array "in place"; and '''binary scanshift''' parse data from a byte array
and removes the data that was parsed.  The intent is that additional commands
can be built on top of these in library code.

The existing '''binary''' commands already make use of an internal cursor;
that notion is extensively used by these new commands.

~~ Binary Edit

 > '''binary edit''' ''varName formatStr'' ?''value value ...''?

This is similar to '''binary format''' except that the initial value of the
new byte array is an existing object stored in a variable rather than an array
of nulls.

Format specifiers in ''formatStr'' are as in '''binary format''' except:

 * fixed-width format specifiers (e.g., '''c''', '''s''', '''i''') that do not
   have enough values in their corresponding argument (importantly, if they
   have 0 values) move the cursor by the appropriate width.

 * New '''z''' and '''Z''' format specifiers are introduced that move the
   cursor forward or backward in the binary string without writing anything
   and consume no arguments. '''Z''' is a synonym for "X", provided for
   symmetry.  A count of "'''*'''" for the "'''z'''" format moves the cursor
   to the end of the existing object.

After the format string and all arguments have been processed, the length of
the string is adjusted to end at the current cursor position.

Thus, a format string that starts with "z*" will append to the existing value,
and one that ends with "z*" will keep the length the same.

~~ Binary Scanshift

 > '''binary scanshift''' ''varName formatStr'' ?''var var var ...''?

This works like '''binary scan''' except that after the format string has been
processed and all variables assigned to, all data in the string before the
ending location of the cursor is discarded.

Thus,

|binary scanshift bvar c byte1
|binary scanshift bvar c byte2
|binary scanshift bvar c byte3

Will put the first 3 bytes of the binary ''$bvar'' into ''byte1'', ''byte2'',
and ''byte3'', with ''bvar'' being subsequently three bytes shorter (the
missing bytes being the first three).

This is useful to avoid keeping a separate external cursor variable that must
be incremented and re-used on each iteration.

~~ Additional Library Commands

Suggested additional library commands are '''poke''' and '''append'''. The
arguments to '''binary poke''' will be:

 > '''binary poke''' ''varName index formatStr'' ?''var ...''?

This moves the cursor to a specified index, then overwrite with the specified
format string.  Implemented as

|      binary edit varName "@${index} $formatStr z*" var ...

The arguments to '''binary append''' will be:

 > '''binary append''' ''varName formatStr'' "?''var ...''?

This appends the given formatted data to an existing var.  Implemented as

|      binary edit varName "z* $formatStr" ?var ...?"

~ Implementation Notes

Efficient implementation of the "'''scanshift'''" subcommand requires a new
"offset" field in the ByteArray structure and any operations that read the
object (particularly duplicating it and updating the string representation)
need to be aware of this field.  All external interfaces should be unaffected,
as the ByteArray structure type is private to tclBinary.c, And since it's
internal, EIAS is not violated.

When extending an existing byte array with the "'''edit'''" subcommand, care
should be taken with memory allocation to avoid repeated ''realloc()'' and
''memcpy()'' operations.  It is a reasonable assumption that a given byte
array will be extended repeatedly or not at all beyond the initial creation.
So a memory allocation strategy is to allocate the exact length initially
(i.e., when adjusting the size from 0 to non-zero) and allocating double the
requested length subsequently a typical allocation-doubling strategy should
work well.  A double allocation should not be needed for an initial extension
(i.e., extending from 0 to some length) as that is typically the case when a
binary object is first created, and most binary objects will probably not be
extended; but once extended it is reasonable to prepare for more of the same.

After numerous "'''scanshift'''" operations there will be wasted space at the
beginning of the memory allocated for the data.  One strategy for keeping this
under control would be to move the live data to the beginning of the allocated
space when the offset is larger than the live data, so that the memory could
be copied without worrying about overlap; and this would also leave the
allocation size at roughly double the live data size.

~ Reference Implementation

Forthcoming.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|




|




|




|

|
|



|


|

|

|



|

|
|
|

|

|
|





|
|

|

|

|





|
|
|

|
|
|




|

|
|

|




|

|

|



|

|

|

|




|
|
|


|


|



|






|



|


>

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
136
137
138
139
140
141
142
143
144
145
146

# TIP 418: Add [binary] Subcommands for In-Place Modification

	Author:         Jeff Rogers <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        27-Aug-2012
	Post-History:   
	Keywords:       Tcl,binary data
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes adding new subcommands to the **binary** to better enable
parsing and manipulation of binary values.

# Rationale

The **binary** command efficiently deals with creating new objects or
completely parsing existing ones, but it does not handle modifying existing
binary objects or parsing them a little bit at a time.  A few new subcommands
would greatly improve the performance of these operations on large objects.

## Variable vs. Value

While it will be possible to implement these modification operations as
standard copy-on-write operations taking a value instead of a variable name, I
believe this would result in copying unless the well-known but still clumsy
technique of unsetting the variable after reading it \(i.e., [K $x [set x {}]]\) 
is used. This TIP is intended to fix this by providing a more
convenient and simpler-to-use mechanism which also admits more efficient
implementation.

# Specification

Two new core subcommands are proposed: **binary edit** modifies an existing
byte array "in place"; and **binary scanshift** parse data from a byte array
and removes the data that was parsed.  The intent is that additional commands
can be built on top of these in library code.

The existing **binary** commands already make use of an internal cursor;
that notion is extensively used by these new commands.

## Binary Edit

 > **binary edit** _varName formatStr_ ?_value value ..._?

This is similar to **binary format** except that the initial value of the
new byte array is an existing object stored in a variable rather than an array
of nulls.

Format specifiers in _formatStr_ are as in **binary format** except:

 * fixed-width format specifiers \(e.g., **c**, **s**, **i**\) that do not
   have enough values in their corresponding argument \(importantly, if they
   have 0 values\) move the cursor by the appropriate width.

 * New **z** and **Z** format specifiers are introduced that move the
   cursor forward or backward in the binary string without writing anything
   and consume no arguments. **Z** is a synonym for "X", provided for
   symmetry.  A count of "**\***" for the "**z**" format moves the cursor
   to the end of the existing object.

After the format string and all arguments have been processed, the length of
the string is adjusted to end at the current cursor position.

Thus, a format string that starts with "z\*" will append to the existing value,
and one that ends with "z\*" will keep the length the same.

## Binary Scanshift

 > **binary scanshift** _varName formatStr_ ?_var var var ..._?

This works like **binary scan** except that after the format string has been
processed and all variables assigned to, all data in the string before the
ending location of the cursor is discarded.

Thus,

	binary scanshift bvar c byte1
	binary scanshift bvar c byte2
	binary scanshift bvar c byte3

Will put the first 3 bytes of the binary _$bvar_ into _byte1_, _byte2_,
and _byte3_, with _bvar_ being subsequently three bytes shorter \(the
missing bytes being the first three\).

This is useful to avoid keeping a separate external cursor variable that must
be incremented and re-used on each iteration.

## Additional Library Commands

Suggested additional library commands are **poke** and **append**. The
arguments to **binary poke** will be:

 > **binary poke** _varName index formatStr_ ?_var ..._?

This moves the cursor to a specified index, then overwrite with the specified
format string.  Implemented as

	      binary edit varName "@${index} $formatStr z*" var ...

The arguments to **binary append** will be:

 > **binary append** _varName formatStr_ "?_var ..._?

This appends the given formatted data to an existing var.  Implemented as

	      binary edit varName "z* $formatStr" ?var ...?"

# Implementation Notes

Efficient implementation of the "**scanshift**" subcommand requires a new
"offset" field in the ByteArray structure and any operations that read the
object \(particularly duplicating it and updating the string representation\)
need to be aware of this field.  All external interfaces should be unaffected,
as the ByteArray structure type is private to tclBinary.c, And since it's
internal, EIAS is not violated.

When extending an existing byte array with the "**edit**" subcommand, care
should be taken with memory allocation to avoid repeated _realloc\(\)_ and
_memcpy\(\)_ operations.  It is a reasonable assumption that a given byte
array will be extended repeatedly or not at all beyond the initial creation.
So a memory allocation strategy is to allocate the exact length initially
\(i.e., when adjusting the size from 0 to non-zero\) and allocating double the
requested length subsequently a typical allocation-doubling strategy should
work well.  A double allocation should not be needed for an initial extension
\(i.e., extending from 0 to some length\) as that is typically the case when a
binary object is first created, and most binary objects will probably not be
extended; but once extended it is reasonable to prepare for more of the same.

After numerous "**scanshift**" operations there will be wasted space at the
beginning of the memory allocated for the data.  One strategy for keeping this
under control would be to move the live data to the beginning of the allocated
space when the offset is larger than the live data, so that the memory could
be copied without worrying about overlap; and this would also leave the
allocation size at roughly double the live data size.

# Reference Implementation

Forthcoming.

# Copyright

This document has been placed in the public domain.

Name change from tip/419.tip to tip/419.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

TIP:            419
Title:          A New Command for Binding to Tk Events
Version:        $Revision: 1.2 $
Author:         Jeff Rogers <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        28-Aug-2012
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes a more modern mechanism for binding callbacks to Tk's
events.

~ Rationale

The Tk '''bind'''' command passes details about an event to a callback script
by doing a textual substitution of percent markers.  This has worked well for
years, however most recent code prefers to use command prefixes to which set
arguments are appended rather than scripts which are evaluated.  This TIP
proposes such an approach for tk event binding.

~ Specification

A new command, "tkevent" is introduced with the following syntax:

 > '''tkevent''' ''tag'' ''sequence'' ''cmd''

The ''tag'' and ''sequence'' arguments are the same as used in the '''bind'''
command. The ''cmd'' is evaluated by appending a single argument which is a
dictionary containing the event details.  The implementation of ''cmd'' can
retrieve details of the event using that dictionary.

Bindings created by '''tkevent''' are compatible with those created by
'''bind'''.  When a sequence is bound to a tag using '''tkevent''', it
replaces any previous binding, and vice versa.  Appending to a binding with
"bind tag sequence +script" may not work as expected.

The possible keys in the dict passed to the handler are:

|        serial        above         button
|        count         detail        focus
|        height        window        keycode
|        mode          override_redirect
|        place         state         time
|        width         x             y
|        character     border_width  delta
|        send_event    keysym        keysym_num
|        property      root          subwindow
|        type          window        xroot
|        yroot

These keys are intended to be be the same as the options to '''event
generate''' where applicable.

Not all values are legal for all event types; where a key is not legal for an
event type, it will not be present in the dictionary when the ''cmd'' bound to
that event is evaluated.

~ Reference Implementation

A sample implementation of these commands in pure tcl is available at
http://wiki.tcl.tk/tkevent

~ Cross-Compatibility with Bind

Except for the "+script" feature, '''bind''' and '''tkevent''' support
identical functionality, and either could be implemented in terms of the
other. If '''bind''' as a core command was dropped in favor of '''tkevent''',
it could be provided as a library implementation.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|




|

|





|



|

|
|
|


|
|

|



|
|
|
|
|
|
|
|
|
|
|

|
|


|


|


|

|

|

|


|


>

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

# TIP 419: A New Command for Binding to Tk Events

	Author:         Jeff Rogers <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        28-Aug-2012
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes a more modern mechanism for binding callbacks to Tk's
events.

# Rationale

The Tk **bind**' command passes details about an event to a callback script
by doing a textual substitution of percent markers.  This has worked well for
years, however most recent code prefers to use command prefixes to which set
arguments are appended rather than scripts which are evaluated.  This TIP
proposes such an approach for tk event binding.

# Specification

A new command, "tkevent" is introduced with the following syntax:

 > **tkevent** _tag_ _sequence_ _cmd_

The _tag_ and _sequence_ arguments are the same as used in the **bind**
command. The _cmd_ is evaluated by appending a single argument which is a
dictionary containing the event details.  The implementation of _cmd_ can
retrieve details of the event using that dictionary.

Bindings created by **tkevent** are compatible with those created by
**bind**.  When a sequence is bound to a tag using **tkevent**, it
replaces any previous binding, and vice versa.  Appending to a binding with
"bind tag sequence \+script" may not work as expected.

The possible keys in the dict passed to the handler are:

	        serial        above         button
	        count         detail        focus
	        height        window        keycode
	        mode          override_redirect
	        place         state         time
	        width         x             y
	        character     border_width  delta
	        send_event    keysym        keysym_num
	        property      root          subwindow
	        type          window        xroot
	        yroot

These keys are intended to be be the same as the options to **event
generate** where applicable.

Not all values are legal for all event types; where a key is not legal for an
event type, it will not be present in the dictionary when the _cmd_ bound to
that event is evaluated.

# Reference Implementation

A sample implementation of these commands in pure tcl is available at
<http://wiki.tcl.tk/tkevent>

# Cross-Compatibility with Bind

Except for the "\+script" feature, **bind** and **tkevent** support
identical functionality, and either could be implemented in terms of the
other. If **bind** as a core command was dropped in favor of **tkevent**,
it could be provided as a library implementation.

# Copyright

This document has been placed in the public domain.

Name change from tip/42.tip to tip/42.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
TIP:		42
Title:          Add New Standard Tk Option: -clientdata
Version:	$Revision: 1.4 $
Author:         Bryan Oakley <[email protected]>
State:		Withdrawn
Type:           Project
Vote:		Pending
Created:	05-Jul-2001
Post-History:	
Tcl-Version:    8.5


~ Abstract

This TIP proposes to add a new standard option, -clientdata, for all
Tk widgets.

~ Rationale

Many modern and not so modern widget toolkits provide a way to attach
programmer defined data to a widget.  Tk lacks such a feature.  The
only way to accomplish a similar feat today is by storing data in a
global or namespace variable keyed by widget name.  This doesn't lend
itself very well to general purpose library routines.

One example of how this could be used is in prototyping additional
widget functionality.  For example, [39] requests a new option for
each widget that enables a widget to declare that it is part of a
larger compound widget.  One potential use of this new flag is in the
Tk library code that handles keyboard traversal.

With the option proposed in this TIP, it would have been quite simple
to prototype the necessary changes at the script level, making it
easier to validate the utility of the requested change in TIP #39, and
to provide a reference implementation of the affected library
procedures.

Another example use of this flag would be in the development of a
graphical interface builder such as SpecTcl or Visual Tcl.  With
applications that let you create widgets interactively, it is often
convenient to attach metadata directly to the widget.  For example,
<
|
<
|
|
|
|
|
|
|
>

|




|








|






|








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

# TIP 42: Add New Standard Tk Option: -clientdata

	Author:         Bryan Oakley <[email protected]>
	State:		Withdrawn
	Type:           Project
	Vote:		Pending
	Created:	05-Jul-2001
	Post-History:	
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to add a new standard option, -clientdata, for all
Tk widgets.

# Rationale

Many modern and not so modern widget toolkits provide a way to attach
programmer defined data to a widget.  Tk lacks such a feature.  The
only way to accomplish a similar feat today is by storing data in a
global or namespace variable keyed by widget name.  This doesn't lend
itself very well to general purpose library routines.

One example of how this could be used is in prototyping additional
widget functionality.  For example, [[39]](39.md) requests a new option for
each widget that enables a widget to declare that it is part of a
larger compound widget.  One potential use of this new flag is in the
Tk library code that handles keyboard traversal.

With the option proposed in this TIP, it would have been quite simple
to prototype the necessary changes at the script level, making it
easier to validate the utility of the requested change in TIP \#39, and
to provide a reference implementation of the affected library
procedures.

Another example use of this flag would be in the development of a
graphical interface builder such as SpecTcl or Visual Tcl.  With
applications that let you create widgets interactively, it is often
convenient to attach metadata directly to the widget.  For example,
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


... and the list goes on.  The bottom line is, it adds flexibility
that can be leveraged in many ways.  Impact on the core is minimal
since it merely requires the storage and retrieval of information.
And the mechanism is already in place; we merely need to define a slot
in the widget data structure to store the information.

~ Specification

Suggested wording for the ''options'' man page (which, I suspect, can
be greatly improved upon):

| Command-Line Name: -clientdata
| Database Name: clientData
| Database Class: ClientData

 > ''Specifies programmer defined data to be associated with the
   widget.  The Tk libraries do not use this information or require
   the information to be in any particular format.  It is purely for
   use by the application.''

~ Lame Joke

Did you hear the one about the three legged dog that went into a
saloon, jumped up on the nearest stool, banged his good foot on the
bar, and with a steely-eyed glare said "I'm lookin' for the man that
shot my Paw!"?

~ Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > Perhaps some of the ideas behind these TIPs should be incorporated
   into some new TIP on making megawidget support better, but none of
   these TIPs really stand on their own.  (38 isn't a good idea, since
   alteration of the bindtags for all widgets of a class at once is a
   bad idea, and it is better when rolling your own megawidget classes
   to put the setting up of the bindtags in there.  39 and 42 just
   clash with each other as soon as you have two different codebases
   trying to use a single widget.)

~ Copyright

This document has been placed in the public domain accompanied with
only a small and very personal amount of fanfare.








|

|
|

|
|
|

|


|

|






|







|




|

|



>
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

... and the list goes on.  The bottom line is, it adds flexibility
that can be leveraged in many ways.  Impact on the core is minimal
since it merely requires the storage and retrieval of information.
And the mechanism is already in place; we merely need to define a slot
in the widget data structure to store the information.

# Specification

Suggested wording for the _options_ man page \(which, I suspect, can
be greatly improved upon\):

	 Command-Line Name: -clientdata
	 Database Name: clientData
	 Database Class: ClientData

 > _Specifies programmer defined data to be associated with the
   widget.  The Tk libraries do not use this information or require
   the information to be in any particular format.  It is purely for
   use by the application._

# Lame Joke

Did you hear the one about the three legged dog that went into a
saloon, jumped up on the nearest stool, banged his good foot on the
bar, and with a steely-eyed glare said "I'm lookin' for the man that
shot my Paw!"?

# Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > Perhaps some of the ideas behind these TIPs should be incorporated
   into some new TIP on making megawidget support better, but none of
   these TIPs really stand on their own.  \(38 isn't a good idea, since
   alteration of the bindtags for all widgets of a class at once is a
   bad idea, and it is better when rolling your own megawidget classes
   to put the setting up of the bindtags in there.  39 and 42 just
   clash with each other as soon as you have two different codebases
   trying to use a single widget.\)

# Copyright

This document has been placed in the public domain accompanied with
only a small and very personal amount of fanfare.

Name change from tip/420.tip to tip/420.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304

TIP:            420
Title:          'vexpr', a Vector Expression Command
Version:        $Revision: 1.6 $
Author:         Sean Woods <[email protected]>
Author:         Andreas Kupries <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        15-Nov-2012
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes to add a new command to Tcl for manipulating vectors and
related mathematical objects. The command, '''vexpr''', will provide
C-optimized implementations of generally useful scalar, 2D, 3D and affine transforms. '''vexpr''' is a complement to '''expr''', and expects to take in vector arguments and return vector results.

~ Rationale

With the interest expressed in the community by [363], I am concerned about
the introduction of non-scalar results from '''expr''' (and parts of the
language the use '''expr'''). As the goal of that TIP is to introduce vector
math operations, a less ambitious, but arguable equally effective technique
could be to introduce a dedicated command. In particular, one designed from
the ground up to handle the intricacies of vector operations.

'''vexpr''' is a vector expression parser. It operates using reverse-polish
notation (like an HP calculator.) Each argument is pushed onto the stack, and
when a command is detected, they are popped off the stack. The result of the
command is pushed onto the stack in their place.

Why? Well mostly for ease of implementation. Partly because there is no PEMDAS
equivalent order of operation for matrices and vectors.  Once I go through an
example or two, it should be a little clearer.

~ Examples

To add {1 1 1} and {2 2 2} I run the following command:

|vexpr {2 2 2} {1 1 1} +
|> 3.0 3.0 3.0

Remember though, we are working with a stack. Items are popped on the stack in
a first-in first-out fashion. While for addition it doesn't matter what order
we do things, subtraction does care.

|vexpr {1 1 1} {2 2 2} -
|> 1.0 1.0 1.0
|vexpr {2 2 2} {1 1 1} -
|> -1.0 -1.0 -1.0

While with 2 arguments and an opcode this seems silly, imagine a complex
operation with several steps. Here we are going to model a robot arm with 3
joints. Each "arm" is one unit long, and when one joint bends, the rest follow
suit.

''unbent''

|(A) - (B) - (C)

''bent''

|      (C)
|        |

|      (B)
|     /

|(A)

Code:

|# Positions of the joints
|set A_pos {0.0 0.0 0.0}
|set B_pos {1.0 0.0 0.0}
|set C_pos {2.0 0.0 0.0}
|
|# Rotations of the joints 
|set A_rot {0 0 45}
|set B_rot {0 0 45}
|
|set b_transform [vexpr \
|    $A_pos $B_pos - \
|    affine_translate \
|    $A_rot radians \
|    affine_rotate \
|    affine_multiply]
|> { 0.707  0.707 0.0  -0.707} 
|  {-0.707  0.707 0.0   0.707}
|  { 0.0    0.0   1.0   0.0}
|  { 0.0    0.0   0.0   1.0}
|
|set b_real [vexpr $B_pos $b_transform vector_transform]
|
|> 0.707106 0.707106 0.0
|
|set c_transform [vexpr \
|    $C_pos $B_real - \
|    affine_translate \
|    load affine_multiply \
|    $B_rot radians \
|    affine_rotate \
|    affine_multiply]
|> { 0.0 1.0 0.0 0.707}
|  {-1.0 0.0 0.0 2.293}
|  {0.0  0.0 1.0 0.0}
|  {0.0  0.0 0.0 1.0}
|
|set c_real [vexpr $C_pos $c_transform vector_transform]
|> 0.0 2.0 0.0

If you aren't familiar with 3D math and affine transformations, that may look
overly complicated, but as you can see each '''vexpr''' call is packed with
commands. You can plainly see that after 2 45 degree bends, our "C" point
comes to rest at 0.0,2,0 after completing a 90 degree bend.

~ Operations

Note that all arguments that are not one of these operation words are instead treated as values to push onto the evaluation stack.

~~affine_multiply

 > AFFINE AFFINE -> AFFINE

Multiplies 2 4x4 matrices. Used to combine 2 affine transformations. Note:
Some affine transformations need to be performed in a particular order to make
sense.

~~affine_rotate

 > VECTOR -> AFFINE

Converts a "vector" of 3 angles (Xrotation Yrotation Zrotation) into an affine
transformation. NOTE: the angles should be in radians.

~~affine_scale

 > VECTOR -> AFFINE

Converts a scale vector (Xscale Yscale Zscale) into an affine transformation.
Note: 1.0 1.0 1.0 = No scaling. 2.0 2.0 2.0 = Double the size. 0.5 0.5 0.5 =
Half the size.

~~affine_translate

 > VECTOR -> AFFINE

Converts a displacement vector (X Y Z) into an affine transformation	

~~cart_to_cyl

 > VECTOR -> VECTOR

Converts a cartesian vector to cylindrical coordinates	

~~cart_to_sphere

 > VECTOR -> VECTOR

Converts a cartesian vector to spherical coordinates

~~cross

 > VECTOR VECTOR -> VECTOR

Performs the cross product of two vectors

~~copy

 > ANY -> ANY ANY

Copies the top of the stack, pushing it onto the stack.

~~cyl_to_cart

 > VECTOR -> VECTOR

Converts a vector in cylindrical coordinates to cartesian coordinates	

~~cyl_to_degrees

 > VECTOR -> VECTOR

Converts a cylindrical vector in radians to degrees.

~~cyl_to_radians

 > VECTOR -> VECTOR

Converts a cylindrical vector in degrees to radians.

~~degrees

 > VECTOR -> VECTOR

Converts a vector or scalar in radians to degrees.

~~dot

 > VECTOR VECTOR -> SCALAR

Produces the dot product of two vectors.

~~dT

 > (None) -> SCALAR

Pushes the value of dT into the stack.

~~identity

 > (None) -> AFFINE

Pushes the identity matrix onto the stack.

~~load

 > (None) -> ANY

Pushes the last value stored by STORE onto the stack.	

~~pi

 > (None) -> SCALER

Pushes the value of PI onto the stack.

~~radians

 > VECTOR -> VECTOR

Converts a vector or scalar in degrees to radians.

~~setDT

 > SCALAR -> (None)

Pops the current stack value and stores it in the dT variable.

~~sphere_to_cart

 > VECTOR -> VECTOR

Converts a vector in spherical coordinates to cartesian coordinates.

~~sphere_to_degrees

 > VECTOR -> VECTOR

Converts a spherical vector in radians to a spherical vector in degrees.

~~sphere_to_radians

 > VECTOR -> VECTOR

Converts a spherical vector in degrees to a spherical vector in radians.

~~store

 > ANY -> ANY

Stores the top of the stack internally for later use. The value stored remains at the top of the stack.

~~vector_add

 > VECTOR VECTOR -> VECTOR

Adds 2 vectors, which must be of the same length.

~~vector_length

 > VECTOR -> SCALAR

Produces the length of a vector.

~~vector_scale

 > SCALAR VECTOR -> VECTOR

Scales a vector by a scalar

~~vector_subtract

 > VECTOR VECTOR -> VECTOR

Subtracts one vector from another.

~~vector_transform

 > AFFINE VECTOR -> VECTOR

Transforms a vector using an affine matrix.

~Implementation

A test implementation for '''vexpr''' is available as an TEA extension, and can be downloaded [http://www.etoyoc.com/tclmatrix3d].  At this point in time, the goal is adding '''vexpr''' as a standalone command.

~~ Limits

'''vexpr''' converts all arguments to an array of 16 double precision
elements; only the item left on the top of the stack is converted back into a Tcl list. The "stack" itself has a hard-coded limit of 32 elements. (It is implemented as an array.) Exceeding the stack size will cause the command to throw a Tcl error.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|
|

|

|
|
|




|
|







|

|

|
|





|
|
|
|






|

|

|

|
<
>
|
<
>
|



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


|



|



|







|



|


|



|



|



|

|





|





|





|





|





|





|





|





|





|

|



|

|



|

|



|

|



|





|

|



|





|





|





|





|





|





|





|





|





|

|

|

|
|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304

# TIP 420: 'vexpr', a Vector Expression Command

	Author:         Sean Woods <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        15-Nov-2012
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to add a new command to Tcl for manipulating vectors and
related mathematical objects. The command, **vexpr**, will provide
C-optimized implementations of generally useful scalar, 2D, 3D and affine transforms. **vexpr** is a complement to **expr**, and expects to take in vector arguments and return vector results.

# Rationale

With the interest expressed in the community by [[363]](363.md), I am concerned about
the introduction of non-scalar results from **expr** \(and parts of the
language the use **expr**\). As the goal of that TIP is to introduce vector
math operations, a less ambitious, but arguable equally effective technique
could be to introduce a dedicated command. In particular, one designed from
the ground up to handle the intricacies of vector operations.

**vexpr** is a vector expression parser. It operates using reverse-polish
notation \(like an HP calculator.\) Each argument is pushed onto the stack, and
when a command is detected, they are popped off the stack. The result of the
command is pushed onto the stack in their place.

Why? Well mostly for ease of implementation. Partly because there is no PEMDAS
equivalent order of operation for matrices and vectors.  Once I go through an
example or two, it should be a little clearer.

# Examples

To add \{1 1 1\} and \{2 2 2\} I run the following command:

	vexpr {2 2 2} {1 1 1} +
	> 3.0 3.0 3.0

Remember though, we are working with a stack. Items are popped on the stack in
a first-in first-out fashion. While for addition it doesn't matter what order
we do things, subtraction does care.

	vexpr {1 1 1} {2 2 2} -
	> 1.0 1.0 1.0
	vexpr {2 2 2} {1 1 1} -
	> -1.0 -1.0 -1.0

While with 2 arguments and an opcode this seems silly, imagine a complex
operation with several steps. Here we are going to model a robot arm with 3
joints. Each "arm" is one unit long, and when one joint bends, the rest follow
suit.

_unbent_

	(A) - (B) - (C)

_bent_

	      (C)

	        |
	      (B)

	     /
	(A)

Code:

	# Positions of the joints
	set A_pos {0.0 0.0 0.0}
	set B_pos {1.0 0.0 0.0}
	set C_pos {2.0 0.0 0.0}
	
	# Rotations of the joints 
	set A_rot {0 0 45}
	set B_rot {0 0 45}
	
	set b_transform [vexpr \
	    $A_pos $B_pos - \
	    affine_translate \
	    $A_rot radians \
	    affine_rotate \
	    affine_multiply]
	> { 0.707  0.707 0.0  -0.707} 
	  {-0.707  0.707 0.0   0.707}
	  { 0.0    0.0   1.0   0.0}
	  { 0.0    0.0   0.0   1.0}
	
	set b_real [vexpr $B_pos $b_transform vector_transform]
	
	> 0.707106 0.707106 0.0
	
	set c_transform [vexpr \
	    $C_pos $B_real - \
	    affine_translate \
	    load affine_multiply \
	    $B_rot radians \
	    affine_rotate \
	    affine_multiply]
	> { 0.0 1.0 0.0 0.707}
	  {-1.0 0.0 0.0 2.293}
	  {0.0  0.0 1.0 0.0}
	  {0.0  0.0 0.0 1.0}
	
	set c_real [vexpr $C_pos $c_transform vector_transform]
	> 0.0 2.0 0.0

If you aren't familiar with 3D math and affine transformations, that may look
overly complicated, but as you can see each **vexpr** call is packed with
commands. You can plainly see that after 2 45 degree bends, our "C" point
comes to rest at 0.0,2,0 after completing a 90 degree bend.

# Operations

Note that all arguments that are not one of these operation words are instead treated as values to push onto the evaluation stack.

## affine\_multiply

 > AFFINE AFFINE -> AFFINE

Multiplies 2 4x4 matrices. Used to combine 2 affine transformations. Note:
Some affine transformations need to be performed in a particular order to make
sense.

## affine\_rotate

 > VECTOR -> AFFINE

Converts a "vector" of 3 angles \(Xrotation Yrotation Zrotation\) into an affine
transformation. NOTE: the angles should be in radians.

## affine\_scale

 > VECTOR -> AFFINE

Converts a scale vector \(Xscale Yscale Zscale\) into an affine transformation.
Note: 1.0 1.0 1.0 = No scaling. 2.0 2.0 2.0 = Double the size. 0.5 0.5 0.5 =
Half the size.

## affine\_translate

 > VECTOR -> AFFINE

Converts a displacement vector \(X Y Z\) into an affine transformation	

## cart\_to\_cyl

 > VECTOR -> VECTOR

Converts a cartesian vector to cylindrical coordinates	

## cart\_to\_sphere

 > VECTOR -> VECTOR

Converts a cartesian vector to spherical coordinates

## cross

 > VECTOR VECTOR -> VECTOR

Performs the cross product of two vectors

## copy

 > ANY -> ANY ANY

Copies the top of the stack, pushing it onto the stack.

## cyl\_to\_cart

 > VECTOR -> VECTOR

Converts a vector in cylindrical coordinates to cartesian coordinates	

## cyl\_to\_degrees

 > VECTOR -> VECTOR

Converts a cylindrical vector in radians to degrees.

## cyl\_to\_radians

 > VECTOR -> VECTOR

Converts a cylindrical vector in degrees to radians.

## degrees

 > VECTOR -> VECTOR

Converts a vector or scalar in radians to degrees.

## dot

 > VECTOR VECTOR -> SCALAR

Produces the dot product of two vectors.

## dT

 > \(None\) -> SCALAR

Pushes the value of dT into the stack.

## identity

 > \(None\) -> AFFINE

Pushes the identity matrix onto the stack.

## load

 > \(None\) -> ANY

Pushes the last value stored by STORE onto the stack.	

## pi

 > \(None\) -> SCALER

Pushes the value of PI onto the stack.

## radians

 > VECTOR -> VECTOR

Converts a vector or scalar in degrees to radians.

## setDT

 > SCALAR -> \(None\)

Pops the current stack value and stores it in the dT variable.

## sphere\_to\_cart

 > VECTOR -> VECTOR

Converts a vector in spherical coordinates to cartesian coordinates.

## sphere\_to\_degrees

 > VECTOR -> VECTOR

Converts a spherical vector in radians to a spherical vector in degrees.

## sphere\_to\_radians

 > VECTOR -> VECTOR

Converts a spherical vector in degrees to a spherical vector in radians.

## store

 > ANY -> ANY

Stores the top of the stack internally for later use. The value stored remains at the top of the stack.

## vector\_add

 > VECTOR VECTOR -> VECTOR

Adds 2 vectors, which must be of the same length.

## vector\_length

 > VECTOR -> SCALAR

Produces the length of a vector.

## vector\_scale

 > SCALAR VECTOR -> VECTOR

Scales a vector by a scalar

## vector\_subtract

 > VECTOR VECTOR -> VECTOR

Subtracts one vector from another.

## vector\_transform

 > AFFINE VECTOR -> VECTOR

Transforms a vector using an affine matrix.

# Implementation

A test implementation for **vexpr** is available as an TEA extension, and can be downloaded <http://www.etoyoc.com/tclmatrix3d> .  At this point in time, the goal is adding **vexpr** as a standalone command.

## Limits

**vexpr** converts all arguments to an array of 16 double precision
elements; only the item left on the top of the stack is converted back into a Tcl list. The "stack" itself has a hard-coded limit of 32 elements. \(It is implemented as an array.\) Exceeding the stack size will cause the command to throw a Tcl error.

# Copyright

This document has been placed in the public domain.

Name change from tip/421.tip to tip/421.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

TIP:		421
Title:		A Command for Iterating Over Arrays
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Post-History:	
Version:	$Revision: 1.1 $
Author:		Karl Lehenbauer <[email protected]>
Author:		Donal K. Fellows <[email protected]>
Created:	28-Nov-2012


~ Abstract

This TIP proposes an efficient mechanism for iterating over the contents of a
large array.

~ Rationale

Tcl currently provides three main mechanisms for iterating over the contents
of an array, but none are quite perfect when dealing with a large array.

 * '''array get''' is simple to use (especially with a two-variable
   '''foreach''') but requires the contents of the array to be effectively
   duplicated; even with the use of the Tcl_Obj system for value reference
   management, this is an expensive operation.

 * '''array names''' (with a simple '''foreach''') is also relatively simple
   to use, but requires producing a list whose size is the same as the number
   of elements of the array. (This is half the size that would be required
   with '''array get''', but can still be large.)

 * '''array startsearch''' et al. provide a memory-efficient general iteration
   mechanism, but in a way that is rather difficult to use. It is also subject
   to significant hazards if the array is modified during iteration (a
   particular problem for the global '''env''' array, as that is regenerated
   on almost any read).

The authors propose that there be a new subcommand of '''array''' which allows
for efficient iteration over an array's elements.

~ Proposed Change

There should be a new command, '''array foreach''', that has this syntax:

 > '''array''' '''foreach''' ''arrayName'' {''keyVar'' ''valueVar''} ''body''

This will iterate internally over the elements of the array called
''arrayName'' in array-iteration order (i.e., the same as that used by the
other '''array''' subcommands), setting the variable ''keyVar'' to the name of
the element and the variable ''valueVar'' to the content of the element before
evaluating the script ''body''. The result will be the empty string (excepting
errors, '''return''', etc.) and any contained '''break''' and '''continue'''
will have their normal interpretation as loop control operations.

~ Implementation

Not yet...

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|




|




|
|
|


|

|
|

|

|
|
|

|


|

|

|


|
|
|
|
|


|



|


>

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

# TIP 421: A Command for Iterating Over Arrays
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Post-History:	

	Author:		Karl Lehenbauer <[email protected]>
	Author:		Donal K. Fellows <[email protected]>
	Created:	28-Nov-2012
-----

# Abstract

This TIP proposes an efficient mechanism for iterating over the contents of a
large array.

# Rationale

Tcl currently provides three main mechanisms for iterating over the contents
of an array, but none are quite perfect when dealing with a large array.

 * **array get** is simple to use \(especially with a two-variable
   **foreach**\) but requires the contents of the array to be effectively
   duplicated; even with the use of the Tcl\_Obj system for value reference
   management, this is an expensive operation.

 * **array names** \(with a simple **foreach**\) is also relatively simple
   to use, but requires producing a list whose size is the same as the number
   of elements of the array. \(This is half the size that would be required
   with **array get**, but can still be large.\)

 * **array startsearch** et al. provide a memory-efficient general iteration
   mechanism, but in a way that is rather difficult to use. It is also subject
   to significant hazards if the array is modified during iteration \(a
   particular problem for the global **env** array, as that is regenerated
   on almost any read\).

The authors propose that there be a new subcommand of **array** which allows
for efficient iteration over an array's elements.

# Proposed Change

There should be a new command, **array foreach**, that has this syntax:

 > **array** **foreach** _arrayName_ \{_keyVar_ _valueVar_\} _body_

This will iterate internally over the elements of the array called
_arrayName_ in array-iteration order \(i.e., the same as that used by the
other **array** subcommands\), setting the variable _keyVar_ to the name of
the element and the variable _valueVar_ to the content of the element before
evaluating the script _body_. The result will be the empty string \(excepting
errors, **return**, etc.\) and any contained **break** and **continue**
will have their normal interpretation as loop control operations.

# Implementation

Not yet...

# Copyright

This document has been placed in the public domain.

Name change from tip/422.tip to tip/422.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

TIP:            422
Title:          Don't Use stdarg.h/va_list in Public API
Version:        $Revision: 1.1 $
Author:         Jan Nijtmans <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        02-Jan-2013
Post-History:   
Tcl-Version:    9.0
Keywords:	Tcl, API removal, varargs


~ Abstract

This TIP proposes to remove all functions which use the ''va_list'' type from
the public API, and it describes what extensions using this should do to make
their extension portable on the mingw-w64 gcc compiler on the AMD64 platform.

~ Rationale

The use of ''va_list'' in public API has the problem that different compilers
have a different implementation of the ''va_list'' structure. The implication
of this is that extensions which are compiled with mingw-w64 for the AMD64
platform, and call any of those functions will fail with a MSVC-compiled Tcl
core. The reverse fails as well. For a brief description about this problem,
see: http://www.bailopan.net/blog/?p=30.  See also an earlier discusion in the
Tcl Core mailing list: http://code.activestate.com/lists/tcl-core/10807/

~ Specification

This TIP proposes to remove the following 4 functions from the public API

 * Tcl_AppendResultVA

 * Tcl_AppendStringsToObjVA

 * Tcl_SetErrorCodeVA

 * Tcl_PanicVA

In addition, the inclusion of <stdarg.h> should move from tcl.h to tclInt.h,
as no public Tcl header uses it any more.
 
~ Compatibility

Extensions using any of those functions will not compile and run in Tcl 9.0
any more. They should be rewritten to use the same functions without the VA
parameter. This can be done as follows.

Before:

|int mypanic(const char *fmt, ...) {
|    va_list ap;
|    va_start(ap, fmt);
|    Tcl_PanicVA(fmt, ap);
|    va_end(ap);
|}


After:

|int mypanic(const char *fmt, ...) {
|    va_list ap;
|    char *arg1, *arg2, *arg3, *arg4;
|    va_start(ap, fmt);
|    arg1 = va_arg(argList, char *);
|    arg2 = va_arg(argList, char *);
|    arg3 = va_arg(argList, char *);
|    arg4 = va_arg(argList, char *);
|    va_end(ap);
|    Tcl_Panic(fmt, arg1, arg2, arg3, arg4);
|}


The number of args used (4, in this example) should be chosen to be the
maximum number of additional parameters that is used in any "mypanic" call.
Since this function is only ever called from the extensions itself, this can
be determined easily.

In addition, the extension must do its own inclusion of <stdarg.h>, as tcl.h
doesn't do that any more.

Extensions rewritten this way, will continue to compile and function with Tcl
8.x as well. I am not aware of any extension which actually calls any of those
VA functions.

~ Reference Implementation

A reference implementation is available in the '''novem-remove-va''' branch.
[https://core.tcl.tk/tcl/timeline?r=novem-remove-va]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|

|
|



|
|

|



|

|

|

|




|







|
|
|
|
|
<
|
>


|
|
|
|
|
|
|
|
|
|
<
|
>
|











|

|
|

|


>

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

# TIP 422: Don't Use stdarg.h/va_list in Public API

	Author:         Jan Nijtmans <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        02-Jan-2013
	Post-History:   
	Tcl-Version:    9.0
	Keywords:	Tcl, API removal, varargs
-----

# Abstract

This TIP proposes to remove all functions which use the _va\_list_ type from
the public API, and it describes what extensions using this should do to make
their extension portable on the mingw-w64 gcc compiler on the AMD64 platform.

# Rationale

The use of _va\_list_ in public API has the problem that different compilers
have a different implementation of the _va\_list_ structure. The implication
of this is that extensions which are compiled with mingw-w64 for the AMD64
platform, and call any of those functions will fail with a MSVC-compiled Tcl
core. The reverse fails as well. For a brief description about this problem,
see: <http://www.bailopan.net/blog/?p=30.>  See also an earlier discusion in the
Tcl Core mailing list: <http://code.activestate.com/lists/tcl-core/10807/>

# Specification

This TIP proposes to remove the following 4 functions from the public API

 * Tcl\_AppendResultVA

 * Tcl\_AppendStringsToObjVA

 * Tcl\_SetErrorCodeVA

 * Tcl\_PanicVA

In addition, the inclusion of <stdarg.h> should move from tcl.h to tclInt.h,
as no public Tcl header uses it any more.
 
# Compatibility

Extensions using any of those functions will not compile and run in Tcl 9.0
any more. They should be rewritten to use the same functions without the VA
parameter. This can be done as follows.

Before:

	int mypanic(const char *fmt, ...) {
	    va_list ap;
	    va_start(ap, fmt);
	    Tcl_PanicVA(fmt, ap);
	    va_end(ap);

	}

After:

	int mypanic(const char *fmt, ...) {
	    va_list ap;
	    char *arg1, *arg2, *arg3, *arg4;
	    va_start(ap, fmt);
	    arg1 = va_arg(argList, char *);
	    arg2 = va_arg(argList, char *);
	    arg3 = va_arg(argList, char *);
	    arg4 = va_arg(argList, char *);
	    va_end(ap);
	    Tcl_Panic(fmt, arg1, arg2, arg3, arg4);

	}

The number of args used \(4, in this example\) should be chosen to be the
maximum number of additional parameters that is used in any "mypanic" call.
Since this function is only ever called from the extensions itself, this can
be determined easily.

In addition, the extension must do its own inclusion of <stdarg.h>, as tcl.h
doesn't do that any more.

Extensions rewritten this way, will continue to compile and function with Tcl
8.x as well. I am not aware of any extension which actually calls any of those
VA functions.

# Reference Implementation

A reference implementation is available in the **novem-remove-va** branch.
<https://core.tcl.tk/tcl/timeline?r=novem-remove-va> 

# Copyright

This document has been placed in the public domain.

Name change from tip/423.tip to tip/423.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

TIP:		423
Title:		Formatting Timestamps with Milliseconds
Version:	$Revision: 1.1 $
Author:		Thomas Perschak <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Created:	07-Jun-2013
Post-History:
Keywords:	Tcl, time, millisecond resolution


~ Abstract

This TIP describes a change to '''clock format''' to allow it to handle
timestamps with sub-second accuracy.

~ Rationale

Currently, the '''clock format''' accepts only integer numbers for clock
formatting. Since the '''clock milliseconds''' command was introduced in Tcl
8.5, this limitation seems a bit restrictive.

In particular, the timestamp column in a number of databases (e.g.,
http://www.postgresql.org/docs/9.1/static/datatype-datetime.html) handles
high-resolution timestamps by allowing full ISO 8601 times, which look like
"04:05:06.789"; this would simplify database write operations.

~ Proposal

The '''clock format''' command should accept floating point values for
timestamps.

Another format letter should be added to '''clock format''' which puts the
milliseconds into the output string; the millisecond value should not be
written unless explicitly requested.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|
|


|
|



|

|


|



|


>

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

# TIP 423: Formatting Timestamps with Milliseconds

	Author:		Thomas Perschak <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Created:	07-Jun-2013
	Post-History:
	Keywords:	Tcl, time, millisecond resolution
-----

# Abstract

This TIP describes a change to **clock format** to allow it to handle
timestamps with sub-second accuracy.

# Rationale

Currently, the **clock format** accepts only integer numbers for clock
formatting. Since the **clock milliseconds** command was introduced in Tcl
8.5, this limitation seems a bit restrictive.

In particular, the timestamp column in a number of databases \(e.g.,
<http://www.postgresql.org/docs/9.1/static/datatype-datetime.html\)> handles
high-resolution timestamps by allowing full ISO 8601 times, which look like
"04:05:06.789"; this would simplify database write operations.

# Proposal

The **clock format** command should accept floating point values for
timestamps.

Another format letter should be added to **clock format** which puts the
milliseconds into the output string; the millisecond value should not be
written unless explicitly requested.

# Copyright

This document has been placed in the public domain.

Name change from tip/424.tip to tip/424.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

TIP:            424
Title:          Improving [exec]
Version:        $Revision: 1.8 $
Author:         Alexandre Ferrieux <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        07-Jul-2013
Post-History:   
Keywords:       Tcl,subprocess,execution
Tcl-Version:    8.7


~ Abstract

This extension overcomes day-1 limitations of [['''exec''']]'s syntax,
allowing for unconstrained arguments to commands, and opening the path to more
exotic redirections.

~ Summary Change

Replace:

|   exec foo bar baz > file

With:

|   exec | {foo bar baz} > file

~ Rationale

For decades people have rightfully complained about the stubborn limitation of
'''exec''' that prevents it from using commands or args resembling a
redirection. It's not just Quoting Hell; it is simply impossible to spawn the
equivalent of Bourne Shell's "echo \>" from pure Tcl (i.e., without resorting
to another shell).

The reason (excuse?) for this is an unfortunate design choice: stick as
closely as possible to the Bourne Shell's syntax, which indeed seamlessly
intertwines commands, arguments, and redirects. This is unfortunate, because
it overlooks a key difference between the two shells:

 * In Bourne Shell, since everything is about spawning commands, redirects are
   expected everywhere; hence their quoting is ubiquitous, and part of the
   language.

 * In Tcl, spawning processes is only a tiny part of the story. Consequently,
   redirect chars (<>|) are not special, and deserve no core-language quoting
   rules.

In this situation, it would have been possible to add an '''exec'''-specific
layer of quoting, just for these characters.  But as usual, the quoting char
itself (typically "'''\'''") would have itself needed quoting ("'''\\'''"),
which would have overburdened the backslash density of all but the simplest
pipelines...

More importantly, the realization that this was Really Wrong came fairly late
in Tcl's life; or at least late enough to consider any incompatible fix out of
the question.

So '''exec''' can be ''extended'', not ''fixed''.

A few such extensions have been suggested over the years, but none reached
critical mass. A possible interpretation of this is that they were considered
too "disruptive" - while necessary only for a corner case.

The current proposal addresses all the above concerns.  Here are its design
goals by decreasing importance:

 1. Current '''exec''''s unescapable warts should disappear

  > (Yeah, take care of that corner case.)

 2. Current '''exec''''s mapping to '''open |''' should be carried over

  > (This part of '''exec''''s design was Good)

 3. Simple pipelines should give easy-to-read lines (like current '''exec''')

  > (No disruption, Ma'am)

 4. Shell-ish advanced redirections like "'''3>&5'''" should be supported

  > (Not just the corner case: you get a free lunch too)

~ Definition

 * Extend '''exec''' "from its error space", by reserving a single pipe
   character passed as its first argument:

|       exec | ...    ;# activates the new syntax
|       open "|| ..." ;# same in [open]

 * Once the new syntax is unambiguously introduced, parse the rest as follows:

|       exec | $cmd1 {*}$redirs1 | ... | $cmdN {*}$redirsN ?&?
|       open "|[list | $cmd1 {*}$redirs1 | ... ]"

  > where:

  > * '''$cmd'''''K'' and '''$redirs'''''K'' are lists

  > * '''$cmd'''''K'' is a simple command-and-args, no extras

  > * '''$redirs'''''K'' is a list of current exec redirection operators

Examples:

|      exec | {echo >} ;# this returns ">"
|      exec | {cmd "<funny>xml</funny>"} 2>@ $ch < /dev/null | {cmd2 arg} >&2

Goals reached:

 1. Unescapable warts are gone because the '''$cmd''' vs '''$redir''' status
    is positional, not content-based: each command-and args is a separate
    sublist, with no in-band encoding of redirections.

 2. The above mapping is consistent with the existing '''open |[list foo
    bar]''' logic.  It respects the invariant saying, for '''open |''',
    that '''[string range $openarg 1 end]''' is always the list that would be
    passed, expanded, to '''exec'''. And it is handy to type
    '''open "|| {foo >} > file"'''

 3. Simple pipelines are simple.

  >  '''exec | $cmd1 | $cmd2 | $cmd3 > file'''

 4. Advanced redirections are imaginable since the redirection subsyntax
    now lives on its own. For example, with a putative "NUMBER>@" family
    of operators, one could define a nonlinear pipe graph:

|      lassign [chan pipe] pr pw
|      exec | {demuxer ...} 3>@ $pw | {filter ...} | {muxer ...} 3<@ $pr

    The definition of these advanced operators will be hosted by another TIP.

~ TL;DR

This very conservative syntax, in addition to preserving the overall style and
density of current '''exec''', overcomes all the limitations and reaches
Bourne Shell power.

Moreover, it leverages the existing internals, so a nearly free side-effect
is that it works with '''pid''' and '''close''' just like current '''exec'''
does.

~ Rejected Alternatives

 * Replace the leading "'''|'''" in '''exec |''' by '''--extended'''

 * Use a different toplevel command name.

  > '''exec2'''...

~ Reference Implementation

Branch "tip-improve-exec" on core.tcl.tk holds the implementation.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|



|



|

|


|

|
|

|









|


|

|







|








|

|

|

|

|

|

|

|

|

|


|
|



|
|

|

|

|

|



|
|



|



|
|
|
|
|



|





|
|



|


|



|


|

|



|

|



|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

# TIP 424: Improving [exec]

	Author:         Alexandre Ferrieux <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        07-Jul-2013
	Post-History:   
	Keywords:       Tcl,subprocess,execution
	Tcl-Version:    8.7
-----

# Abstract

This extension overcomes day-1 limitations of [**exec**]'s syntax,
allowing for unconstrained arguments to commands, and opening the path to more
exotic redirections.

# Summary Change

Replace:

	   exec foo bar baz > file

With:

	   exec | {foo bar baz} > file

# Rationale

For decades people have rightfully complained about the stubborn limitation of
**exec** that prevents it from using commands or args resembling a
redirection. It's not just Quoting Hell; it is simply impossible to spawn the
equivalent of Bourne Shell's "echo \\>" from pure Tcl \(i.e., without resorting
to another shell\).

The reason \(excuse?\) for this is an unfortunate design choice: stick as
closely as possible to the Bourne Shell's syntax, which indeed seamlessly
intertwines commands, arguments, and redirects. This is unfortunate, because
it overlooks a key difference between the two shells:

 * In Bourne Shell, since everything is about spawning commands, redirects are
   expected everywhere; hence their quoting is ubiquitous, and part of the
   language.

 * In Tcl, spawning processes is only a tiny part of the story. Consequently,
   redirect chars \(<>\|\) are not special, and deserve no core-language quoting
   rules.

In this situation, it would have been possible to add an **exec**-specific
layer of quoting, just for these characters.  But as usual, the quoting char
itself \(typically "**\\**"\) would have itself needed quoting \("**\\\\**"\),
which would have overburdened the backslash density of all but the simplest
pipelines...

More importantly, the realization that this was Really Wrong came fairly late
in Tcl's life; or at least late enough to consider any incompatible fix out of
the question.

So **exec** can be _extended_, not _fixed_.

A few such extensions have been suggested over the years, but none reached
critical mass. A possible interpretation of this is that they were considered
too "disruptive" - while necessary only for a corner case.

The current proposal addresses all the above concerns.  Here are its design
goals by decreasing importance:

 1. Current **exec**'s unescapable warts should disappear

	  > \(Yeah, take care of that corner case.\)

 2. Current **exec**'s mapping to **open \|** should be carried over

	  > \(This part of **exec**'s design was Good\)

 3. Simple pipelines should give easy-to-read lines \(like current **exec**\)

	  > \(No disruption, Ma'am\)

 4. Shell-ish advanced redirections like "**3>&5**" should be supported

	  > \(Not just the corner case: you get a free lunch too\)

# Definition

 * Extend **exec** "from its error space", by reserving a single pipe
   character passed as its first argument:

		       exec | ...    ;# activates the new syntax
		       open "|| ..." ;# same in [open]

 * Once the new syntax is unambiguously introduced, parse the rest as follows:

		       exec | $cmd1 {*}$redirs1 | ... | $cmdN {*}$redirsN ?&?
		       open "|[list | $cmd1 {*}$redirs1 | ... ]"

	  > where:

	  > \* **$cmd**_K_ and **$redirs**_K_ are lists

	  > \* **$cmd**_K_ is a simple command-and-args, no extras

	  > \* **$redirs**_K_ is a list of current exec redirection operators

Examples:

	      exec | {echo >} ;# this returns ">"
	      exec | {cmd "<funny>xml</funny>"} 2>@ $ch < /dev/null | {cmd2 arg} >&2

Goals reached:

 1. Unescapable warts are gone because the **$cmd** vs **$redir** status
    is positional, not content-based: each command-and args is a separate
    sublist, with no in-band encoding of redirections.

 2. The above mapping is consistent with the existing **open \|[list foo
    bar]** logic.  It respects the invariant saying, for **open \|**,
    that **[string range $openarg 1 end]** is always the list that would be
    passed, expanded, to **exec**. And it is handy to type
    **open "\|\| \{foo >\} > file"**

 3. Simple pipelines are simple.

	  >  **exec \| $cmd1 \| $cmd2 \| $cmd3 > file**

 4. Advanced redirections are imaginable since the redirection subsyntax
    now lives on its own. For example, with a putative "NUMBER>@" family
    of operators, one could define a nonlinear pipe graph:

		      lassign [chan pipe] pr pw
		      exec | {demuxer ...} 3>@ $pw | {filter ...} | {muxer ...} 3<@ $pr

    The definition of these advanced operators will be hosted by another TIP.

# TL;DR

This very conservative syntax, in addition to preserving the overall style and
density of current **exec**, overcomes all the limitations and reaches
Bourne Shell power.

Moreover, it leverages the existing internals, so a nearly free side-effect
is that it works with **pid** and **close** just like current **exec**
does.

# Rejected Alternatives

 * Replace the leading "**\|**" in **exec \|** by **--extended**

 * Use a different toplevel command name.

	  > **exec2**...

# Reference Implementation

Branch "tip-improve-exec" on core.tcl.tk holds the implementation.

# Copyright

This document has been placed in the public domain.

Name change from tip/425.tip to tip/425.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

TIP:            425
Title:          Internationalization of Default Panic Callback on Windows
Version:        $Revision: 1.6 $
Author:         Jan Nijtmans <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        17-Jul-2013
Post-History:   
Keywords:       Tcl,platform integration,i18n
Tcl-Version:    8.7


~ Abstract

The default panic proc on Windows console applications writes the
message in UTF-8 to stderr. Unfortunately, the Windows console
normally does not have UTF-8 as code page but some single-byte
code page like CP1252. When using characters outside the ASCII
range, that does not give the expected output in the console.
This TIP proposes to add a new Console panic proc to the stub
library, and modify the Tcl_Main() macro to use it.

~ Rationale

Many parts of Tcl are initernationalized in Tcl 8.6: The command
line handling, and the communication with all Win32 API functions.
But the Panic proc has - so far - not been modified accordingly
for Windows console applications, even though win32 has a
suitable API to do so.

On Windows, there actually are two different panic procs,
one for GUI applications and one for console applications, but
external embedders don't have an API for deciding which one
should be used other than provide their own. This TIP can
finally do that: The call
''Tcl_SetPanicProc(Tcl_ConsolePanic)'' will initialize the
Tcl subsystem for Console applications, while
''Tcl_SetPanicProc(NULL)'' will continue to use the default.

Making things worse, stderr is implemented by the C runtime,
(msvcrt??.dll) but if a application is embedding or dynamically
loading tcl.dll then the runtime of the embedder might be
different from tcl.dll/tclsh.exe's runtime. The embedder
providing the panic proc gives the highest chance that panic
messages arrive in the same runtime as the embedder.
For tclsh.exe this makes no difference.

~ Proposed Change

A new function ''Tcl_ConsolePanic'' is added to the stub library
on Windows and Cygwin, which can be installed by embedding
application as panic proc. The full signature is:

 > EXTERN void
   '''Tcl_ConsolePanic'''(
       const char *''format''
       ...);

On other platforms than Windows or Cygwin, ''Tcl_ConsolePanic''
is a macro equivalent to NULL, on those platforms
Tcl_SetPanicProc(Tcl_ConsolePanic) has the effect of resetting
the panic proc to the platform's default.

This function is meant to be used for Win32 or Cygwin console
applications, and can deliver the message in 3 possible ways

* If a (Windows) debugger is running, the message is sent there.

* If stderr is connected to a Windows console, the message is
sent there (Windows only).

* Otherwise, the UTF-8 BOM (3 bytes) is written followed by
the unmodified message (assumed to be in UTF-8).

The function ''Tcl_ConsolePanic'' does not assume any locale,
does not allocate memory, neither does it make any assumptions
on the initialized state of Tcl. This makes Tcl_Panic work fine
even in the final stage of a Tcl_Finalize() call.
If a Win32 Unicode API is available for the desired output,
''Tcl_ConsolePanic'' will do at most an UTF-8 to Unicode
conversion using the Win32 function MultiByteToWideChar().

The maximum number of (unicode) characters that is
written is 26000, as that is the maximum that
WriteConsoleW() can handle in a single call. See: 
[https://connect.microsoft.com/VisualStudio/feedback/details/635230]
If the message is longer than that, the string is
truncated and three dots appended to it. If
the message is sent to a character device, the
UTF-8 BOM is prepended.

The function is available from the stub library, in
order to bring the responsibility for correct linking
to the embedding application, in stead of Tcl. In
case of tclsh.exe, this makes no difference.

~ Reference Implementation

A reference implementation is available in the '''win-console-panic''' branch.
[https://core.tcl.tk/tcl/info/00a17823f0]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|







|

|












|

|


|






|

|




|
|
|

|

|





|


|

|
|

|

|
|

|
|

|

|
|










|

|
|

|


>

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

# TIP 425: Internationalization of Default Panic Callback on Windows

	Author:         Jan Nijtmans <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        17-Jul-2013
	Post-History:   
	Keywords:       Tcl,platform integration,i18n
	Tcl-Version:    8.7
-----

# Abstract

The default panic proc on Windows console applications writes the
message in UTF-8 to stderr. Unfortunately, the Windows console
normally does not have UTF-8 as code page but some single-byte
code page like CP1252. When using characters outside the ASCII
range, that does not give the expected output in the console.
This TIP proposes to add a new Console panic proc to the stub
library, and modify the Tcl\_Main\(\) macro to use it.

# Rationale

Many parts of Tcl are initernationalized in Tcl 8.6: The command
line handling, and the communication with all Win32 API functions.
But the Panic proc has - so far - not been modified accordingly
for Windows console applications, even though win32 has a
suitable API to do so.

On Windows, there actually are two different panic procs,
one for GUI applications and one for console applications, but
external embedders don't have an API for deciding which one
should be used other than provide their own. This TIP can
finally do that: The call
_Tcl\_SetPanicProc\(Tcl\_ConsolePanic\)_ will initialize the
Tcl subsystem for Console applications, while
_Tcl\_SetPanicProc\(NULL\)_ will continue to use the default.

Making things worse, stderr is implemented by the C runtime,
\(msvcrt??.dll\) but if a application is embedding or dynamically
loading tcl.dll then the runtime of the embedder might be
different from tcl.dll/tclsh.exe's runtime. The embedder
providing the panic proc gives the highest chance that panic
messages arrive in the same runtime as the embedder.
For tclsh.exe this makes no difference.

# Proposed Change

A new function _Tcl\_ConsolePanic_ is added to the stub library
on Windows and Cygwin, which can be installed by embedding
application as panic proc. The full signature is:

 > EXTERN void
   **Tcl\_ConsolePanic**\(
       const char \*_format_
       ...\);

On other platforms than Windows or Cygwin, _Tcl\_ConsolePanic_
is a macro equivalent to NULL, on those platforms
Tcl\_SetPanicProc\(Tcl\_ConsolePanic\) has the effect of resetting
the panic proc to the platform's default.

This function is meant to be used for Win32 or Cygwin console
applications, and can deliver the message in 3 possible ways

* If a \(Windows\) debugger is running, the message is sent there.

* If stderr is connected to a Windows console, the message is
sent there \(Windows only\).

* Otherwise, the UTF-8 BOM \(3 bytes\) is written followed by
the unmodified message \(assumed to be in UTF-8\).

The function _Tcl\_ConsolePanic_ does not assume any locale,
does not allocate memory, neither does it make any assumptions
on the initialized state of Tcl. This makes Tcl\_Panic work fine
even in the final stage of a Tcl\_Finalize\(\) call.
If a Win32 Unicode API is available for the desired output,
_Tcl\_ConsolePanic_ will do at most an UTF-8 to Unicode
conversion using the Win32 function MultiByteToWideChar\(\).

The maximum number of \(unicode\) characters that is
written is 26000, as that is the maximum that
WriteConsoleW\(\) can handle in a single call. See: 
<https://connect.microsoft.com/VisualStudio/feedback/details/635230> 
If the message is longer than that, the string is
truncated and three dots appended to it. If
the message is sent to a character device, the
UTF-8 BOM is prepended.

The function is available from the stub library, in
order to bring the responsibility for correct linking
to the embedding application, in stead of Tcl. In
case of tclsh.exe, this makes no difference.

# Reference Implementation

A reference implementation is available in the **win-console-panic** branch.
<https://core.tcl.tk/tcl/info/00a17823f0> 

# Copyright

This document has been placed in the public domain.

Name change from tip/426.tip to tip/426.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

TIP:		426
Title:		Determining the "Type" of Commands
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Post-History:	
Version:	$Revision: 1.2 $
Author:		Donal K. Fellows <[email protected]>
Created:	31-Jul-2013
Keywords:	introspection, commands, Tcl, Tk


~ Abstract

This TIP describes a mechanism for determining what "type" of command
a particular command is. This can be used as a prelude to performing
other kinds of introspection, such as using '''info body''',
'''namespace origin''' or '''interp alias'''.

~ Rationale

Currently, in order to find out information about an arbitrary command
you have to apply a suitable introspection command and deal with any
errors arising in order to tell that you had a command of some other
type. It was made clear to me at EuroTcl 2013 that this was inelegant,
especially since we in principle had the information available to do
something neater.

The information in question is the pointer to the implementation
function, that's stored in the C record describing the command. All
that is needed is a way to surface that information to Tcl as a new
introspection command.

~ Proposed Change

This new introspection interface shall consist of one new subcommand
of '''info''' and a pair of new public C functions.

 > '''info cmdtype''' ''commandName''

The new '''info''' subcommand is to be called '''cmdtype''' (the name
is chosen so as to not conflict with abbreviations '''info commands'''
even though it does conflict with '''info cmdcount''') and it takes a
single argument, ''commandName'', which must be the name of an
existing Tcl command. The result of this subcommand shall be a string
describing what sort of command ''commandName'' is; if no other
information is available, the result shall be '''native'''.

NB: The Tcl implementation will not make any guarantees of the command
type for any particular command supplied by default in any
interpreter. User code should never assume that just because a command
is implemented one way in one particular version that it will continue
to be implemented that way in any future version.

~~ Supporting C API

The supporting public C functions shall be:

 > void '''Tcl_RegisterCommandTypeName'''(Tcl_ObjCmdProc
   *''implementationProc'', const char *''nameStr'')

 > const char * '''Tcl_GetCommandTypeName'''(Tcl_Command ''command'')

'''Tcl_RegisterCommandTypeName''' will associate a particular
implementation function, ''implementationProc'', with an (assumed
literal constant) string, ''nameStr''; if ''nameStr'' is supplied as
NULL, the mapping for ''implementationProc'' will be removed. The
''implementationProc'' argument must not be NULL. The use of a package
prefix within the name is ''recommended''.

'''Tcl_GetCommandTypeName''' shall take a command handle, ''command'',
and return the registered type name string (as previously passed to
Tcl_RegisterCommandTypeName) for the command implementation function
that the ''command'' is using. If there is no type name registered for
the command's implementation function, the literal string '''native'''
will be returned instead. The result will never be NULL.

~~ Predefined Command Types

The following command types are guaranteed to be among the set defined
by default, but others may be done as well.

 proc: Procedures defined by the '''proc''' command.

 alias: Aliases defined by the '''interp alias''' command.

 ensemble: Ensembles defined by the '''namespace ensemble''' command.

 import: Commands imported by the '''namespace import''' command.

 object: Object (or class) defined by instantiating any TclOO class.

~~ Impact on Tk

It is anticipated that Tk widget instances will report themselves
through this mechanism as well, with a prefix to their names of
'''tk::'''; that prefix ''should not'' be used by any other package.
Note however that not all widget types will be distinguishable; this
is part of the way that Tk is implemented.

The built-in widget creation functions ''may'' declare themselves to
be of type '''tk::widgetFactory'''.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|



|
|

|













|


|

|

|
|
|
|

|
|







|



|
|

|

|
|
|
|
|
|

|
|
|
|
|


|




|

|

|

|

|

|



|



|
|

|


>

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

# TIP 426: Determining the "Type" of Commands
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	31-Jul-2013
	Keywords:	introspection, commands, Tcl, Tk
-----

# Abstract

This TIP describes a mechanism for determining what "type" of command
a particular command is. This can be used as a prelude to performing
other kinds of introspection, such as using **info body**,
**namespace origin** or **interp alias**.

# Rationale

Currently, in order to find out information about an arbitrary command
you have to apply a suitable introspection command and deal with any
errors arising in order to tell that you had a command of some other
type. It was made clear to me at EuroTcl 2013 that this was inelegant,
especially since we in principle had the information available to do
something neater.

The information in question is the pointer to the implementation
function, that's stored in the C record describing the command. All
that is needed is a way to surface that information to Tcl as a new
introspection command.

# Proposed Change

This new introspection interface shall consist of one new subcommand
of **info** and a pair of new public C functions.

 > **info cmdtype** _commandName_

The new **info** subcommand is to be called **cmdtype** \(the name
is chosen so as to not conflict with abbreviations **info commands**
even though it does conflict with **info cmdcount**\) and it takes a
single argument, _commandName_, which must be the name of an
existing Tcl command. The result of this subcommand shall be a string
describing what sort of command _commandName_ is; if no other
information is available, the result shall be **native**.

NB: The Tcl implementation will not make any guarantees of the command
type for any particular command supplied by default in any
interpreter. User code should never assume that just because a command
is implemented one way in one particular version that it will continue
to be implemented that way in any future version.

## Supporting C API

The supporting public C functions shall be:

 > void **Tcl\_RegisterCommandTypeName**\(Tcl\_ObjCmdProc
   *_implementationProc_, const char \*_nameStr_\)

	 > const char \* **Tcl\_GetCommandTypeName**\(Tcl\_Command _command_\)

**Tcl\_RegisterCommandTypeName** will associate a particular
implementation function, _implementationProc_, with an \(assumed
literal constant\) string, _nameStr_; if _nameStr_ is supplied as
NULL, the mapping for _implementationProc_ will be removed. The
_implementationProc_ argument must not be NULL. The use of a package
prefix within the name is _recommended_.

**Tcl\_GetCommandTypeName** shall take a command handle, _command_,
and return the registered type name string \(as previously passed to
Tcl\_RegisterCommandTypeName\) for the command implementation function
that the _command_ is using. If there is no type name registered for
the command's implementation function, the literal string **native**
will be returned instead. The result will never be NULL.

## Predefined Command Types

The following command types are guaranteed to be among the set defined
by default, but others may be done as well.

 proc: Procedures defined by the **proc** command.

 alias: Aliases defined by the **interp alias** command.

 ensemble: Ensembles defined by the **namespace ensemble** command.

 import: Commands imported by the **namespace import** command.

 object: Object \(or class\) defined by instantiating any TclOO class.

## Impact on Tk

It is anticipated that Tk widget instances will report themselves
through this mechanism as well, with a prefix to their names of
**tk::**; that prefix _should not_ be used by any other package.
Note however that not all widget types will be distinguishable; this
is part of the way that Tk is implemented.

The built-in widget creation functions _may_ declare themselves to
be of type **tk::widgetFactory**.

# Copyright

This document has been placed in the public domain.

Name change from tip/427.tip to tip/427.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

TIP:            427
Title:          Introspection of Asynchronous Socket Connection
Version:        $Revision: 1.13 $
Author:         Reinhard Max <[email protected]>
Author:         Harald Oehlmann <[email protected]>
Author:         Reinhard Max <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        16-Mar-2014
Post-History:   
Keywords:       async socket connect,introspection,IPV6
Tcl-Version:    8.6.4


~ Abstract

This TIP describes a method to introspect the asynchronous connection
process by an extension of the '''fconfigure''' interface in addition
to '''fconfigure -error'''. This will enable better control over the
asynchronous connection process, even in cases where the event loop is
not in use.

~ Rationale

The '''socket''' core command supports two ways to establish a
client socket, ''synchronous'' and ''asynchronous''. In synchronous
mode (which is the default) the command does not return until the
connection attempt has completed (established or failed).

In asynchronous mode ('''-async option''') the command returns after DNS lookup and the connection is established in the background.
This is useful in situations where it is undesirable that a
process or thread blocks for completing a synchronous connection
attempt.
Classically, an asyncronously connecting socket would indicate that it
had connected (or failed to connect) by becoming writeable, which
'''fileevent writable''' can be used to detect.

A DNS name may have multiple IP addresses associated, e.g. for
IPv4/IPv6 dual stack hosts or for fail safety or load balancing
reasons as it is the case for google.com as of this writing.

In Tcl 8.5 the socket command only tried to connect to a single IPv4
address that was randomly picked from the list returned by DNS. In Tcl
8.6, the socket command tries to connect to all the IP addresses of a
DNS name in turn until one succeeds or all have failed.

This caused the following changes to the '''socket -async''' command from Tcl 8.5 to 8.6:

   * The socket introspection options to '''fconfigure''' (i.e.,
     '''-error''', '''-sockname''' and '''-peername''') can change
     between successive invocations while the connection is in
     progress as they reflect the state of the internal loop
     over the IP addresses.

   * The event loop must run in order to allow looping over the
     various possible IP addresses of a host.

The usage of '''socket -async''' is seen as helpful even without the event loop. An example is an application, which checks a list of
hosts for a connection.  The application may start many background
socket connects, do something else, and then collect the results.  Without the event loop (i.e., a '''fileevent writable'''), there is
no non-blocking way to discover if the asynchronous connect has
completed.

In addition, the following future points may be considered:

   * The connection process may internally get delegated to its own
     thread; this would allow the connection process to be
     asynchronous without requiring the event loop.

   * A future Windows implementation may use the Vista+ API
     ''WSAConnectByList'' (once we do not support Windows XP any
     more). Using this, no own looping over the addresses is
     necessary.  It allows the connection process to be a single OS
     call, but does not allow inspection of the different connection
     steps.

~ Proposed Change

~~ Current Introspection Change

The introspection functions should act as follows during an
asynchronous connection process:

   * '''fconfigure -error''' will return the empty string (no error)

   * '''fconfigure -sockname''' will return the empty string

   * '''fconfigure -peername''' will return the empty string

~~ Introspection Command to Inspect a Running Asynchronous Connect

An additional introspection function should inform if the asynchronous
connect is running or if it has terminated:

 > '''fconfigure''' ''channel'' '''-connecting'''

This option returns '''1''' as long as a socket is still in the process of connecting asynchronously and 0 when the asynchronous connection has completed (succeeded or failed) or the socket was opened synchronously.

~~ Non-Event Loop Operation

If the event loop runs, the state machine of a (possibly multiple-address try) async connection proceeds within an internal callback.

In addition to that (for the case the event loop does currently not run), it proceeds whenever a channel operation is attempted on the socket_

   * nonblocking I/O and [fconfigure] will advance it by one step (i.e. do whatever is doable without waiting).

   * blocking I/O will advance it to completion, in essence meaning "switch back to synchronous connect, and in case of success, do the blocking I/O I asked for".

~ Use Case of the Connecting Option

My own use case for the proposed option '''-connecting''' is as follows.
A TCL script is started within Rivet to do two tasks:

 * Verify many URLs for existance (e.g. open a socket and do a head request).

 * Do some data base work.

I don't use the event loop to get a linear program with controlled order.

So the program flow is as follows:

 * Open async sockets for all links to verify:

 > ''foreach host $hosts; set h($host) [socket -async $host 23]''

 * Do some data base work which takes time.

 * Check all open sockets and eventually advance the state machine by calling
   '''-connecting''':

 > ''foreach host $hosts; if {[fconfigure $h($host) -connecting]} {Connected $host}''

 * Do some more data base work which takes time.

 * Check '''-connecting''' and react until there are no open sockets any more.

I have cut the data base processing into two parts; I assume there
are normally two IP's to try, one IPV6 and one IPV4.

~ Alternatives

Two alternatives for the behavior of '''fconfigure -sockname''' and
'''fconfigure -peername''' are:

   * If there is only one destination IP address, return this before
     the connection is really established. This may also happen if the
     socket has processed its ''bind()'' system call in such a way
     that it knows it will not attempt another, and is currently
     processing its ''connect()'' to the remote host.

   * If an asynchronous connect is running, raise an error.

These are open to discussion.

~ Implementation

The fossil branch ''tip-427'' contains an implementation of
these extensions.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|


|
|



|

|
|
|
|

|




|
|










|

|
|







|

|









|
|
|




|

|




|

|

|

|




|

|

|

|

|

|



|

|


|









|




|

|



|




|

|
|



|

|





|

|


|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

# TIP 427: Introspection of Asynchronous Socket Connection

	Author:         Reinhard Max <[email protected]>
	Author:         Harald Oehlmann <[email protected]>
	Author:         Reinhard Max <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        16-Mar-2014
	Post-History:   
	Keywords:       async socket connect,introspection,IPV6
	Tcl-Version:    8.6.4
-----

# Abstract

This TIP describes a method to introspect the asynchronous connection
process by an extension of the **fconfigure** interface in addition
to **fconfigure -error**. This will enable better control over the
asynchronous connection process, even in cases where the event loop is
not in use.

# Rationale

The **socket** core command supports two ways to establish a
client socket, _synchronous_ and _asynchronous_. In synchronous
mode \(which is the default\) the command does not return until the
connection attempt has completed \(established or failed\).

In asynchronous mode \(**-async option**\) the command returns after DNS lookup and the connection is established in the background.
This is useful in situations where it is undesirable that a
process or thread blocks for completing a synchronous connection
attempt.
Classically, an asyncronously connecting socket would indicate that it
had connected \(or failed to connect\) by becoming writeable, which
**fileevent writable** can be used to detect.

A DNS name may have multiple IP addresses associated, e.g. for
IPv4/IPv6 dual stack hosts or for fail safety or load balancing
reasons as it is the case for google.com as of this writing.

In Tcl 8.5 the socket command only tried to connect to a single IPv4
address that was randomly picked from the list returned by DNS. In Tcl
8.6, the socket command tries to connect to all the IP addresses of a
DNS name in turn until one succeeds or all have failed.

This caused the following changes to the **socket -async** command from Tcl 8.5 to 8.6:

   * The socket introspection options to **fconfigure** \(i.e.,
     **-error**, **-sockname** and **-peername**\) can change
     between successive invocations while the connection is in
     progress as they reflect the state of the internal loop
     over the IP addresses.

   * The event loop must run in order to allow looping over the
     various possible IP addresses of a host.

The usage of **socket -async** is seen as helpful even without the event loop. An example is an application, which checks a list of
hosts for a connection.  The application may start many background
socket connects, do something else, and then collect the results.  Without the event loop \(i.e., a **fileevent writable**\), there is
no non-blocking way to discover if the asynchronous connect has
completed.

In addition, the following future points may be considered:

   * The connection process may internally get delegated to its own
     thread; this would allow the connection process to be
     asynchronous without requiring the event loop.

   * A future Windows implementation may use the Vista\+ API
     _WSAConnectByList_ \(once we do not support Windows XP any
     more\). Using this, no own looping over the addresses is
     necessary.  It allows the connection process to be a single OS
     call, but does not allow inspection of the different connection
     steps.

# Proposed Change

## Current Introspection Change

The introspection functions should act as follows during an
asynchronous connection process:

   * **fconfigure -error** will return the empty string \(no error\)

   * **fconfigure -sockname** will return the empty string

   * **fconfigure -peername** will return the empty string

## Introspection Command to Inspect a Running Asynchronous Connect

An additional introspection function should inform if the asynchronous
connect is running or if it has terminated:

 > **fconfigure** _channel_ **-connecting**

This option returns **1** as long as a socket is still in the process of connecting asynchronously and 0 when the asynchronous connection has completed \(succeeded or failed\) or the socket was opened synchronously.

## Non-Event Loop Operation

If the event loop runs, the state machine of a \(possibly multiple-address try\) async connection proceeds within an internal callback.

In addition to that \(for the case the event loop does currently not run\), it proceeds whenever a channel operation is attempted on the socket\_

   * nonblocking I/O and [fconfigure] will advance it by one step \(i.e. do whatever is doable without waiting\).

   * blocking I/O will advance it to completion, in essence meaning "switch back to synchronous connect, and in case of success, do the blocking I/O I asked for".

# Use Case of the Connecting Option

My own use case for the proposed option **-connecting** is as follows.
A TCL script is started within Rivet to do two tasks:

 * Verify many URLs for existance \(e.g. open a socket and do a head request\).

 * Do some data base work.

I don't use the event loop to get a linear program with controlled order.

So the program flow is as follows:

 * Open async sockets for all links to verify:

	 > _foreach host $hosts; set h\($host\) [socket -async $host 23]_

 * Do some data base work which takes time.

 * Check all open sockets and eventually advance the state machine by calling
   **-connecting**:

	 > _foreach host $hosts; if \{[fconfigure $h($host) -connecting]\} \{Connected $host\}_

 * Do some more data base work which takes time.

 * Check **-connecting** and react until there are no open sockets any more.

I have cut the data base processing into two parts; I assume there
are normally two IP's to try, one IPV6 and one IPV4.

# Alternatives

Two alternatives for the behavior of **fconfigure -sockname** and
**fconfigure -peername** are:

   * If there is only one destination IP address, return this before
     the connection is really established. This may also happen if the
     socket has processed its _bind\(\)_ system call in such a way
     that it knows it will not attempt another, and is currently
     processing its _connect\(\)_ to the remote host.

   * If an asynchronous connect is running, raise an error.

These are open to discussion.

# Implementation

The fossil branch _tip-427_ contains an implementation of
these extensions.

# Copyright

This document has been placed in the public domain.

Name change from tip/428.tip to tip/428.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

TIP:            428
Title:          Produce Error Dictionary from 'fconfigure -error'
Version:        $Revision: 1.26 $
Author:         Harald Oehlmann <[email protected]>
Author:         Harald Oehlmann <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        16-Mar-2014
Post-History:   
Keywords:       socket,non-blocking,error reporting,option dictionary
Tcl-Version:    8.7


~ Abstract

This TIP proposes a new method which allows to return the error message and the error code of a background socket error (as reported by '''fconfigure -error'''), similar to the option dictionaries produced by catch and try and consumed by return.

~ Rationale

The error message of a background channel error may be retrieved and
cleared by '''fconfigure''' ''channel'' '''-error''', but there is no access to the error code.

In addition, the error may not be handled in the TCL-like way using '''catch''' or '''try''' (or just let fail the program).

Specially the new '''try''' syntax (see example in the man page) is well suited to handle socket errors.
Example:

|try {set h [socket $host $port]}\
|trap {POSIX ECONNREFUSED} {} {
|    # handle not open port
|}


Drivers mostly use POSIX errors to report issues where the error code is more portable than the error message (AFAIK).

To handle an error by '''try''', the error must be thrown.

We are limited to an option to the command '''fconfigure''', as this is implemented within the driver interface.

Throwing the error would change the semantics of '''fconfigure''' and thus should not happen (consensus on the core list).
Instead, the new '''fconfigure''' operation should return the error message and the error code.

To finally throw the error, an utility function ('''chan throwerror $h''') may be defined in TCL.
This is not part of this TIP.

~ Proposed Change

The option '''fconfigure channel -error''' should be extended to take an optional argument as follows:

 > '''fconfigure''' ''channel'' '''-error''' ''?errorDictVar?''

If the optional argument ''errorDictVar'' is given, the following dict is written in the named variable of the caller environment:

   *   if there is no error, it should be set to '''-code 0'''

   *   if there is an error, it should be set to '''-code 1 -errorcode ''' ''errorCode''

This is executed in addition to the standard action of '''fconfigure''' ''channel'' '''-error'''.

~ Example

Usage example with failing async connect:

|% set h [connect -async localhost 30001]
|d00000af
|% fileevent $h writable {set x 1}
|% vwait x
|% fconfigure $h -error errorDict
|connection refused
|% set errorDict
|-code 1 -errorcode {POSIX ECONNREFUSED {connection refused}}
|% close $h

The following example demonstrates the implementation of '''chan throwerror''' eg to throw the error from the provided dict.

|proc throwerror {h} {
|    set errorMessage [fconfigure $h -errorDict]
|    return -options $errorDict $errorMessage
|}


~ Alternatives

   *   Revision 1.11 of this TIP proposed to really throw the error.

   *   Revision 1.21 of this TIP proposed a new option to return an error dict directly.

~ Implementation

The tip is implemented in fossil branch '''tip-428'''.

~ Remarks

The idea of this semantics and a feasability study is from Reinhard Max.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|

|


|

|

|


|
|
|
<
|
>
|

|

|

|
|

|


|

|

|

|

|

|

|

|



|
|
|
|
|
|
|
|
|

|

|
|
|
<
|
>
|





|

|

|



|


>

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

# TIP 428: Produce Error Dictionary from 'fconfigure -error'

	Author:         Harald Oehlmann <[email protected]>
	Author:         Harald Oehlmann <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        16-Mar-2014
	Post-History:   
	Keywords:       socket,non-blocking,error reporting,option dictionary
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes a new method which allows to return the error message and the error code of a background socket error \(as reported by **fconfigure -error**\), similar to the option dictionaries produced by catch and try and consumed by return.

# Rationale

The error message of a background channel error may be retrieved and
cleared by **fconfigure** _channel_ **-error**, but there is no access to the error code.

In addition, the error may not be handled in the TCL-like way using **catch** or **try** \(or just let fail the program\).

Specially the new **try** syntax \(see example in the man page\) is well suited to handle socket errors.
Example:

	try {set h [socket $host $port]}\
	trap {POSIX ECONNREFUSED} {} {
	    # handle not open port

	}

Drivers mostly use POSIX errors to report issues where the error code is more portable than the error message \(AFAIK\).

To handle an error by **try**, the error must be thrown.

We are limited to an option to the command **fconfigure**, as this is implemented within the driver interface.

Throwing the error would change the semantics of **fconfigure** and thus should not happen \(consensus on the core list\).
Instead, the new **fconfigure** operation should return the error message and the error code.

To finally throw the error, an utility function \(**chan throwerror $h**\) may be defined in TCL.
This is not part of this TIP.

# Proposed Change

The option **fconfigure channel -error** should be extended to take an optional argument as follows:

 > **fconfigure** _channel_ **-error** _?errorDictVar?_

If the optional argument _errorDictVar_ is given, the following dict is written in the named variable of the caller environment:

   *   if there is no error, it should be set to **-code 0**

   *   if there is an error, it should be set to **-code 1 -errorcode ** _errorCode_

This is executed in addition to the standard action of **fconfigure** _channel_ **-error**.

# Example

Usage example with failing async connect:

	% set h [connect -async localhost 30001]
	d00000af
	% fileevent $h writable {set x 1}
	% vwait x
	% fconfigure $h -error errorDict
	connection refused
	% set errorDict
	-code 1 -errorcode {POSIX ECONNREFUSED {connection refused}}
	% close $h

The following example demonstrates the implementation of **chan throwerror** eg to throw the error from the provided dict.

	proc throwerror {h} {
	    set errorMessage [fconfigure $h -errorDict]
	    return -options $errorDict $errorMessage

	}

# Alternatives

   *   Revision 1.11 of this TIP proposed to really throw the error.

   *   Revision 1.21 of this TIP proposed a new option to return an error dict directly.

# Implementation

The tip is implemented in fossil branch **tip-428**.

# Remarks

The idea of this semantics and a feasability study is from Reinhard Max.

# Copyright

This document has been placed in the public domain.

Name change from tip/429.tip to tip/429.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

TIP:            429
Title:          A 'string' Subcommand for Concatenation
Version:        $Revision: 1.6 $
Author:         Andreas Leitgeb <[email protected]>
Author:         Alexandre Ferrieux <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        27-Jul-2014
Post-History:   
Keywords:       Tcl,cat,scriptlet result
Tcl-Version:    8.6.2


~ Abstract

This TIP describes a new (sub)command '''string cat''' to concatenate an
arbitrary number of strings.

~ Rationale

Tcl has string concatenation built-in. But that is lacking in two specific
cases:

   * one cannot directly concat a braced string with anything else

   * scriptlets such as used for '''lmap''' are expected to contain commands,
     the last one of which returns a value. To have the scriptlet return a
     concatenated string or even just a single string literal, one currently
     needs to misuse some corner-case of a non-trivial command, like '''return
     -level 0 $x$y''' or '''string map {} "$x$y"''' just to have the scriptlet
     produce the string as its result.

~ Proposal

I propose a new subcommand '''string cat''', that will take an arbitrary
number of arguments (i.e., 0 or more), and concatenate them into a single
string that becomes the result of the command.

It would be equivalent to creating a '''list''' of the separate arguments and
use '''join''' on that list with an empty string as second argument.

Compiling that new command to bytecode should be trivial, as concatenation of
strings is already compileable. The added value would be allowing braced
string literals to be involved, and promoting the resulting stack-item to the
result of the command/scriptlet. (This simple compileability is also meant to
be a main advantage over '''join [[list ...]] ""''', where the contents of the
intermediate list are either a single word or many words, or '''lindex [[list
...]] 0''' where the contents of the intermediate list are a single word.)

The following equality will hold for any arbitrary contents of the variables
'''a''' and '''b''':

| string equals $a$b [string cat $a $b]

~ Rejected Alternatives

Lars has mailed on tclcore that TclX has a command '''cconcat''' that does essentially what my proposed '''string cat''' is supposed to do (not sure though whether that is compiled). This proposal sticks to the '''cat''' subcommand, as that is generally the preferred way over new toplevel commands.

Also, '''string concat''' is added to this section, for it is a bit longer than '''string cat''', and (as Lars put it) '''string cat''' is less likely to be misinterpreted as "concat, just moved into the string ensemble."

~ Reference implementation

Available as branch tip-429 on core.tcl.tk.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|






|


|
|


|

|
|


|
|




|
|
|
|


|

|

|

|

|

|



|


>

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

# TIP 429: A 'string' Subcommand for Concatenation

	Author:         Andreas Leitgeb <[email protected]>
	Author:         Alexandre Ferrieux <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        27-Jul-2014
	Post-History:   
	Keywords:       Tcl,cat,scriptlet result
	Tcl-Version:    8.6.2
-----

# Abstract

This TIP describes a new \(sub\)command **string cat** to concatenate an
arbitrary number of strings.

# Rationale

Tcl has string concatenation built-in. But that is lacking in two specific
cases:

   * one cannot directly concat a braced string with anything else

   * scriptlets such as used for **lmap** are expected to contain commands,
     the last one of which returns a value. To have the scriptlet return a
     concatenated string or even just a single string literal, one currently
     needs to misuse some corner-case of a non-trivial command, like **return
     -level 0 $x$y** or **string map \{\} "$x$y"** just to have the scriptlet
     produce the string as its result.

# Proposal

I propose a new subcommand **string cat**, that will take an arbitrary
number of arguments \(i.e., 0 or more\), and concatenate them into a single
string that becomes the result of the command.

It would be equivalent to creating a **list** of the separate arguments and
use **join** on that list with an empty string as second argument.

Compiling that new command to bytecode should be trivial, as concatenation of
strings is already compileable. The added value would be allowing braced
string literals to be involved, and promoting the resulting stack-item to the
result of the command/scriptlet. \(This simple compileability is also meant to
be a main advantage over **join [list ...] ""**, where the contents of the
intermediate list are either a single word or many words, or **lindex [list
...] 0** where the contents of the intermediate list are a single word.\)

The following equality will hold for any arbitrary contents of the variables
**a** and **b**:

	 string equals $a$b [string cat $a $b]

# Rejected Alternatives

Lars has mailed on tclcore that TclX has a command **cconcat** that does essentially what my proposed **string cat** is supposed to do \(not sure though whether that is compiled\). This proposal sticks to the **cat** subcommand, as that is generally the preferred way over new toplevel commands.

Also, **string concat** is added to this section, for it is a bit longer than **string cat**, and \(as Lars put it\) **string cat** is less likely to be misinterpreted as "concat, just moved into the string ensemble."

# Reference implementation

Available as branch tip-429 on core.tcl.tk.

# Copyright

This document has been placed in the public domain.

Name change from tip/43.tip to tip/43.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

TIP:            43
Title:          How to be a TIP Editor
Version:        $Revision: 1.4 $
Author:         Donal K. Fellows <[email protected]>
State:          Draft
Type:           Informative
Vote:           Pending
Created:        07-Jul-2001
Post-History:   


~ Abstract

This TIP describes some of the rules and guidelines that the TIP
Editor uses when accepting TIPs for the first time.

~ Rules

There are some things that are hard rules, which should be obeyed even
if it means having to postpone acceptance of the TIP or rewrite it
yourself.

 * ''Every TIP ''must'' be relevant to Tcl and/or Tk.''

 > It's probably better to suggest that changes that affect just a
   single extension should be dealt with through the processes for
   feature requests for that extension, but where they are about
   providing some kind common interface across a whole group of
   extensions, it is fair to think of using a TIP as well.  I'd reckon
   that's up to the discretion of the editor, but no TIP should be
   rejected by the editor out of hand, and never without a proper
   written explanation.

 > Of course, ultimately whether a TIP is relevant to Tcl and/or Tk is
   up to the whole Tcl Core Team (as described in [0]) so you should
   try to ensure that their policy on TIP-suitability is what you are
   enforcing.

 * ''Every TIP ''must'' be in the TIP format (see [3] for details.)''

 > This is important because it allows the TIP rendering engine to
   handle all the formatting and indexing automatically for you.  Note
   that it is very picky about the format of the header, and not that
   choosy about the format of the content (though it is not a good
   idea to have a sub-item of a list without a previous main item.)
   Get it wrong, and the TIP archive engine will fail in all sorts of
   "interesting" ways.  Take particular note of the format of the
   ''Created:'' line, as it surprises many people in just how exact it
   must be.

 * ''Every author ''must'' be associated with a real email address.''

 > You should fill this in yourself if it is not already supplied and
   spam-protected addresses are not acceptable, since they tend to
   frustrate the main purpose of TIPs which is to foster collaboration
   on things to improve Tcl and Tk.  Proper email addresses help this
   by always allowing people to contact the author of the TIP to give
   suggestions to improve the TIP or to resolve issues they have with
   it.

 * ''Every TIP ''must'' have an Abstract.''

 > Not everyone has the desire, or the time, to read each TIP.
   Providing an abstract allows people to determine whether the TIP is
   relevant to what they are looking for at the moment.  Searches on
   the TIP archive also always search the abstract.

 > Abstracts should be formed of the section title whose text is
   precisely "Abstract" and then a single normal paragraph of no more
   than around 200 words; if it is longer than that then it is no
   longer a summary or abstract but a genuine major part of the
   document body.  While authors should write their own abstracts, it
   is reasonable for the editor to add one, particularly if the
   author's native language is not English.

 * ''Every TIP ''must'' have a Copyright declaration.''

 > World-wide copyright laws are funny things, and I'm not sure that
   it is safe to assume that the submission of the TIP constitutes
   permission for all the things that might be done with it in the
   future.  Work around this by getting every author to clarify the
   copyright position at time of submission by explicitly saying that
   the document is placed in the public domain.  (The way that TIPs
   are kept under CVS should assuage most concerns relating to
   misrepresentation through inappropriate modifications, and it is a
   definite aim that TIPs should be distributed as widely as possible
   to encourage a wide dissemination of the ideas contained.)

~ Guidelines

 * TIPs should be written in English (unless there are very good
   reasons otherwise) since that is the language most widely
   understood in the Tcl/Tk community.

 * TIP should be written so as to be readable!  This requirement is
   not strict, but it will make it much easier for the TCT to
   evaluate...

 * The Abstract should be written in a third-person voice, and
   ''definitely'' in English.  It isn't so important for the rest of
   the TIP, but the abstract will be seen quite a bit more widely and
   without as much context.  It also fits in with the style of the
   existing abstracts.

 * The section headings and title should be capitalised according to
   the rules for such things in English.  It looks neater that way.

 * Spell check before checking in.  No sense in having glaring errors
   in the initial version!  (I do not enforce the use of either US or
   UK spellings; that is rightfully the domain of the TIP author who
   might be based anywhere in the world.)  Be especially careful with
   the checking of the spellings of the names of file names, C
   identifiers or Tcl commands/variables/etc.

 * C identifiers and Tcl commands/variables/etc. should normally be
   ''emphasized'', as should file names.  This should be moderated by
   good sense though; the aim of such emphasis is to indicate that it
   is a reference to an entity in the code domain as opposed to the
   domain of the English language.

 * TIP numbers should be allocated by the TIP editor in sequence of
   the order they are checked into the CVS archive.  Make sure that
   the filename (''num.tip'') matches up with the ''TIP: num'' header
   or bizarre things may happen.

 * Where someone submits a TIP proposing a new Tk widget, invite them
   to supply an image (or two) of how the widget will look in
   operation.  These images will need to be checked in by hand, and
   will not be editable.  Images should be checked in in both a raster
   form (GIF, JPEG or PNG) and as Encapsulated PostScript (EPS) - make
   sure that you set the binary flag on the file when you do this.
   Where someone produces a diagram with a tool that can produce FIG
   files, it is nice if you can check that into CVS as well so that
   the diagram itself can be maintained if necessary.

 > As a convention, name the images with the TIP number as the first
   part of the name.  This makes it much easier to determine what TIP
   a particular image is associated with (and certainly beats grepping
   the whole set of TIPs!)

 * Once a TIP is checked in, it should normally be published to
   news:comp.lang.tcl, news:comp.lang.tcl.annouce and the tcl-core
   mailing list (though with some TIPs it is obvious that wider
   dissemination is less useful.)  It is a good idea to send a copy to
   the TIP author as well, as this lets them know not only that the
   TIP has been accepted but also what it looks like and that it has
   been distributed to the wider community.  The ''postnews.tcl''
   script that comes with the TIP renderer distribution is designed to
   do all this with a minimum of fuss.  A quick "Thank You" note is
   also courteous.

 * When a TIP has been accepted by the TCT in a TYANNOTT vote, put a
   note into the log to record what the vote was.  It is best to do
   this as part of the log message for when you change the Vote: and
   Status: headers...

 * If a TIP does not state whether it is an alteration to Tcl or Tk in
   either its title or its abstract, it is a good idea to add a
   Keywords: header (or a keyword in an existing such header) which
   includes that information.

 * Don't forget to use both '''bold''' and ''italic'' text when
   formatting strings that represent command syntaxes.  It makes them
   much clearer!

''I need to write something here about the production of PS and PDF
versions of the whole TIP archive, but that side of the code is not
yet finished and released.''

~ Notes

TIPs do not need to be tightly focussed.  Making them so does make
them easier to evaluate, but it might also remove the real rationale
behind the changes.  Instead, it is best that they form a coherent
logical entity, since I believe that it is that which makes for a good
TIP.

The title, section headings and list item headings must be plain text.
This is because there are output formats which are very picky about
what is allowed in those sorts of places (PDF bookmarks have
especially strict restrictions) and plain text has the virtue of being
accepted pretty much everywhere.

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
>

|




|





|

|








|
|



|

|


|
|


|


|

|







|

|




|







|

|




|



|

|

|
|







|








|

|




|






|



|


|





|

|
|



|
|


|











|


|



|

|

|









|
|


|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

# TIP 43: How to be a TIP Editor

	Author:         Donal K. Fellows <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        07-Jul-2001
	Post-History:   
-----

# Abstract

This TIP describes some of the rules and guidelines that the TIP
Editor uses when accepting TIPs for the first time.

# Rules

There are some things that are hard rules, which should be obeyed even
if it means having to postpone acceptance of the TIP or rewrite it
yourself.

 * _Every TIP _must_ be relevant to Tcl and/or Tk._

	 > It's probably better to suggest that changes that affect just a
   single extension should be dealt with through the processes for
   feature requests for that extension, but where they are about
   providing some kind common interface across a whole group of
   extensions, it is fair to think of using a TIP as well.  I'd reckon
   that's up to the discretion of the editor, but no TIP should be
   rejected by the editor out of hand, and never without a proper
   written explanation.

	 > Of course, ultimately whether a TIP is relevant to Tcl and/or Tk is
   up to the whole Tcl Core Team \(as described in [[0]](0.md)\) so you should
   try to ensure that their policy on TIP-suitability is what you are
   enforcing.

 * _Every TIP _must_ be in the TIP format \(see [[3]](3.md) for details.\)_

	 > This is important because it allows the TIP rendering engine to
   handle all the formatting and indexing automatically for you.  Note
   that it is very picky about the format of the header, and not that
   choosy about the format of the content \(though it is not a good
   idea to have a sub-item of a list without a previous main item.\)
   Get it wrong, and the TIP archive engine will fail in all sorts of
   "interesting" ways.  Take particular note of the format of the
   _Created:_ line, as it surprises many people in just how exact it
   must be.

 * _Every author _must_ be associated with a real email address._

	 > You should fill this in yourself if it is not already supplied and
   spam-protected addresses are not acceptable, since they tend to
   frustrate the main purpose of TIPs which is to foster collaboration
   on things to improve Tcl and Tk.  Proper email addresses help this
   by always allowing people to contact the author of the TIP to give
   suggestions to improve the TIP or to resolve issues they have with
   it.

 * _Every TIP _must_ have an Abstract._

	 > Not everyone has the desire, or the time, to read each TIP.
   Providing an abstract allows people to determine whether the TIP is
   relevant to what they are looking for at the moment.  Searches on
   the TIP archive also always search the abstract.

	 > Abstracts should be formed of the section title whose text is
   precisely "Abstract" and then a single normal paragraph of no more
   than around 200 words; if it is longer than that then it is no
   longer a summary or abstract but a genuine major part of the
   document body.  While authors should write their own abstracts, it
   is reasonable for the editor to add one, particularly if the
   author's native language is not English.

 * _Every TIP _must_ have a Copyright declaration._

	 > World-wide copyright laws are funny things, and I'm not sure that
   it is safe to assume that the submission of the TIP constitutes
   permission for all the things that might be done with it in the
   future.  Work around this by getting every author to clarify the
   copyright position at time of submission by explicitly saying that
   the document is placed in the public domain.  \(The way that TIPs
   are kept under CVS should assuage most concerns relating to
   misrepresentation through inappropriate modifications, and it is a
   definite aim that TIPs should be distributed as widely as possible
   to encourage a wide dissemination of the ideas contained.\)

# Guidelines

 * TIPs should be written in English \(unless there are very good
   reasons otherwise\) since that is the language most widely
   understood in the Tcl/Tk community.

 * TIP should be written so as to be readable!  This requirement is
   not strict, but it will make it much easier for the TCT to
   evaluate...

 * The Abstract should be written in a third-person voice, and
   _definitely_ in English.  It isn't so important for the rest of
   the TIP, but the abstract will be seen quite a bit more widely and
   without as much context.  It also fits in with the style of the
   existing abstracts.

 * The section headings and title should be capitalised according to
   the rules for such things in English.  It looks neater that way.

 * Spell check before checking in.  No sense in having glaring errors
   in the initial version!  \(I do not enforce the use of either US or
   UK spellings; that is rightfully the domain of the TIP author who
   might be based anywhere in the world.\)  Be especially careful with
   the checking of the spellings of the names of file names, C
   identifiers or Tcl commands/variables/etc.

 * C identifiers and Tcl commands/variables/etc. should normally be
   _emphasized_, as should file names.  This should be moderated by
   good sense though; the aim of such emphasis is to indicate that it
   is a reference to an entity in the code domain as opposed to the
   domain of the English language.

 * TIP numbers should be allocated by the TIP editor in sequence of
   the order they are checked into the CVS archive.  Make sure that
   the filename \(_num.tip_\) matches up with the _TIP: num_ header
   or bizarre things may happen.

 * Where someone submits a TIP proposing a new Tk widget, invite them
   to supply an image \(or two\) of how the widget will look in
   operation.  These images will need to be checked in by hand, and
   will not be editable.  Images should be checked in in both a raster
   form \(GIF, JPEG or PNG\) and as Encapsulated PostScript \(EPS\) - make
   sure that you set the binary flag on the file when you do this.
   Where someone produces a diagram with a tool that can produce FIG
   files, it is nice if you can check that into CVS as well so that
   the diagram itself can be maintained if necessary.

	 > As a convention, name the images with the TIP number as the first
   part of the name.  This makes it much easier to determine what TIP
   a particular image is associated with \(and certainly beats grepping
   the whole set of TIPs!\)

 * Once a TIP is checked in, it should normally be published to
   news:comp.lang.tcl, news:comp.lang.tcl.annouce and the tcl-core
   mailing list \(though with some TIPs it is obvious that wider
   dissemination is less useful.\)  It is a good idea to send a copy to
   the TIP author as well, as this lets them know not only that the
   TIP has been accepted but also what it looks like and that it has
   been distributed to the wider community.  The _postnews.tcl_
   script that comes with the TIP renderer distribution is designed to
   do all this with a minimum of fuss.  A quick "Thank You" note is
   also courteous.

 * When a TIP has been accepted by the TCT in a TYANNOTT vote, put a
   note into the log to record what the vote was.  It is best to do
   this as part of the log message for when you change the Vote: and
   Status: headers...

 * If a TIP does not state whether it is an alteration to Tcl or Tk in
   either its title or its abstract, it is a good idea to add a
   Keywords: header \(or a keyword in an existing such header\) which
   includes that information.

 * Don't forget to use both **bold** and _italic_ text when
   formatting strings that represent command syntaxes.  It makes them
   much clearer!

_I need to write something here about the production of PS and PDF
versions of the whole TIP archive, but that side of the code is not
yet finished and released._

# Notes

TIPs do not need to be tightly focussed.  Making them so does make
them easier to evaluate, but it might also remove the real rationale
behind the changes.  Instead, it is best that they form a coherent
logical entity, since I believe that it is that which makes for a good
TIP.

The title, section headings and list item headings must be plain text.
This is because there are output formats which are very picky about
what is allowed in those sorts of places \(PDF bookmarks have
especially strict restrictions\) and plain text has the virtue of being
accepted pretty much everywhere.

# Copyright

This document is placed in the public domain.

Name change from tip/430.tip to tip/430.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

TIP:            430
Title:          Add basic ZIP archive support to Tcl
Version:        $Revision: 1.6 $
Author:         Sean Woods <[email protected]>
Author:         Donal Fellows <[email protected]>
Author:         Poor Yorick <[email protected]>
Author:         Harald Oehlmann <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        03-Sep-2014
Post-History:   
Keywords:       virtual filesystem,zip,tclkit,boot,bootstrap
Tcl-Version:    8.6.3


~ Abstract

This proposal will add basic support for mounting zip archive files as virtual
filesystems to the Tcl core.

~ Target Tcl-Version

This TIP targets TCL Version 8.7 or 9.0, whatever comes first.

~ Rationale

Tcl/Tk relies on the presence of a file system containing Tcl scripts for
bootstrapping the interpreter.  When dealing with code packed in a
self-contained executable, a chicken-and-egg problem arises when developers
try to provide this bootstrap from their attached VFS with extensions like
TclVfs.  TclVfs runs in the Tcl interpreter.  The interpreter needs
''init.tcl'', which would mean that the filesystem containing ''init.tcl'' is
not present until after TclVfs mounts it yet that mount cannot happen until
after ''init.tcl'' has been loaded. Bootstrap filesystem mounts require
built-in support for the filesystem that they use.

With the inclusion of Zlib in the core (starting with 8.6, [244]), all that is
required to implement a zip file system based VFS is to add a C-level VFS
implementation to decode the zip archive format. Thus: this project.

Note that we are prioritizing the zip archive format also because it is
practical to generate the files without a Tcl installation being present; it
is a format with widespread OS support. This makes it much easier to bootstrap
a build of Tcl that uses it without requiring a native build of tclsh to be
present.

~ Specification

There shall be new commands added to safe interpreters withing Tcl. All of which 
shall be in the '''::zvfs''' namespace. These commands shall include:

 * '''zvfs::mount''' ?''archive''? ?''mountpoint''?

 > Mounts the ZIP file ''archive'' at the location given by ''mountpoint'',
   which will default to '''zipfs:''/''archive'' if absent. With no arguments
   this command describes all current mounts, returning a list of pairs.

 * '''zvfs::unmount''' ''archive''

 > Unmounts the ZIP file ''archive'', which must have been previously mounted.

Safe interpreters will not be given the mount or unmount commands. 
Already mounted file systems will be available via the '''glob''' and '''file'''
commands. These commands, and any commands related to building
archives will be marked with the unsafe bit within the '''zipfs''' ensemble,
and will be removed from any interpreter through the normal mechanism
to hide unsafe commands within the core.

~ Implementation

I have adapted Richard Hipp's work on Tcl As One Big Executable (TOBE) to
operate inside of a modern Tcl. That implementation consists of one C file
(''tclZipvfs.c'').  I have also prepared new behaviors for inside of
Tcl_AppInit() to detect if a zip filesystem is attached to the current
executable, and how to extract a "''main.tcl''" as well as the initial file
systems for both Tcl and Tk.

This work is checked in as the "''core_zip_vfs''" branch on both Tcl and Tk.

~ C API

* '''int TclZipfsInit(Tcl_Interp *interp);'''
> Initializes the C API for Zipfs. If called with a non-null ''interp'', adds the commands
   for the zipfs Tcl API to the interpreter. Returns '''TCL_OK''' on success, and '''TCL_ERROR''' in  
   all other cases.

* '''int TclZipfsMount(Tcl_Interp *interp, const char *zipname, const char *mntpt, const char *passwd);'''
> Mounts a zip file ''zipname'' to the mount point ''mntpt''. If ''passwd'' is non-null, that string is
   utilized as the password to decrypt the contents. ''mnpnt'' will always be relative to '''zipfs:'''

* '''int TclZipfsUnmount(Tcl_Interp *interp, const char *zipname);'''
> Unmount the file system created by a prior call to '''TclZipfsMount()'''

~ Bootstraping

The mount and unmount commands are usable within the core as just another feature engine. A call to TclZipfsInit() will be inserted into tclBasic.c, immediately after the code to initialize zlib.

A modified shell (tclkit.exe) will be generated by Make. This shell will:
* Check if the executable has a zip archive attached. If so, that 
archive shall be mounted as '''zipfs:/app'''. 
* If ''zipfs:/app" is present the interpreter will look for 
'''boot/tcl/init.tcl'''. If that file is present, the location for '''$tcl_library'''
will be set to '''zipfs:/app/boot/tcl'''.
* If ''zipfs:/app'' is present the interpreter will look for '''boot/tk/tk.tcl'. If present
the location for '''$tk_library''' will be set to '''zipfs:/boot/tk'''. 
* If the file '''pkgIndex.tcl''' is present, the '''$dir''' variable will be set to
'''zipfs:/app''' and the file will be sourced as if it were a package index.
* If the file '''main.tcl''' is present, the file '''zipfs://app/main.tcl''' will be registered with '''Tcl_SetStartupScript()'''

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
>

|




|



|






|

|


|









|


|

|

|
|


|

|


|

|



|

|

|
|
|


|

|

|
|
|


|
|
|

|
|

|

|

|

|
|
|
|
|
|
|
|
|

|


>

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

# TIP 430: Add basic ZIP archive support to Tcl

	Author:         Sean Woods <[email protected]>
	Author:         Donal Fellows <[email protected]>
	Author:         Poor Yorick <[email protected]>
	Author:         Harald Oehlmann <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        03-Sep-2014
	Post-History:   
	Keywords:       virtual filesystem,zip,tclkit,boot,bootstrap
	Tcl-Version:    8.6.3
-----

# Abstract

This proposal will add basic support for mounting zip archive files as virtual
filesystems to the Tcl core.

# Target Tcl-Version

This TIP targets TCL Version 8.7 or 9.0, whatever comes first.

# Rationale

Tcl/Tk relies on the presence of a file system containing Tcl scripts for
bootstrapping the interpreter.  When dealing with code packed in a
self-contained executable, a chicken-and-egg problem arises when developers
try to provide this bootstrap from their attached VFS with extensions like
TclVfs.  TclVfs runs in the Tcl interpreter.  The interpreter needs
_init.tcl_, which would mean that the filesystem containing _init.tcl_ is
not present until after TclVfs mounts it yet that mount cannot happen until
after _init.tcl_ has been loaded. Bootstrap filesystem mounts require
built-in support for the filesystem that they use.

With the inclusion of Zlib in the core \(starting with 8.6, [[244]](244.md)\), all that is
required to implement a zip file system based VFS is to add a C-level VFS
implementation to decode the zip archive format. Thus: this project.

Note that we are prioritizing the zip archive format also because it is
practical to generate the files without a Tcl installation being present; it
is a format with widespread OS support. This makes it much easier to bootstrap
a build of Tcl that uses it without requiring a native build of tclsh to be
present.

# Specification

There shall be new commands added to safe interpreters withing Tcl. All of which 
shall be in the **::zvfs** namespace. These commands shall include:

 * **zvfs::mount** ?_archive_? ?_mountpoint_?

	 > Mounts the ZIP file _archive_ at the location given by _mountpoint_,
   which will default to **zipfs:_/_archive_ if absent. With no arguments
   this command describes all current mounts, returning a list of pairs.

 * **zvfs::unmount** _archive_

	 > Unmounts the ZIP file _archive_, which must have been previously mounted.

Safe interpreters will not be given the mount or unmount commands. 
Already mounted file systems will be available via the **glob** and **file**
commands. These commands, and any commands related to building
archives will be marked with the unsafe bit within the **zipfs** ensemble,
and will be removed from any interpreter through the normal mechanism
to hide unsafe commands within the core.

# Implementation

I have adapted Richard Hipp's work on Tcl As One Big Executable \(TOBE\) to
operate inside of a modern Tcl. That implementation consists of one C file
\(_tclZipvfs.c_\).  I have also prepared new behaviors for inside of
Tcl\_AppInit\(\) to detect if a zip filesystem is attached to the current
executable, and how to extract a "_main.tcl_" as well as the initial file
systems for both Tcl and Tk.

This work is checked in as the "_core\_zip\_vfs_" branch on both Tcl and Tk.

# C API

* **int TclZipfsInit\(Tcl\_Interp \*interp\);**
	> Initializes the C API for Zipfs. If called with a non-null _interp_, adds the commands
   for the zipfs Tcl API to the interpreter. Returns **TCL\_OK** on success, and **TCL\_ERROR** in  
   all other cases.

* **int TclZipfsMount\(Tcl\_Interp \*interp, const char \*zipname, const char \*mntpt, const char \*passwd\);**
	> Mounts a zip file _zipname_ to the mount point _mntpt_. If _passwd_ is non-null, that string is
   utilized as the password to decrypt the contents. _mnpnt_ will always be relative to **zipfs:**

* **int TclZipfsUnmount\(Tcl\_Interp \*interp, const char \*zipname\);**
	> Unmount the file system created by a prior call to **TclZipfsMount\(\)**

# Bootstraping

The mount and unmount commands are usable within the core as just another feature engine. A call to TclZipfsInit\(\) will be inserted into tclBasic.c, immediately after the code to initialize zlib.

A modified shell \(tclkit.exe\) will be generated by Make. This shell will:
* Check if the executable has a zip archive attached. If so, that 
archive shall be mounted as **zipfs:/app**. 
* If _zipfs:/app" is present the interpreter will look for 
**boot/tcl/init.tcl**. If that file is present, the location for **$tcl\_library**
will be set to **zipfs:/app/boot/tcl**.
* If _zipfs:/app_ is present the interpreter will look for **boot/tk/tk.tcl'. If present
the location for **$tk\_library** will be set to **zipfs:/boot/tk**. 
* If the file **pkgIndex.tcl** is present, the **$dir** variable will be set to
**zipfs:/app** and the file will be sourced as if it were a package index.
* If the file **main.tcl** is present, the file **zipfs://app/main.tcl** will be registered with **Tcl\_SetStartupScript\(\)**

# Copyright

This document has been placed in the public domain.

Name change from tip/431.tip to tip/431.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

TIP:		431
Title:		Add 'tempdir' Subcommand to 'file'
Version:	$Revision: 1.2 $
Author:		Kevin Pasko <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	8.6.4
Vote:		Pending
Created:		10-Sep-2014
Keywords:	Tcl, directory, file
Post-History:


~ Abstract

This TIP proposes adding a new '''tempdir''' subcommand to the '''file'''
command, simplifying the effort required in creating uniquely named temporary
directories at the scripting level.

~ Rationale

Due to the non-atomic nature of the '''file mkdir''' command it is currently
impossible to create uniquely named temporary directories at the script level
without the possibility of race conditions.

~ Specification

The '''file tempdir''' command shall implement the functionality of the POSIX
standard mkdtemp() function. With no arguments '''file tempdir''' shall create
a uniquely named temporary directory in the native operating system's
temporary directory, with naming convention "'''tcl_'''''XXXXXX''" where each
''X'' is a randomly selected character (following the '''file tempfile'''
naming convention). Successful completion of '''file tempdir''' shall return
the absolute path of the created directory, otherwise an error shall be
thrown.

'''file tempdir''' shall have an optional argument, ''template'', to modify
the created directory's path and name. The ''template'' shall be decomposed
into (up to) two parts: the directory's path and rootname. If either part is
absent, relevant defaults (e.g., according to the native operating system)
shall be used. The entire temporary name shall then be formed from the path,
the root, and a generated unique string of (typically) six characters.

The command syntax should be defined as:

 > '''file tempdir''' ?''template''?

~ Considerations

 * The subcommand '''tempdir''' could be a candidate, later, for returning the
   native file system's temporary directory. Naming the subcommand something
   else such as '''mktempdir''' is another option, though strays from the '''file
   tempfile''' naming convention.

 * For future extensibility the '''template''' argument to '''file tempdir'''
   (since it is optional) could be specified in the key / value format,
   '''-template''', changing the command syntax to:

 > > '''file tempdir''' ?''options...''?

~ Reference Implementation

An example of temporary directory creation has already been developed into the
Tcl core, at the C level, within the platform specific layers of the
'''load''' command. The principal work remaining is to expose this via a Tcl
command.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|

|



|

|
|

|
|
|



|
|
|
|

|



|

|

|

|
|

|
|
|

|

|



|


|


>

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

# TIP 431: Add 'tempdir' Subcommand to 'file'

	Author:		Kevin Pasko <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	8.6.4
	Vote:		Pending
	Created:		10-Sep-2014
	Keywords:	Tcl, directory, file
	Post-History:
-----

# Abstract

This TIP proposes adding a new **tempdir** subcommand to the **file**
command, simplifying the effort required in creating uniquely named temporary
directories at the scripting level.

# Rationale

Due to the non-atomic nature of the **file mkdir** command it is currently
impossible to create uniquely named temporary directories at the script level
without the possibility of race conditions.

# Specification

The **file tempdir** command shall implement the functionality of the POSIX
standard mkdtemp\(\) function. With no arguments **file tempdir** shall create
a uniquely named temporary directory in the native operating system's
temporary directory, with naming convention "**tcl\_**_XXXXXX_" where each
_X_ is a randomly selected character \(following the **file tempfile**
naming convention\). Successful completion of **file tempdir** shall return
the absolute path of the created directory, otherwise an error shall be
thrown.

**file tempdir** shall have an optional argument, _template_, to modify
the created directory's path and name. The _template_ shall be decomposed
into \(up to\) two parts: the directory's path and rootname. If either part is
absent, relevant defaults \(e.g., according to the native operating system\)
shall be used. The entire temporary name shall then be formed from the path,
the root, and a generated unique string of \(typically\) six characters.

The command syntax should be defined as:

 > **file tempdir** ?_template_?

# Considerations

 * The subcommand **tempdir** could be a candidate, later, for returning the
   native file system's temporary directory. Naming the subcommand something
   else such as **mktempdir** is another option, though strays from the **file
   tempfile** naming convention.

 * For future extensibility the **template** argument to **file tempdir**
   \(since it is optional\) could be specified in the key / value format,
   **-template**, changing the command syntax to:

	 > > **file tempdir** ?_options..._?

# Reference Implementation

An example of temporary directory creation has already been developed into the
Tcl core, at the C level, within the platform specific layers of the
**load** command. The principal work remaining is to expose this via a Tcl
command.

# Copyright

This document has been placed in the public domain.

Name change from tip/432.tip to tip/432.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

TIP:		432
Title:		Support for New Windows File Dialogs in Vista and Later
Version:	$Revision: 1.4 $
Author:		Ashok P. Nadkarni <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	20-Sep-2014
Post-History:	
Tcl-Version:	8.6.3


~ Abstract

This TIP proposes changing the '''tk_getOpenFile''', '''tk_getSaveFile''' and
'''tk_chooseDirectory''' dialog box commands to display the new style file
dialogs available on newer Windows versions.

~ Rationale

As of Tk 8.6.2, the above commands translate to Windows native file dialogs
corresponding to the ones present in Windows XP (the earliest version of
Windows supported by Tcl 8.6). Vista and later Windows systems have newer
versions of these dialogs with additional features and a different look and
feel. Although the older dialogs are functional on these platforms, they have
the following issues:

 * They do not support the new features, such as breadcrumbs, enhanced
   navigation etc.
   
 * The look and feel is dated and inconsistent not only with other native
   applications, but even with Tk itself since the Ttk widgets adapt to the
   theme for the platform.

In addition, this TIP proposes some changes to behaviour with respect to
existing dialogs that would make the dialogs more consistent with Windows
conventions.

~ Proposed Changes

The proposal will result in the '''tk_getOpenFile''', '''tk_getSaveFile''' and
'''tk_chooseDirectory''' dialog box commands displaying the new Vista style
file dialogs if available and falling back to the older style otherwise.
Options to the commands and return value from the dialogs remain unchanged
except as noted below.

~~ Incompatible changes

If the '''-initialdir''' option is not specified, the new dialog will default
to the default Windows mechanism for choosing the initial directory displayed.
Documentation will be updated to state that the initial directory displayed
when this option is not present is system dependent.

~ Reference Implementation

A reference implementation is available in the apn-win-filedialogs branch.

The new dialogs require a new COM interface IFileDialog. The reference
implementation uses this interface if available and falls back to the old one
otherwise.

~ Discussion

 * The change in behaviour when '''-initialdir''' is not specified is driven
   by the fact that on Windows the current working directory for a GUI program
   is generally the directory where the program was installed. This is almost
   never useful and is contrary to what the user expects which is the last
   directory shown by the program (even across process invocations).

 * Should there be either a global setting or an option that forces the use of
   old style dialogs. Alternatively, should the new dialogs be only displayed
   if a (new) option is specified with the command.  The author is not in
   favor of either of these but applications that have documented screenshots
   may wish to preserve the old dialogs.  As of now, the reference
   implementation has a hidden option '''-xpstyle''' that can be used to
   select between old and new styles.  This is present mainly to allow
   debugging and testing of the older dialogs on newer platforms.

 * The new implementation calls '''CoInitialize''' to initialize COM. It is
   not clear when, and if, '''CoUnInitialize''' needs to be called. In fact,
   as documented in MSDN, even the '''SHBrowseForFolder''' call used by the
   current 8.6 code requires a prior call to '''CoInitialize''' which Tcl does
   not do.  Need discussion on whether Tcl should always call
   '''CoInitialize''' at thread startup and '''CoUnInitialize''' at thread
   shutdown.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|


|


|
|















|

|
|




|

|




|







|

|



|



|


|



|
|
|
|

|


|


>

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

# TIP 432: Support for New Windows File Dialogs in Vista and Later

	Author:		Ashok P. Nadkarni <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	20-Sep-2014
	Post-History:	
	Tcl-Version:	8.6.3
-----

# Abstract

This TIP proposes changing the **tk\_getOpenFile**, **tk\_getSaveFile** and
**tk\_chooseDirectory** dialog box commands to display the new style file
dialogs available on newer Windows versions.

# Rationale

As of Tk 8.6.2, the above commands translate to Windows native file dialogs
corresponding to the ones present in Windows XP \(the earliest version of
Windows supported by Tcl 8.6\). Vista and later Windows systems have newer
versions of these dialogs with additional features and a different look and
feel. Although the older dialogs are functional on these platforms, they have
the following issues:

 * They do not support the new features, such as breadcrumbs, enhanced
   navigation etc.
   
 * The look and feel is dated and inconsistent not only with other native
   applications, but even with Tk itself since the Ttk widgets adapt to the
   theme for the platform.

In addition, this TIP proposes some changes to behaviour with respect to
existing dialogs that would make the dialogs more consistent with Windows
conventions.

# Proposed Changes

The proposal will result in the **tk\_getOpenFile**, **tk\_getSaveFile** and
**tk\_chooseDirectory** dialog box commands displaying the new Vista style
file dialogs if available and falling back to the older style otherwise.
Options to the commands and return value from the dialogs remain unchanged
except as noted below.

## Incompatible changes

If the **-initialdir** option is not specified, the new dialog will default
to the default Windows mechanism for choosing the initial directory displayed.
Documentation will be updated to state that the initial directory displayed
when this option is not present is system dependent.

# Reference Implementation

A reference implementation is available in the apn-win-filedialogs branch.

The new dialogs require a new COM interface IFileDialog. The reference
implementation uses this interface if available and falls back to the old one
otherwise.

# Discussion

 * The change in behaviour when **-initialdir** is not specified is driven
   by the fact that on Windows the current working directory for a GUI program
   is generally the directory where the program was installed. This is almost
   never useful and is contrary to what the user expects which is the last
   directory shown by the program \(even across process invocations\).

 * Should there be either a global setting or an option that forces the use of
   old style dialogs. Alternatively, should the new dialogs be only displayed
   if a \(new\) option is specified with the command.  The author is not in
   favor of either of these but applications that have documented screenshots
   may wish to preserve the old dialogs.  As of now, the reference
   implementation has a hidden option **-xpstyle** that can be used to
   select between old and new styles.  This is present mainly to allow
   debugging and testing of the older dialogs on newer platforms.

 * The new implementation calls **CoInitialize** to initialize COM. It is
   not clear when, and if, **CoUnInitialize** needs to be called. In fact,
   as documented in MSDN, even the **SHBrowseForFolder** call used by the
   current 8.6 code requires a prior call to **CoInitialize** which Tcl does
   not do.  Need discussion on whether Tcl should always call
   **CoInitialize** at thread startup and **CoUnInitialize** at thread
   shutdown.

# Copyright

This document has been placed in the public domain.

Name change from tip/433.tip to tip/433.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

TIP:            433
Title:          Add %M binding substitution
Version:        $Revision: 1.7 $
Author:		Joe Mistachkin <[email protected]>
Author:		Brian Griffin <[email protected]>
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        25-Feb-2015
Post-History:   
Tcl-Version:    8.6.4


~ Abstract

This TIP proposes one new binding substitution, '''%M''', to access
the number of script-based binding patterns matched so far for the event.

~ Background

In a presentation at the 2012 Tcl Conference
(http://www.tclcommunityassociation.org/wub/proceedings/Proceedings-2012/RonWold/Customizable-Keyboard-Shortcuts.pdf), Ron Wold pointed out that
coding global catch-all scripts bound to the same event in many widgets
is complicated because Tk's '''bind''' machinery allows any bind script to
use '''break''' to prevent later bind scripts from evaluating.  Among
a known set of bind scripts, this is a useful technique, but it interferes
with the non-coordinated introduction of additional bind scripts
on the same event.

An alternative strategy is to avoid any bind script using '''break''', but
to give the latter scripts the means to detect when an earlier
script has run so it can defer its own operations.  That motivates
the introduction of a means by which a bind script can discover something
about the history of other bind script evaluations on the same event.

~ Specification

Add to the set of substitutions made in scripts passed to '''bind'''
the new one, '''%M'''.  When the substring '''%M''' appears in a binding
script, it will be replaced with a count of the number of binding
script evaluations that have already been performed in the handling
of the current event.

~ Simple Example

The script...

|   pack [entry .e]
|   bind all <Key> {set z %M}
|   bind Entry <Key> {set y %M}
|   bind .e <Key> {set x %M}
|   event generate .e <Key-a>
|   list $x $y $z

will produce the result:

|   0 1 2

~ Use Case Example

One of the default bind scripts in Tk is

| event add <<NextWindow>> <Tab>
| bind all <<NextWindow>> {tk::TabToWindow [tk_focusNext %W]}

which permits a '''<Tab>''' anywhere in Tk to shift the focus.

Some widgets have their own uses for '''<Tab>''', though, notably

| bind Text <Tab> {
|     if {[%W cget -state] eq "normal"} {
|         tk::TextInsert %W \t
|         focus %W
|         break
|     }
| }



where a text widget in normal state accepts '''Tab'''s as entered
text like any other keypresses.  The '''break''' in this script serves
to prevent the focus shift that would otherwise take place.
Since the same Tk developers coded both bind scripts, the global
knowledge can make the system work as a whole.

However, a third party facility trying to join the party has
difficulty.  Consider a simple key logging facility,

| bind all <Key> {log_key %W %k %s %x %y %X %Y %A}

This will fail to log '''Tab'''s typed in a Text due to the '''break''' noted
above.

With the '''%M''' binding proposed here, an alternative set of
bind scripts is possible.

| bind all <<NextWindow>> {if {%M==0} {tk::TabToWindow [tk_focusNext %W]}}

| bind Text <Tab> {
|     if {[%W cget -state] eq "normal"} {
|         tk::TextInsert %W \t
|         focus %W
|     }
| }



In fact with the revised script bound to '''all''' it may be that
the script bound to '''<Tab>''' is no longer needed at all and the
general default binding

| bind Text <KeyPress> {tk::TextInsert %W %A}

is sufficient.

With this alternative in place the third-party keylogger would work.

~ Compatibility

Any '''%M''' in an existing bind script will now stop reproducing
itself literally, and will result in the new substitution.  This
has the potential to cause trouble with any bind scripts that
themselves make use of '''clock scan''' or '''clock format''' or 
any other command that invites the use of the literal string '''%M'''.
Dealing with such a situation is not difficult, but it is still
a potential incompatibility.

~ Prototype

This feature is already implemented and committed to both the
core-8-5-branch and the trunk, and is poised to be released
as part of Tk 8.5.18 and Tk 8.6.4.  Any objections to that
should be raised in TIP discussion and voting.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|


|

|
|




|





|

|
|




|



|
|
|
|
|
|



|

|



|
|

|

|

|
|
|
|
|
<
<
|
>
>
|
|







|

|


|


|

|
|
|
|
<
<
|
>
>
|
|


|





|

|


|
|



|






|


>

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

# TIP 433: Add %M binding substitution

	Author:		Joe Mistachkin <[email protected]>
	Author:		Brian Griffin <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        25-Feb-2015
	Post-History:   
	Tcl-Version:    8.6.4
-----

# Abstract

This TIP proposes one new binding substitution, **%M**, to access
the number of script-based binding patterns matched so far for the event.

# Background

In a presentation at the 2012 Tcl Conference
\(<http://www.tclcommunityassociation.org/wub/proceedings/Proceedings-2012/RonWold/Customizable-Keyboard-Shortcuts.pdf\),> Ron Wold pointed out that
coding global catch-all scripts bound to the same event in many widgets
is complicated because Tk's **bind** machinery allows any bind script to
use **break** to prevent later bind scripts from evaluating.  Among
a known set of bind scripts, this is a useful technique, but it interferes
with the non-coordinated introduction of additional bind scripts
on the same event.

An alternative strategy is to avoid any bind script using **break**, but
to give the latter scripts the means to detect when an earlier
script has run so it can defer its own operations.  That motivates
the introduction of a means by which a bind script can discover something
about the history of other bind script evaluations on the same event.

# Specification

Add to the set of substitutions made in scripts passed to **bind**
the new one, **%M**.  When the substring **%M** appears in a binding
script, it will be replaced with a count of the number of binding
script evaluations that have already been performed in the handling
of the current event.

# Simple Example

The script...

	   pack [entry .e]
	   bind all <Key> {set z %M}
	   bind Entry <Key> {set y %M}
	   bind .e <Key> {set x %M}
	   event generate .e <Key-a>
	   list $x $y $z

will produce the result:

	   0 1 2

# Use Case Example

One of the default bind scripts in Tk is

	 event add <<NextWindow>> <Tab>
	 bind all <<NextWindow>> {tk::TabToWindow [tk_focusNext %W]}

which permits a **<Tab>** anywhere in Tk to shift the focus.

Some widgets have their own uses for **<Tab>**, though, notably

	 bind Text <Tab> {
	     if {[%W cget -state] eq "normal"} {
	         tk::TextInsert %W \t
	         focus %W
	         break


	     }
	 }

where a text widget in normal state accepts **Tab**s as entered
text like any other keypresses.  The **break** in this script serves
to prevent the focus shift that would otherwise take place.
Since the same Tk developers coded both bind scripts, the global
knowledge can make the system work as a whole.

However, a third party facility trying to join the party has
difficulty.  Consider a simple key logging facility,

	 bind all <Key> {log_key %W %k %s %x %y %X %Y %A}

This will fail to log **Tab**s typed in a Text due to the **break** noted
above.

With the **%M** binding proposed here, an alternative set of
bind scripts is possible.

	 bind all <<NextWindow>> {if {%M==0} {tk::TabToWindow [tk_focusNext %W]}}

	 bind Text <Tab> {
	     if {[%W cget -state] eq "normal"} {
	         tk::TextInsert %W \t
	         focus %W


	     }
	 }

In fact with the revised script bound to **all** it may be that
the script bound to **<Tab>** is no longer needed at all and the
general default binding

	 bind Text <KeyPress> {tk::TextInsert %W %A}

is sufficient.

With this alternative in place the third-party keylogger would work.

# Compatibility

Any **%M** in an existing bind script will now stop reproducing
itself literally, and will result in the new substitution.  This
has the potential to cause trouble with any bind scripts that
themselves make use of **clock scan** or **clock format** or 
any other command that invites the use of the literal string **%M**.
Dealing with such a situation is not difficult, but it is still
a potential incompatibility.

# Prototype

This feature is already implemented and committed to both the
core-8-5-branch and the trunk, and is poised to be released
as part of Tk 8.5.18 and Tk 8.6.4.  Any objections to that
should be raised in TIP discussion and voting.

# Copyright

This document has been placed in the public domain.

Name change from tip/434.tip to tip/434.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

TIP:		434
Title: 		Specify Event Sources for 'vwait'
Version: 	$Revision: 1.1 $
Author:		Jos Decoster <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	8.6
Vote:	Pending
Created:	26-Feb-2015
Post-History:	


~ Abstract

This TIP proposes to extend the '''vwait''' Tcl command so the event sources can
be specified, as is possible with the '''Tcl_DoOneEvent''' C command.

~ Rationale

In some situations it can be required not to wait for specific event sources or
to wait for specific events sources only. You might want the program to only
react on timer events, and not on file or window events. You can write your own
version of the '''Tcl_VwaitObjCmd''' command in C, and call '''Tcl_DoOneEvent'''
with the flags you need. Making it possible to specify the event sources,
i.e. the arguments for the call to '''Tcl_DoOneEvent''' within
'''Tcl_VwaitObjCmd''', from the Tcl '''vwait''' command would make this
functionality available from the Tcl lebvel.

~ Specification

This document proposes to add optional arguments to the '''vwait''' command. If
these arguments are not specified, the current event source 
'''TCL_ALL_EVENTS''' will be used. If the optinal arguments are specified, they
are the event sources to be passed to '''Tcl_DoOneEvent''' within
'''Tcl_VwaitObjCmd'''. The flags set with the optinal arguments will be
or-ed. Possible flags are corresponding to the flags for the
'''Tcl_DoOneEvent''' command:

   * '''-all''' (default) - process all events

   * '''-file'''          - process file events

   * '''-idle'''          - process idle events

   * '''-timer'''         - process timer events

   * '''-window'''        - process window system events

Example: wait until variable '''a''' is written and only allow timer events to
be processed:

| vwait a -timer

~ Alternatives

A possible alternative is to add support for a '''-events <event_list>'''
argument.

A '''-dont_wait''' argument is not added, a call to '''update''' will have the
same effect.

~ Compatibility

No incompatibilities are introduced.

~ Reference Implementation

A reference implementation is available.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|

|




|

|
|


|

|

|
|
|

|

|

|

|

|

|

|


|

|

|


|


|



|



|


>

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

# TIP 434: Specify Event Sources for 'vwait'

	Author:		Jos Decoster <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	8.6
	Vote:	Pending
	Created:	26-Feb-2015
	Post-History:	
-----

# Abstract

This TIP proposes to extend the **vwait** Tcl command so the event sources can
be specified, as is possible with the **Tcl\_DoOneEvent** C command.

# Rationale

In some situations it can be required not to wait for specific event sources or
to wait for specific events sources only. You might want the program to only
react on timer events, and not on file or window events. You can write your own
version of the **Tcl\_VwaitObjCmd** command in C, and call **Tcl\_DoOneEvent**
with the flags you need. Making it possible to specify the event sources,
i.e. the arguments for the call to **Tcl\_DoOneEvent** within
**Tcl\_VwaitObjCmd**, from the Tcl **vwait** command would make this
functionality available from the Tcl lebvel.

# Specification

This document proposes to add optional arguments to the **vwait** command. If
these arguments are not specified, the current event source 
**TCL\_ALL\_EVENTS** will be used. If the optinal arguments are specified, they
are the event sources to be passed to **Tcl\_DoOneEvent** within
**Tcl\_VwaitObjCmd**. The flags set with the optinal arguments will be
or-ed. Possible flags are corresponding to the flags for the
**Tcl\_DoOneEvent** command:

   * **-all** \(default\) - process all events

   * **-file**          - process file events

   * **-idle**          - process idle events

   * **-timer**         - process timer events

   * **-window**        - process window system events

Example: wait until variable **a** is written and only allow timer events to
be processed:

	 vwait a -timer

# Alternatives

A possible alternative is to add support for a **-events <event\_list>**
argument.

A **-dont\_wait** argument is not added, a call to **update** will have the
same effect.

# Compatibility

No incompatibilities are introduced.

# Reference Implementation

A reference implementation is available.

# Copyright

This document has been placed in the public domain.

Name change from tip/435.tip to tip/435.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

TIP:		435
Title: 		Safe Mutex Disposal API
Version: 	$Revision: 1.7 $
Author:		Donal Fellows <[email protected]>
Author:		Joe Mistachkin <[email protected]>
State:		Rejected
Type:		Project
Tcl-Version:	8.6.5
Vote:		Done
Created:	16-May-2015
Post-History:	


~ Abstract

This TIP proposes a new C API for improving mutex deletion.

~ Rationale

Context: Bug #57945b574a

There is a race condition in the code that disposes of mutexes, in that a
mutex must only be disposed of when it is not in use by another thread, yet
the disposal code does not lock it. This would not be a particular problem as
there is a ''global'' lock that protects the disposal code, except that during
the cleanup immediately after a fork (during the '''exec''' command, for
example) things can get deeply confused, and trigger deadlocks under heavy
load. We need to be careful and make sure that we really hold the global lock
when unlocking and disposing mutexes.

Because the pipeline-opening code isn't the only thing that might ever fork
internally, we should provide the capability to do this correctly as part of
Tcl's public API.

~ Specification

This TIP specifies a single new function:

 > void	'''Tcl_MutexUnlockAndFinalize'''(Tcl_Mutex *''mutex'');

The '''Tcl_MutexUnlockAndFinalize''' function (which takes a single argument,
the mutex to operate on) will atomically unlock the mutex and dispose of it
without giving an opportunity for another thread to lock the mutex between
unlocking and disposal.  The mutex must have previously been locked by
'''Tcl_MutexLock'''.

~ Implementation

See branch bug-57945b574a.

~ Acknowlegement

Thanks to Gustaf Neumann for his trouble tracking this down, and apologies for
the problems the fault has caused him.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|



|

|




|
|
|







|



|

|
|


|

|



|




|


>

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

# TIP 435: Safe Mutex Disposal API

	Author:		Donal Fellows <[email protected]>
	Author:		Joe Mistachkin <[email protected]>
	State:		Rejected
	Type:		Project
	Tcl-Version:	8.6.5
	Vote:		Done
	Created:	16-May-2015
	Post-History:	
-----

# Abstract

This TIP proposes a new C API for improving mutex deletion.

# Rationale

Context: Bug \#57945b574a

There is a race condition in the code that disposes of mutexes, in that a
mutex must only be disposed of when it is not in use by another thread, yet
the disposal code does not lock it. This would not be a particular problem as
there is a _global_ lock that protects the disposal code, except that during
the cleanup immediately after a fork \(during the **exec** command, for
example\) things can get deeply confused, and trigger deadlocks under heavy
load. We need to be careful and make sure that we really hold the global lock
when unlocking and disposing mutexes.

Because the pipeline-opening code isn't the only thing that might ever fork
internally, we should provide the capability to do this correctly as part of
Tcl's public API.

# Specification

This TIP specifies a single new function:

 > void	**Tcl\_MutexUnlockAndFinalize**\(Tcl\_Mutex \*_mutex_\);

The **Tcl\_MutexUnlockAndFinalize** function \(which takes a single argument,
the mutex to operate on\) will atomically unlock the mutex and dispose of it
without giving an opportunity for another thread to lock the mutex between
unlocking and disposal.  The mutex must have previously been locked by
**Tcl\_MutexLock**.

# Implementation

See branch bug-57945b574a.

# Acknowlegement

Thanks to Gustaf Neumann for his trouble tracking this down, and apologies for
the problems the fault has caused him.

# Copyright

This document has been placed in the public domain.

Name change from tip/436.tip to tip/436.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

TIP:		436
Title:		Improve TclOO isa Introspection
State:		Final
Type:		Project
Tcl-Version:	8.6.5
Vote:		Done
Post-History:	
Version:	$Revision: 1.3 $
Author:		Donal Fellows <[email protected]>
Created:	30-Jun-2015


~ Abstract

The various '''info object isa''' introspectors should not produce errors when
given a non-object; the set membership tests should simply return boolean
false in those cases.

~ Rationale

The '''info object isa''' command is intended to be used to allow asking
whether some object is a member of a general set of entities; for example,
'''info object isa object''' allows querying whether you actually have a
handle to an object at all. However, the other membership sets all throw an
error when given a non-object. This complicates the use of the API when all
that is really needed is to return a '''false''' value in those cases.

Motivating example (with thanks to Will Duquette): is the '''proc''' a class?
No. It's not even an object, so it clearly cannot be a class and so the
following command should produce false (or 0) and not an error:

| info object isa class proc

~ Proposed Change

Where one of the '''info object isa''' introspectors:

 * '''info object isa''' ''class object''

 * '''info object isa metaclass''' ''object''

 * '''info object isa mixin''' ''object class''

 * '''info object isa object''' ''object''

 * '''info object isa typeof''' ''object class''

Would produce an error due to either the ''object'' or (where appropriate) the
''class'' object not passing some critical precondition to the test, the
result of the command will be '''0''' (i.e., boolean false). Errors will be
still generated when the wrong number of arguments are supplied.

Note that this rule is already followed by '''info object isa object'''.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
>

|

|



|

|

|


|

|

|

|

|

|

|

|

|

|

|

|
|
|


|

|


>

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

# TIP 436: Improve TclOO isa Introspection
	State:		Final
	Type:		Project
	Tcl-Version:	8.6.5
	Vote:		Done
	Post-History:	

	Author:		Donal Fellows <[email protected]>
	Created:	30-Jun-2015
-----

# Abstract

The various **info object isa** introspectors should not produce errors when
given a non-object; the set membership tests should simply return boolean
false in those cases.

# Rationale

The **info object isa** command is intended to be used to allow asking
whether some object is a member of a general set of entities; for example,
**info object isa object** allows querying whether you actually have a
handle to an object at all. However, the other membership sets all throw an
error when given a non-object. This complicates the use of the API when all
that is really needed is to return a **false** value in those cases.

Motivating example \(with thanks to Will Duquette\): is the **proc** a class?
No. It's not even an object, so it clearly cannot be a class and so the
following command should produce false \(or 0\) and not an error:

	 info object isa class proc

# Proposed Change

Where one of the **info object isa** introspectors:

 * **info object isa** _class object_

 * **info object isa metaclass** _object_

 * **info object isa mixin** _object class_

 * **info object isa object** _object_

 * **info object isa typeof** _object class_

Would produce an error due to either the _object_ or \(where appropriate\) the
_class_ object not passing some critical precondition to the test, the
result of the command will be **0** \(i.e., boolean false\). Errors will be
still generated when the wrong number of arguments are supplied.

Note that this rule is already followed by **info object isa object**.

# Copyright

This document has been placed in the public domain.

Name change from tip/437.tip to tip/437.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

TIP:		437
Title:		Tk panedwindow options for proxy window
State:		Final
Type:		Project
Tcl-Version:	8.5.18
Vote:		Done
Post-History:	
Version:	$Revision: 1.5 $
Author:		Eric Boudaillier <[email protected]>
Author:		Fran�ois Vogel <[email protected]>
Created:	14-Jul-2015
Keywords:	Tk


~ Abstract

The proxy window (i.e., the moving sash) of the Tk paned window widget is hard
to see in some circumstances.  This TIP adds three options allowing more
control over the display of the proxy so that its visibility can be enhanced
where required.

~ Rationale

As identified in [Bug: 1247115, https://core.tcl.tk/tk/tktview/1247115], a
flat sashrelief is common for '''panedwindow''' widgets, when it separates two
widgets with sunken relief.  For example, the left part can be a tree and the
right part a text widget, both with a white background.  Under Windows, the
paned window has a light grey color, and in this configuration, the proxy
window is not well visible when it is moved over its managed widgets.

~ Proposed Change

It is proposed to add three options to the Tk '''panedwindow''' widget:
'''-proxybackground''', '''-proxyrelief''' and '''-proxyborderwidth'''.

 * '''-proxybackground''' controls the background of the proxy window.  If
   empty (the default), the background is that of the panedwindow widget,
   which is the current behaviour.

 * '''-proxyrelief''' controls the relief of the proxy window.  If empty (the
   default), the relief is that of the panedwindow widget, which is the
   current behaviour.

 * '''-proxyborderwidth''' controls the border width of the proxy window.  The
   default value is 2, which is the current value.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
|
>

|

|




|

|
|





|

|
|

|
|


|
|


|


|


>

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

# TIP 437: Tk panedwindow options for proxy window
	State:		Final
	Type:		Project
	Tcl-Version:	8.5.18
	Vote:		Done
	Post-History:	

	Author:		Eric Boudaillier <[email protected]>
	Author:		François Vogel <[email protected]>
	Created:	14-Jul-2015
	Keywords:	Tk
-----

# Abstract

The proxy window \(i.e., the moving sash\) of the Tk paned window widget is hard
to see in some circumstances.  This TIP adds three options allowing more
control over the display of the proxy so that its visibility can be enhanced
where required.

# Rationale

As identified in [Bug: 1247115, <https://core.tcl.tk/tk/tktview/1247115],> a
flat sashrelief is common for **panedwindow** widgets, when it separates two
widgets with sunken relief.  For example, the left part can be a tree and the
right part a text widget, both with a white background.  Under Windows, the
paned window has a light grey color, and in this configuration, the proxy
window is not well visible when it is moved over its managed widgets.

# Proposed Change

It is proposed to add three options to the Tk **panedwindow** widget:
**-proxybackground**, **-proxyrelief** and **-proxyborderwidth**.

 * **-proxybackground** controls the background of the proxy window.  If
   empty \(the default\), the background is that of the panedwindow widget,
   which is the current behaviour.

 * **-proxyrelief** controls the relief of the proxy window.  If empty \(the
   default\), the relief is that of the panedwindow widget, which is the
   current behaviour.

 * **-proxyborderwidth** controls the border width of the proxy window.  The
   default value is 2, which is the current value.

# Copyright

This document has been placed in the public domain.

Name change from tip/438.tip to tip/438.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149

150
151
152
153
154
155
156
157
158
159
160
161
162
163

164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179


180
181
182
183
184
185
186
187

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

TIP:            438
Title:          Ensure Line Metrics are Up-to-Date
Version:        $Revision: 1.16 $
Author:         Fran�ois Vogel <[email protected]>
Author:         Jan Nijtmans <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        01-Nov-2015
Post-History:   
Keywords:       Tk,text
Tcl-Version:    8.6.5


~ Abstract

The text widget calculates line metrics asynchronously, for performance
reasons.  Because of this, some commands of the text widget may return wrong
results if the asynchronous calculations are not over.  This TIP is about
providing the user with ways to ensure that line metrics are up-to-date.

~ Rationale

The text widget features asynchronous calculation of the display height of
logical lines. The reasons for this and the details of the implementation are
explained at the beginning of tkTextDisp.c.

This approach has definite advantages among which responsivity of the text
widget is important. Yet, there are drawbacks in the fact the calculation is
asynchronous. Some commands of the text widget may return wrong results if the
asynchronous calculations are not finished at the time these commands are
called. For example this is the case of '''.text count -ypixels''', which was
solved by adding a modifier '''-update''' allowing the user to be sure any
possible out of date line height information is recalculated.

It appears that aside of '''.text count -ypixels''' there are several other
cases where wrong results can be produced by text widget commands. These cases
are illustrated in several bug reports:

 * [http://core.tcl.tk/tk/tktview/1566949]  (.text yview moveto)

 * [http://core.tcl.tk/tk/tktview/e51941c]  (.text yview)

In all these cases, forcing the update by calling '''.text count -update
-ypixels 1.0 end''' before calling '''.text yview''', or '''.text yview
moveto''' solves the issue presented in the ticket. This has however a
performance cost, of course, but the above tickets show that there are cases
where the programmer needs accurate results, be it at the cost of the time
needed to get the line heights calculations up-to-date.

This TIP is about providing the user/programmer with (better) ways to ensure
that line metrics are up-to-date.

Indeed it is not appropriate to let the concerned commands always force update
of the line metrics or wait for the end of the update calculation each time
they are called: performance impact would be way too large.

Also, it has to be noted that the '''update''' command is of no help here since
the line metrics calculation is done within the event loop in a chained
sequence of [after 1] handlers.

~ Proposed Change

It is proposed to add two new commands to the text widget:

 > ''pathName'' '''sync''' ''?-command command?''

 > ''pathName'' '''pendingsync'''

Also a new virtual event '''<<WidgetViewSync>>''' will be added.

Description:

''pathName'' '''sync'''

    Immediately brings the line metrics up-to-date by forcing computation of
    any outdated line pixel heights. Indeed, to maintain a responsive
    user-experience, the text widget caches line heights and re-calculates them
    in the background. The command returns immediately if there is no such
    outdated line heights, otherwise it returns only at the end of the
    computation. The command returns an empty string.

Implementation details: The command executes:

|    TkTextUpdateLineMetrics(textPtr, 1,
|	      TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), -1);

''pathName'' '''sync''' '''-command''' ''command''

    Schedule ''command'' to be executed exactly once as soon as all line
    calculations are up-to-date. If there are no pending line metrics
    calculations, the scheduling is immediate. The command returns the empty
    string. '''bgerror''' is called on ''command'' failure.

''pathName'' '''pendingsync'''

    Returns 1 if the line calculations are not up-to-date, 0 otherwise.

'''<<WidgetViewSync>>'''

    A widget can have a period of time during which the internal data model is
    not in sync with the view. The '''sync''' method forces the view to be in
    sync with the data. The '''<<WidgetViewSync>>''' virtual event fires when
    the internal data model starts to be out of sync with the widget view, and
    also when it becomes again in sync with the widget view. For the text
    widget, it fires when line metrics become outdated, and when they are
    up-to-date again. Note that this means it fires in particular when
    ''pathName'' '''sync''' returns (if there was pending updates). The detail
    field (%d substitution) is either true (when the widget is in sync) or
    false (when it is not).

All '''sync''', '''pendingsync''' and '''<<WidgetViewSync>>''' apply to
each text widget independently of its peers.

The names '''sync''', '''pendingsync''' and '''<<WidgetViewSync>>''' are chosen
because of the potential for generalization to other widgets they have.

The text widget documentation will be augmented by a short section describing
the asynchronous update of line metrics, the reasons for that background
update, the drawbacks regarding possibly wrong results in '''.text yview''' or
'''.text yview moveto''', and the way to solve these issues by using the new
commands. Example code as below will be provided in the documentation, since
this code will not be included in the library (i.e. in ''text.tcl'')).

The existing '''-update''' modifier switch of '''.text count''' will become
obsolete. It will be declared as deprecated in the text widget documentation
page while being still supported for backwards compatibility reasons.

Using the new commands, ways to ensure accurate results in '''.text yview''',
or '''.text yview moveto''' are as in the following example:

|    ## Example 1:
|
|    # runtime, immediately complete line metrics at any cost (GUI unresponsive)
|    $w sync
|    $w yview moveto $fraction
|
|    ## Example 2:
|
|    # runtime, synchronously wait for up-to-date line metrics (GUI responsive)
|    $w sync -command [list $w yview moveto $fraction]
|
|    ## Example 3:
|
|    # init
|    set yud($w) 0
|    proc updateaction w {
|        set ::yud($w) 1
|        # any other update action here...
|    }

|
|    # runtime, synchronously wait for up-to-date line metrics (GUI responsive)
|    $w sync -command [list updateaction $w]
|    vwait yud($w)
|    $w yview moveto $fraction
|
|    ## Example 4:
|
|    # init
|    set todo($w) {}
|    proc updateaction w {
|        foreach cmd $::todo($w) {uplevel #0 $cmd}
|        set todo($w) {}
|    }

|
|    # runtime
|    lappend todo($w) [list $w yview moveto $fraction]
|    $w sync -command [list updateaction $w]
|
|    ## Example 5:
|
|    # init
|    set todo($w) {}
|
|    bind $w <<WidgetViewSync>> {
|        if {%d} {
|            foreach cmd $todo(%W) {eval $cmd}
|            set todo(%W) {}
|        }
|    }


|
|    # runtime
|    if {![$w pendingsync]} {
|        $w yview moveto $fraction
|    } else {
|        lappend todo($w) [list $w yview moveto $fraction]
|    }


~ Rejected alternatives

 * Use a script-visible array variable such as '''::tk::metricsDone($w)'''
   instead of an event.

 * Don't change the source code and better document the '''.text count -update
   -ypixels''' trick. This is believed to be suboptimal considering that
   '''.text count''' indeed performs counting (which has a cost). This
   performance drawback could however be very much alleviated by counting
   between the two same indices: there would be no cost at all if this case
   was detected and was a short-cut in function TextWidgetObjCmd.

 * Instead of a new text widget sub-command, follow the lines of the existing
   example of '''text count''' and provide a new modifier switch '''-update'''
   to all sub-commands that may need it. The list of such sub-commands include
   '''text yview''', '''text yview moveto''', and '''text yview scroll'''.

 * '''update idletasks''' could force line metrics calculation update (in
   addition to what this command already does). This is certainly not the
   right thing to do since it is not very flexible. It would impact the
   performance of all text widgets whereas perhaps only one of them needs
   up-to-date line heights. Also, one could want to update idletasks (in the
   current sense: idle tasks) but not the line heights calculation, or the
   opposite. All in all, linking the event loop and the line heights
   calculation seems bad.

 * For each sub-command that needs up-to-date line heights to provide fully
   correct results, detect whether it is the case or not at the time they are
   called. If so, fine. If not, there could be two ways forward:

 > 1. Force the update. This is not believed to be desirable, again for
   performance reasons. While there are cases where accurate results are
   mandatory (see the tickets above), most of the time one can live with
   approximate results. Any mismatch is temporary, since the asynchronous line
   height calculations will always catch up eventually. It is preferred to let
   the programmer decide if this update is needed or not.

 > 2. Decide that the line height of not yet up-to-date lines is equal to some
   reasonable value, for instance the height of the first displayed line
   (which is likely up-to-date). For text widgets using only a single font,
   this would be OK since all line heights are then the same. However this
   would not solve all cases, for instance in '''text yview''' where the total
   number of pixels used by the text widget contents is needed, because this
   total pixel height calculation involves the total number of display (not
   logical) lines. Assessing the total number of display lines has a
   performance cost similar to proper line heights calculation, which voids
   that path.

 * It has been proposed that the detail field %d for the
   '''<<WidgetViewSync>>''' event contain the number of outdated lines, while
   this event would fire at each [after 1] partial update of the line metrics.
   This was rejected since no use case of this value could be exhibited, and it
   was believed that firing the event twice (when out of sync and when again in
   sync) was sufficient.

 * It has been proposed that the '''text pendingsync''' command return the
   number of currently outdated lines. This was rejected because no use case
   could be found, and because this TIP aims at generalization and it might be
   hard to define the equivalent of "number of lines to do" for other widgets.
   Anyway, using a boolean now (noted as "1" and "0", rather than "true" and
   "false") leaves room to change our minds later with minimal incompatibility,
   since [if {[.t pendingsync]}] will keep its semantics with an integer.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|






|









|
|


|



|

|

|
|
|




|






|



|



|

|

|



|










|
|

|

|


|

|



|


|
|




|
|
|

|


|




|
|

|

|



|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
<
|
>
|

|


|
|
|





|

|

|
|


|
|







|

|




|

|

|

|
|




|


|
|

|



|
|
|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176


177
178
179
180
181
182
183
184

185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

# TIP 438: Ensure Line Metrics are Up-to-Date

	Author:         François Vogel <[email protected]>
	Author:         Jan Nijtmans <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        01-Nov-2015
	Post-History:   
	Keywords:       Tk,text
	Tcl-Version:    8.6.5
-----

# Abstract

The text widget calculates line metrics asynchronously, for performance
reasons.  Because of this, some commands of the text widget may return wrong
results if the asynchronous calculations are not over.  This TIP is about
providing the user with ways to ensure that line metrics are up-to-date.

# Rationale

The text widget features asynchronous calculation of the display height of
logical lines. The reasons for this and the details of the implementation are
explained at the beginning of tkTextDisp.c.

This approach has definite advantages among which responsivity of the text
widget is important. Yet, there are drawbacks in the fact the calculation is
asynchronous. Some commands of the text widget may return wrong results if the
asynchronous calculations are not finished at the time these commands are
called. For example this is the case of **.text count -ypixels**, which was
solved by adding a modifier **-update** allowing the user to be sure any
possible out of date line height information is recalculated.

It appears that aside of **.text count -ypixels** there are several other
cases where wrong results can be produced by text widget commands. These cases
are illustrated in several bug reports:

 * <http://core.tcl.tk/tk/tktview/1566949>   \(.text yview moveto\)

 * <http://core.tcl.tk/tk/tktview/e51941c>   \(.text yview\)

In all these cases, forcing the update by calling **.text count -update
-ypixels 1.0 end** before calling **.text yview**, or **.text yview
moveto** solves the issue presented in the ticket. This has however a
performance cost, of course, but the above tickets show that there are cases
where the programmer needs accurate results, be it at the cost of the time
needed to get the line heights calculations up-to-date.

This TIP is about providing the user/programmer with \(better\) ways to ensure
that line metrics are up-to-date.

Indeed it is not appropriate to let the concerned commands always force update
of the line metrics or wait for the end of the update calculation each time
they are called: performance impact would be way too large.

Also, it has to be noted that the **update** command is of no help here since
the line metrics calculation is done within the event loop in a chained
sequence of [after 1] handlers.

# Proposed Change

It is proposed to add two new commands to the text widget:

 > _pathName_ **sync** _?-command command?_

 > _pathName_ **pendingsync**

Also a new virtual event **<<WidgetViewSync>>** will be added.

Description:

_pathName_ **sync**

    Immediately brings the line metrics up-to-date by forcing computation of
    any outdated line pixel heights. Indeed, to maintain a responsive
    user-experience, the text widget caches line heights and re-calculates them
    in the background. The command returns immediately if there is no such
    outdated line heights, otherwise it returns only at the end of the
    computation. The command returns an empty string.

Implementation details: The command executes:

	    TkTextUpdateLineMetrics(textPtr, 1,
		      TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), -1);

_pathName_ **sync** **-command** _command_

    Schedule _command_ to be executed exactly once as soon as all line
    calculations are up-to-date. If there are no pending line metrics
    calculations, the scheduling is immediate. The command returns the empty
    string. **bgerror** is called on _command_ failure.

_pathName_ **pendingsync**

    Returns 1 if the line calculations are not up-to-date, 0 otherwise.

**<<WidgetViewSync>>**

    A widget can have a period of time during which the internal data model is
    not in sync with the view. The **sync** method forces the view to be in
    sync with the data. The **<<WidgetViewSync>>** virtual event fires when
    the internal data model starts to be out of sync with the widget view, and
    also when it becomes again in sync with the widget view. For the text
    widget, it fires when line metrics become outdated, and when they are
    up-to-date again. Note that this means it fires in particular when
    _pathName_ **sync** returns \(if there was pending updates\). The detail
    field \(%d substitution\) is either true \(when the widget is in sync\) or
    false \(when it is not\).

All **sync**, **pendingsync** and **<<WidgetViewSync>>** apply to
each text widget independently of its peers.

The names **sync**, **pendingsync** and **<<WidgetViewSync>>** are chosen
because of the potential for generalization to other widgets they have.

The text widget documentation will be augmented by a short section describing
the asynchronous update of line metrics, the reasons for that background
update, the drawbacks regarding possibly wrong results in **.text yview** or
**.text yview moveto**, and the way to solve these issues by using the new
commands. Example code as below will be provided in the documentation, since
this code will not be included in the library \(i.e. in _text.tcl_\)\).

The existing **-update** modifier switch of **.text count** will become
obsolete. It will be declared as deprecated in the text widget documentation
page while being still supported for backwards compatibility reasons.

Using the new commands, ways to ensure accurate results in **.text yview**,
or **.text yview moveto** are as in the following example:

	    ## Example 1:
	
	    # runtime, immediately complete line metrics at any cost (GUI unresponsive)
	    $w sync
	    $w yview moveto $fraction
	
	    ## Example 2:
	
	    # runtime, synchronously wait for up-to-date line metrics (GUI responsive)
	    $w sync -command [list $w yview moveto $fraction]
	
	    ## Example 3:
	
	    # init
	    set yud($w) 0
	    proc updateaction w {
	        set ::yud($w) 1
	        # any other update action here...

	    }
	
	    # runtime, synchronously wait for up-to-date line metrics (GUI responsive)
	    $w sync -command [list updateaction $w]
	    vwait yud($w)
	    $w yview moveto $fraction
	
	    ## Example 4:
	
	    # init
	    set todo($w) {}
	    proc updateaction w {
	        foreach cmd $::todo($w) {uplevel #0 $cmd}
	        set todo($w) {}

	    }
	
	    # runtime
	    lappend todo($w) [list $w yview moveto $fraction]
	    $w sync -command [list updateaction $w]
	
	    ## Example 5:
	
	    # init
	    set todo($w) {}
	
	    bind $w <<WidgetViewSync>> {
	        if {%d} {
	            foreach cmd $todo(%W) {eval $cmd}
	            set todo(%W) {}


	        }
	    }
	
	    # runtime
	    if {![$w pendingsync]} {
	        $w yview moveto $fraction
	    } else {
	        lappend todo($w) [list $w yview moveto $fraction]

	    }

# Rejected alternatives

 * Use a script-visible array variable such as **::tk::metricsDone\($w\)**
   instead of an event.

 * Don't change the source code and better document the **.text count -update
   -ypixels** trick. This is believed to be suboptimal considering that
   **.text count** indeed performs counting \(which has a cost\). This
   performance drawback could however be very much alleviated by counting
   between the two same indices: there would be no cost at all if this case
   was detected and was a short-cut in function TextWidgetObjCmd.

 * Instead of a new text widget sub-command, follow the lines of the existing
   example of **text count** and provide a new modifier switch **-update**
   to all sub-commands that may need it. The list of such sub-commands include
   **text yview**, **text yview moveto**, and **text yview scroll**.

 * **update idletasks** could force line metrics calculation update \(in
   addition to what this command already does\). This is certainly not the
   right thing to do since it is not very flexible. It would impact the
   performance of all text widgets whereas perhaps only one of them needs
   up-to-date line heights. Also, one could want to update idletasks \(in the
   current sense: idle tasks\) but not the line heights calculation, or the
   opposite. All in all, linking the event loop and the line heights
   calculation seems bad.

 * For each sub-command that needs up-to-date line heights to provide fully
   correct results, detect whether it is the case or not at the time they are
   called. If so, fine. If not, there could be two ways forward:

	 > 1. Force the update. This is not believed to be desirable, again for
   performance reasons. While there are cases where accurate results are
   mandatory \(see the tickets above\), most of the time one can live with
   approximate results. Any mismatch is temporary, since the asynchronous line
   height calculations will always catch up eventually. It is preferred to let
   the programmer decide if this update is needed or not.

	 > 2. Decide that the line height of not yet up-to-date lines is equal to some
   reasonable value, for instance the height of the first displayed line
   \(which is likely up-to-date\). For text widgets using only a single font,
   this would be OK since all line heights are then the same. However this
   would not solve all cases, for instance in **text yview** where the total
   number of pixels used by the text widget contents is needed, because this
   total pixel height calculation involves the total number of display \(not
   logical\) lines. Assessing the total number of display lines has a
   performance cost similar to proper line heights calculation, which voids
   that path.

 * It has been proposed that the detail field %d for the
   **<<WidgetViewSync>>** event contain the number of outdated lines, while
   this event would fire at each [after 1] partial update of the line metrics.
   This was rejected since no use case of this value could be exhibited, and it
   was believed that firing the event twice \(when out of sync and when again in
   sync\) was sufficient.

 * It has been proposed that the **text pendingsync** command return the
   number of currently outdated lines. This was rejected because no use case
   could be found, and because this TIP aims at generalization and it might be
   hard to define the equivalent of "number of lines to do" for other widgets.
   Anyway, using a boolean now \(noted as "1" and "0", rather than "true" and
   "false"\) leaves room to change our minds later with minimal incompatibility,
   since [if {[.t pendingsync]\}] will keep its semantics with an integer.

# Copyright

This document has been placed in the public domain.

Name change from tip/439.tip to tip/439.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161

TIP:            439
Title:          Semantic Versioning
Version:        $Revision: 1.8 $
Author:         Jan Nijtmans <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        08-Dec-2015
Post-History:   
Tcl-Version:    8.7


~ Abstract

The version schema used by Tcl and Tk has the form MAJOR.MINOR.PATCH, which is
the same schema used by "Semantic Versioning" [http://semver.org/]. For alpha
and beta releases the schema is MAJOR.MINORaPATCH resp MAJOR.MINORbPATCH,
which is not following the "Semantic Versioning" rules, but it's close.
This TIP proposes to start using "Semantic Versioning" for Tcl and Tk,
starting with Tcl/Tk 8.7, without making it mandatory for extensions and
Tcl modules: existing extensions and modules written for Tcl/Tk 8.6
or lower must cooperate unmodified with later 8.x versions as well.

~ Rationale

Semantic Versioning is an attempt to assign meaning to a software
version number. It has a very simple rule:

 * Given a version number MAJOR.MINOR.PATCH, increment the:

 > * MAJOR version when you make incompatible API changes,

 > * MINOR version when you add functionality in a backwards-compatible
     manner, and

 > * PATCH version when you make backwards-compatible bug fixes.

 * Additional labels for pre-release and build metadata are available as
   extensions to the MAJOR.MINOR.PATCH format.

As the version number of Tcl has the same form MAJOR.MINOR.PATCH, nothing
needs to be done here: future Tcl releases can be done following the Semantic
Versioning rules. Tcl/Tk alpha/beta releases have the form
MAJOR.MINOR[ab]PATCH, while Semantic Versioning dictates a form siminar to
MAJOR.MINOR.0(-alpha.|-beta.)PATCH: numeric and non-numeric parts must be
preceded by a dash, and separated by additional dots.

So, it is just a small step to adopt the Semantic Versioning idea. This TIP
proposes to do just that, and describes the implications it has on Tcl and
Tk. Alpha releases allow two forms of the version number, the semantic form
MAJOR.MINOR.0-alpha.PATCH or the legacy form MAJOR.MINORaPATCH.  For beta
releases this will be MAJOR.MINOR.0-beta.PATCH resp MAJOR.MINORbPATCH.  In Tcl
9.0, the legacy form might be removed and possibly enhanced to support all
semantic versioning forms, but this is outside the scope of this TIP.

Semantic Versioning will only be adopted for Tcl 8.7 and higher, so Tcl 8.5.x
and 8.6.x will not be affected. This means that it is possible to introduce a
minor new feature in 8.6.6, which would mandate a MINOR increment under the
Semantic Versioning rules. This TIP doesn't apply to Tcl extensions either,
each extension writer is free in whatever version strategy they choose.

~ Proposed Change

This TIP proposes to adopt Semantic Versioning for Tcl and Tk 8.7 and higher.
An exception will be made for Tcl extensions and Tcl modules, each extension
and module author will be free to choose whether or not to adopt Semantic
Versioning. Existing extensions/modules will continue to cooperate unchanged
with future Tcl and Tk 8.x releases.

One of the implications of this change is that there - most likely -
will be future Tcl 8.7/8.8/8.9/8.10 releases. Since all Tcl minor
releases can be installed next to each other, this would be a
maintenance burden since all of those versions need to be maintained
during serveral years in the future. Solution: drop the minor number
from all Tcl and Tk filenames and installation directories. This way,
Tcl 8.7 and 8.8 cannot be installed next to each other any more,
they share the same installation directory if the installation
''prefix'' is the same. Does that matter? No, because you always
can choose a different prefix. Actually, there is no need for 
Tcl 8.7 any more when Tcl 8.8 is available, as they are 100%
upwards compatible: the Semantic Versioning rules assure this.
As soon as Tcl 8.8 is released, no new Tcl 8.7 releases will
come out any more. Any incompatible change will have to wait
for Tcl 9 (or 10 or 11...). Tcl 8.5 and 8.6 releases will
continue to be supported as long as there is sufficient interest,
this TIP doesn't change anything on that.

An important implication of dropping the minor number in
the Tcl installation script directory is that it would
become "<prefix>/lib/tcl8" in stead of "<prefix>/lib/tcl8.7".
This is a problem, because this is the same directory used for
Tcl Modules, which still need to support existing extensions.
This TIP therefore proposes to change TCL_LIBRARY to
'<prefix>/share/tcl8', that won't conflict with anything used thus far.

Since Tcl now starts using TCL_LIBRARY being a subdirectory of
"<prefix>/share", it seems logical to start using this directory
for man-pages as well. Therefore, it is proposed to upgrade
"autoconf" to the latest version (2.69), which brings the
man-page change without further hurdle.

All together, the proposed directory structure (UNIX)

 > ''<prefix>/bin/tclsh8'' '''Tcl executable'''

 > ''<prefix>/lib/libtcl8.so'' '''Tcl shared library'''

 > ''<prefix>/lib/tcl8'' '''Tcl Modules'''

 > ''<prefix>/lib/tcl8/8.6''

 > ''<prefix>/lib/tcl8/8.7''

 > ''<prefix>/lib/tcl8.6'' '''TCL_LIBRARY for Tcl 8.6'''

 > ''<prefix>/share/tcl8'' '''TCL_LIBRARY for Tcl 8.x (x>=7)'''

 > ''<prefix>/share/man'' '''Tcl manual pages'''

Regarding backporting, any change done in Tcl 8.7 could in principle
be backported to Tcl 8.6 and further to 8.5, if desired. This TIP
doesn't put a restriction to that, as Semantic Versioning only starts
with version 8.7. Still it would be desirable for the TCT to describe a
procedure for that, this is outside the scope of this TIP.

Semantic Versioning requires that any API which is removed in Tcl 9.0 must be
made deprecated in Tcl 8.7 (or 8.8). A new macro TCL_DEPRECATED will be
introduced for that in the *Decls.h files. If Tcl 8.7 is compiled with the
flag TCL_NO_DEPRECATED, all deprecated API is removed, by making those entries
MODULE_SCOPE, and putting 0 in the corresponding stub entries.  This can be
used by extensions to see whether they are compatible with the next major Tcl
release or not.

The following API's are declared deprecated in Tcl 8.7 and will be
removed in Tcl 9.0. They are already removed in the "novem" branch:

 * Tcl_Backslash

 * Tcl_EvalFile

 * Tcl_GetDefaultEncodingDir

 * Tcl_SetDefaultEncodingDir

 * Tcl_EvalTokens

 * Tcl_CreateMathFunc

 * Tcl_GetMathFuncInfo

 * Tcl_ListMathFuncs

An implementation of this TIP can be found at [http://core.tcl.tk/tcl]; branch
"semver".

~ Rejected Alternatives

TODO

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|







|






|

|


|








|
















|















|





|








|


|


|


|

|

|

|

|

|

|

|

|








|
|
|
|






|

|

|

|

|

|

|

|

|


|



|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161

# TIP 439: Semantic Versioning

	Author:         Jan Nijtmans <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        08-Dec-2015
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

The version schema used by Tcl and Tk has the form MAJOR.MINOR.PATCH, which is
the same schema used by "Semantic Versioning" <http://semver.org/> . For alpha
and beta releases the schema is MAJOR.MINORaPATCH resp MAJOR.MINORbPATCH,
which is not following the "Semantic Versioning" rules, but it's close.
This TIP proposes to start using "Semantic Versioning" for Tcl and Tk,
starting with Tcl/Tk 8.7, without making it mandatory for extensions and
Tcl modules: existing extensions and modules written for Tcl/Tk 8.6
or lower must cooperate unmodified with later 8.x versions as well.

# Rationale

Semantic Versioning is an attempt to assign meaning to a software
version number. It has a very simple rule:

 * Given a version number MAJOR.MINOR.PATCH, increment the:

	 > \* MAJOR version when you make incompatible API changes,

	 > \* MINOR version when you add functionality in a backwards-compatible
     manner, and

	 > \* PATCH version when you make backwards-compatible bug fixes.

 * Additional labels for pre-release and build metadata are available as
   extensions to the MAJOR.MINOR.PATCH format.

As the version number of Tcl has the same form MAJOR.MINOR.PATCH, nothing
needs to be done here: future Tcl releases can be done following the Semantic
Versioning rules. Tcl/Tk alpha/beta releases have the form
MAJOR.MINOR[ab]PATCH, while Semantic Versioning dictates a form siminar to
MAJOR.MINOR.0\(-alpha.\|-beta.\)PATCH: numeric and non-numeric parts must be
preceded by a dash, and separated by additional dots.

So, it is just a small step to adopt the Semantic Versioning idea. This TIP
proposes to do just that, and describes the implications it has on Tcl and
Tk. Alpha releases allow two forms of the version number, the semantic form
MAJOR.MINOR.0-alpha.PATCH or the legacy form MAJOR.MINORaPATCH.  For beta
releases this will be MAJOR.MINOR.0-beta.PATCH resp MAJOR.MINORbPATCH.  In Tcl
9.0, the legacy form might be removed and possibly enhanced to support all
semantic versioning forms, but this is outside the scope of this TIP.

Semantic Versioning will only be adopted for Tcl 8.7 and higher, so Tcl 8.5.x
and 8.6.x will not be affected. This means that it is possible to introduce a
minor new feature in 8.6.6, which would mandate a MINOR increment under the
Semantic Versioning rules. This TIP doesn't apply to Tcl extensions either,
each extension writer is free in whatever version strategy they choose.

# Proposed Change

This TIP proposes to adopt Semantic Versioning for Tcl and Tk 8.7 and higher.
An exception will be made for Tcl extensions and Tcl modules, each extension
and module author will be free to choose whether or not to adopt Semantic
Versioning. Existing extensions/modules will continue to cooperate unchanged
with future Tcl and Tk 8.x releases.

One of the implications of this change is that there - most likely -
will be future Tcl 8.7/8.8/8.9/8.10 releases. Since all Tcl minor
releases can be installed next to each other, this would be a
maintenance burden since all of those versions need to be maintained
during serveral years in the future. Solution: drop the minor number
from all Tcl and Tk filenames and installation directories. This way,
Tcl 8.7 and 8.8 cannot be installed next to each other any more,
they share the same installation directory if the installation
_prefix_ is the same. Does that matter? No, because you always
can choose a different prefix. Actually, there is no need for 
Tcl 8.7 any more when Tcl 8.8 is available, as they are 100%
upwards compatible: the Semantic Versioning rules assure this.
As soon as Tcl 8.8 is released, no new Tcl 8.7 releases will
come out any more. Any incompatible change will have to wait
for Tcl 9 \(or 10 or 11...\). Tcl 8.5 and 8.6 releases will
continue to be supported as long as there is sufficient interest,
this TIP doesn't change anything on that.

An important implication of dropping the minor number in
the Tcl installation script directory is that it would
become "<prefix>/lib/tcl8" in stead of "<prefix>/lib/tcl8.7".
This is a problem, because this is the same directory used for
Tcl Modules, which still need to support existing extensions.
This TIP therefore proposes to change TCL\_LIBRARY to
'<prefix>/share/tcl8', that won't conflict with anything used thus far.

Since Tcl now starts using TCL\_LIBRARY being a subdirectory of
"<prefix>/share", it seems logical to start using this directory
for man-pages as well. Therefore, it is proposed to upgrade
"autoconf" to the latest version \(2.69\), which brings the
man-page change without further hurdle.

All together, the proposed directory structure \(UNIX\)

 > _<prefix>/bin/tclsh8_ **Tcl executable**

 > _<prefix>/lib/libtcl8.so_ **Tcl shared library**

 > _<prefix>/lib/tcl8_ **Tcl Modules**

 > _<prefix>/lib/tcl8/8.6_

 > _<prefix>/lib/tcl8/8.7_

 > _<prefix>/lib/tcl8.6_ **TCL\_LIBRARY for Tcl 8.6**

 > _<prefix>/share/tcl8_ **TCL\_LIBRARY for Tcl 8.x \(x>=7\)**

 > _<prefix>/share/man_ **Tcl manual pages**

Regarding backporting, any change done in Tcl 8.7 could in principle
be backported to Tcl 8.6 and further to 8.5, if desired. This TIP
doesn't put a restriction to that, as Semantic Versioning only starts
with version 8.7. Still it would be desirable for the TCT to describe a
procedure for that, this is outside the scope of this TIP.

Semantic Versioning requires that any API which is removed in Tcl 9.0 must be
made deprecated in Tcl 8.7 \(or 8.8\). A new macro TCL\_DEPRECATED will be
introduced for that in the \*Decls.h files. If Tcl 8.7 is compiled with the
flag TCL\_NO\_DEPRECATED, all deprecated API is removed, by making those entries
MODULE\_SCOPE, and putting 0 in the corresponding stub entries.  This can be
used by extensions to see whether they are compatible with the next major Tcl
release or not.

The following API's are declared deprecated in Tcl 8.7 and will be
removed in Tcl 9.0. They are already removed in the "novem" branch:

 * Tcl\_Backslash

 * Tcl\_EvalFile

 * Tcl\_GetDefaultEncodingDir

 * Tcl\_SetDefaultEncodingDir

 * Tcl\_EvalTokens

 * Tcl\_CreateMathFunc

 * Tcl\_GetMathFuncInfo

 * Tcl\_ListMathFuncs

An implementation of this TIP can be found at <http://core.tcl.tk/tcl> ; branch
"semver".

# Rejected Alternatives

TODO

# Copyright

This document has been placed in the public domain.

Name change from tip/44.tip to tip/44.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
136
137
138
139
140
141
142
143
144
145
146
147
148

149
150
151

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

TIP:            44
Title:          Move Tk's Private Commands and Variables into ::tk Namespace
Version:        $Revision: 1.9 $
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        16-Jul-2001
Post-History:   
Tcl-Version:    8.4


~ Abstract

This TIP proposes that Tk's private commands and variables be moved
into the namespace ''::tk'' or its descendent namespace(s).

~ Background

Tk defines several commands and variables in the global namespace
that are not intended for public use.  Some of the commands are
used for widget bindings.  Some of the variables are used to maintain
widget state information.  The definition of these "private" commands
and variables in the global namespace is a legacy held over from Tk 4
and the pre-8 versions of Tcl in which there was only one namespace.

Fortunately, the coders of Tk have maintained good discipline in
naming these commands and variables intended for Tk's internal
use only.  The commands and variables matching the glob pattern
''::tk[[A-Z]]*'' are private.  Consider this interactive tktest session
with Tk 8.3.3:

| $ cd tk/unix
| $ make runtest
| ...
| % # Put Tk through its paces to define all commands and variables
| % source ./../tests/all.tcl
| ...
| % llength [info commands {tk[A-Z]*}]
| 183
| % llength [info vars {tk[A-Z]*}]
| 5


So, on Unix, there are 183 private commands and 5 private variables
polluting the global namespace.  The number and list of commands
and variables varies a bit from platform to platform due to
differences in widget bindings.

More recently, private commands in Tk have been added in the ''::tk''
namespace; two examples are ''tk::PlaceWindow'' and ''tk::SetFocusGrab''.
Likewise the private variable ''tk::FocusGrab'' has also been added
in the ''::tk'' namespace.

There are three reasons why it is better for Tk's private commands
and variables to be moved out of the global namespace and into the
''::tk'' namespace.

 1. The large number of commands and variable makes it more difficult
    to use interactive ''[[info commands]]'' and ''[[info vars]]'' or
    ''[[info globals]]'' introspection to learn about what application
    specific commands and variables are defined.

 2. Placing private commands and variables in the global namespace
    gives them a higher profile, and increases the likelihood that
    they will be used publicly, against the intent of Tk's interface.

 3. By making more use of its own namespace for keeping track of its
    own internals, Tk becomes a better example for authors of other
    packages to copy.

~ Proposal

All commands and variables created by Tk and matching the glob pattern
''::tk[[A-Z]]*'' shall be renamed to a name contained within the
''::tk'' namespace or one of the descendent namespaces of ''::tk''.

The global variable ''::histNum'' created by ''tk/library/console.tcl''
shall also be renamed to ''::tk::HistNum''.

All commands and variables created by the proposal will be given names
that begin with an uppercase character (''[[A-Z]]'') to indicate their
internal status according to the conventions of the Tcl Style Guide
[http://purl.org/tcl/home/doc/styleGuide.pdf].

~ Compatibility and Migration

This proposal only deals with the internals of Tk, so technically there
are no compatibility issues, because Tk users should not be depending
on these private commands and variables.

That said, because these commands and variables have had a high
profile in the global namespace, it seems likely that some users
have written code that depends on them.  To aid such users in a
migration away from that dependence, it is also proposed that
Tk provide two additional unsupported commands:

| ::tk::unsupported::ExposePrivateCommand commandName

and

| ::tk::unsupported::ExposePrivateVariable variableName

The command ''[[::tk::unsupported::ExposePrivateCommand commandName]]''
restores the existence of the Tk private command ''commandName'' in
the global namespace as it was before adoption of this proposal.
The command ''[[::tk::unsupported::ExposePrivateVariable variableName]]''
restores the existence of the Tk private variable ''variableName'' in
the global namespace as it was before adoption of this proposal.
For example, a Tk user who had written code that made use of the Tk
private command ''tkCancelRepeat'' can add the following code to
continue working with Tk after acceptance of this proposal:

| if {![llength [info commands tkCancelRepeat]]} {
|     tk::unsupported::ExposePrivateCommand tkCancelRepeat
| }


These migration commands are in the namespace ''tk::unsupported'',
a new namespace to be used for unsupported commands in Tk.  This
namespace may and should be used for any other unsupported commands
to be created in Tk.  Their implementation is in the new file
''tk/library/unsupported.tcl''.

~ Reference Implementation

This proposal has already been implemented and committed to Tk's
CVS repository on the branch tagged ''dgp-privates-into-namespace''.
That branch is up to date with Tk's HEAD branch as of July 16, 2001.

To make an anonymous checkout of the reference implementation into
a directory named ''tkprivate'', run the following CVS commands:

| $ cvs -d :pserver:[email protected]:/cvsroot/tktoolkit \
|   login
| (Logging in to [email protected])
| CVS password: <Enter>
| $ cvs -z3 -d :pserver:[email protected]:/cvsroot/tktoolkit \
|   co -r dgp-privates-into-namespace -d tkprivate tk

The reference implementation has the same results on the Tk
test suite as the HEAD revision.

In the tktest of the reference implementation:

| $ make runtest
| ...
| % source ./../tests/all.tcl
| ...
| % llength [info commands {tk[A-Z]*}]
| 0

| % llength [info vars {tk[A-Z]*}]
| 0


~ See Also

Feature Request 220936
[http://sf.net/tracker/?func=detail&aid=220936&group_id=12997&atid=362997]

~ Related Ideas / Future Work

The ideas in this section are ''not'' part of this proposal.  They are
related ideas mentioned here as explicitly outside the scope of this
proposal so they will not be counter-proposed.

 * ''Shouldn't Tk's public commands and variables be moved to ::tk too?''

 > Well, yes, I think they should, but that change clearly involves 
   sorting out more difficult compatibility/migration issues.  The
   current proposal is limited to the less controversial topic of
   Tk's private commands and variables.  We'll tackle the rest later.

 * ''Shouldn't Tk make use of [[namespace code]] in its bindings?''

 * ''Wouldn't it make Tk better organized if commands like
   [[tk::IconList_Add]] were further renamed [[tk::IconList::Add]]?''

 > Perhaps so.  There may be many ways in which Tk can and should 
   make better or more idiomatic use of namespaces.  That's not the
   point of this proposal, though.  The point is to get these commands
   and variables out of the global namespace.  Once that is accomplished,
   then these other matters are unquestionably internal and can proceed
   at the discretion of the maintainers without further TIP review.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|

|











|


|
|
|
|
|
|
|
|
|
<
>






|
|
|
|



|


|
|










|


|
|

|
|


|

|

|











|



|

|
|

|
|


|


|
|
<
|
>
|



|

|


|



|

|
|
|
|
|
|






|
|
|
|
|
<
>
|
<
|
>
|


|

|

|



|

|




|

|
|

|






|


>

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
136
137
138
139
140
141
142
143
144
145
146

147
148

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

# TIP 44: Move Tk's Private Commands and Variables into ::tk Namespace

	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        16-Jul-2001
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

This TIP proposes that Tk's private commands and variables be moved
into the namespace _::tk_ or its descendent namespace\(s\).

# Background

Tk defines several commands and variables in the global namespace
that are not intended for public use.  Some of the commands are
used for widget bindings.  Some of the variables are used to maintain
widget state information.  The definition of these "private" commands
and variables in the global namespace is a legacy held over from Tk 4
and the pre-8 versions of Tcl in which there was only one namespace.

Fortunately, the coders of Tk have maintained good discipline in
naming these commands and variables intended for Tk's internal
use only.  The commands and variables matching the glob pattern
_::tk[A-Z]\*_ are private.  Consider this interactive tktest session
with Tk 8.3.3:

	 $ cd tk/unix
	 $ make runtest
	 ...
	 % # Put Tk through its paces to define all commands and variables
	 % source ./../tests/all.tcl
	 ...
	 % llength [info commands {tk[A-Z]*}]
	 183
	 % llength [info vars {tk[A-Z]*}]

	 5

So, on Unix, there are 183 private commands and 5 private variables
polluting the global namespace.  The number and list of commands
and variables varies a bit from platform to platform due to
differences in widget bindings.

More recently, private commands in Tk have been added in the _::tk_
namespace; two examples are _tk::PlaceWindow_ and _tk::SetFocusGrab_.
Likewise the private variable _tk::FocusGrab_ has also been added
in the _::tk_ namespace.

There are three reasons why it is better for Tk's private commands
and variables to be moved out of the global namespace and into the
_::tk_ namespace.

 1. The large number of commands and variable makes it more difficult
    to use interactive _[info commands]_ and _[info vars]_ or
    _[info globals]_ introspection to learn about what application
    specific commands and variables are defined.

 2. Placing private commands and variables in the global namespace
    gives them a higher profile, and increases the likelihood that
    they will be used publicly, against the intent of Tk's interface.

 3. By making more use of its own namespace for keeping track of its
    own internals, Tk becomes a better example for authors of other
    packages to copy.

# Proposal

All commands and variables created by Tk and matching the glob pattern
_::tk[A-Z]\*_ shall be renamed to a name contained within the
_::tk_ namespace or one of the descendent namespaces of _::tk_.

The global variable _::histNum_ created by _tk/library/console.tcl_
shall also be renamed to _::tk::HistNum_.

All commands and variables created by the proposal will be given names
that begin with an uppercase character \(_[A-Z]_\) to indicate their
internal status according to the conventions of the Tcl Style Guide
<http://purl.org/tcl/home/doc/styleGuide.pdf> .

# Compatibility and Migration

This proposal only deals with the internals of Tk, so technically there
are no compatibility issues, because Tk users should not be depending
on these private commands and variables.

That said, because these commands and variables have had a high
profile in the global namespace, it seems likely that some users
have written code that depends on them.  To aid such users in a
migration away from that dependence, it is also proposed that
Tk provide two additional unsupported commands:

	 ::tk::unsupported::ExposePrivateCommand commandName

and

	 ::tk::unsupported::ExposePrivateVariable variableName

The command _[::tk::unsupported::ExposePrivateCommand commandName]_
restores the existence of the Tk private command _commandName_ in
the global namespace as it was before adoption of this proposal.
The command _[::tk::unsupported::ExposePrivateVariable variableName]_
restores the existence of the Tk private variable _variableName_ in
the global namespace as it was before adoption of this proposal.
For example, a Tk user who had written code that made use of the Tk
private command _tkCancelRepeat_ can add the following code to
continue working with Tk after acceptance of this proposal:

	 if {![llength [info commands tkCancelRepeat]]} {
	     tk::unsupported::ExposePrivateCommand tkCancelRepeat

	 }

These migration commands are in the namespace _tk::unsupported_,
a new namespace to be used for unsupported commands in Tk.  This
namespace may and should be used for any other unsupported commands
to be created in Tk.  Their implementation is in the new file
_tk/library/unsupported.tcl_.

# Reference Implementation

This proposal has already been implemented and committed to Tk's
CVS repository on the branch tagged _dgp-privates-into-namespace_.
That branch is up to date with Tk's HEAD branch as of July 16, 2001.

To make an anonymous checkout of the reference implementation into
a directory named _tkprivate_, run the following CVS commands:

	 $ cvs -d :pserver:[email protected]:/cvsroot/tktoolkit \
	   login
	 (Logging in to [email protected])
	 CVS password: <Enter>
	 $ cvs -z3 -d :pserver:[email protected]:/cvsroot/tktoolkit \
	   co -r dgp-privates-into-namespace -d tkprivate tk

The reference implementation has the same results on the Tk
test suite as the HEAD revision.

In the tktest of the reference implementation:

	 $ make runtest
	 ...
	 % source ./../tests/all.tcl
	 ...
	 % llength [info commands {tk[A-Z]*}]

	 0
	 % llength [info vars {tk[A-Z]*}]

	 0

# See Also

Feature Request 220936
<http://sf.net/tracker/?func=detail&aid=220936&group_id=12997&atid=362997> 

# Related Ideas / Future Work

The ideas in this section are _not_ part of this proposal.  They are
related ideas mentioned here as explicitly outside the scope of this
proposal so they will not be counter-proposed.

 * _Shouldn't Tk's public commands and variables be moved to ::tk too?_

	 > Well, yes, I think they should, but that change clearly involves 
   sorting out more difficult compatibility/migration issues.  The
   current proposal is limited to the less controversial topic of
   Tk's private commands and variables.  We'll tackle the rest later.

 * _Shouldn't Tk make use of [namespace code] in its bindings?_

 * _Wouldn't it make Tk better organized if commands like
   [tk::IconList_Add] were further renamed [tk::IconList::Add]?_

	 > Perhaps so.  There may be many ways in which Tk can and should 
   make better or more idiomatic use of namespaces.  That's not the
   point of this proposal, though.  The point is to get these commands
   and variables out of the global namespace.  Once that is accomplished,
   then these other matters are unquestionably internal and can proceed
   at the discretion of the maintainers without further TIP review.

# Copyright

This document has been placed in the public domain.

Name change from tip/440.tip to tip/440.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

TIP:            440
Title:          Add engine to tcl_platform Array
Version:        $Revision: 1.13 $
Author:         Joe Mistachkin <[email protected]>
Author:         Jan Nijtmans <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        14-Jan-2016
Post-History:   
Keywords:       language implementation,platform
Tcl-Version:    8.5


~ Abstract

This TIP proposes a mechanism for determining the implementation of the Tcl
language currently in use.

~ Rationale

There is more than one implementation of the Tcl language (see
[http://wiki.tcl.tk/13992]). These implementations differ greatly in their
degree of compatibility and completeness. At the script level, there is
currently no standard way to determine which implementation of the Tcl
language is being used.

~ Specification

The '''engine''' element will be added to the '''tcl_platform''' array. Its
value will be set to '''"Tcl"'''.

~ Reference Implementation

A reference implementation of this TIP is available
[https://core.tcl.tk/tcl/timeline?r=tclPlatformEngine].

The TH1, Jim, Picol, JTcl, and Eagle implementations of the Tcl language already
implement this feature, each using the name of the project as the value of
the '''tcl_platform(engine)''' element.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|




|

|
|




|

|
|

|


|



|

|


>

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

# TIP 440: Add engine to tcl_platform Array

	Author:         Joe Mistachkin <[email protected]>
	Author:         Jan Nijtmans <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        14-Jan-2016
	Post-History:   
	Keywords:       language implementation,platform
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes a mechanism for determining the implementation of the Tcl
language currently in use.

# Rationale

There is more than one implementation of the Tcl language \(see
<http://wiki.tcl.tk/13992> \). These implementations differ greatly in their
degree of compatibility and completeness. At the script level, there is
currently no standard way to determine which implementation of the Tcl
language is being used.

# Specification

The **engine** element will be added to the **tcl\_platform** array. Its
value will be set to **"Tcl"**.

# Reference Implementation

A reference implementation of this TIP is available
<https://core.tcl.tk/tcl/timeline?r=tclPlatformEngine> .

The TH1, Jim, Picol, JTcl, and Eagle implementations of the Tcl language already
implement this feature, each using the name of the project as the value of
the **tcl\_platform\(engine\)** element.

# Copyright

This document has been placed in the public domain.

Name change from tip/441.tip to tip/441.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

TIP:            441
Title:          Add -justify Configuration Option to the listbox Widget
Version:        $Revision: 1.3 $
Author:         Fran�ois Vogel <[email protected]>
Author:         Fran�ois Vogel <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        18-Jan-2016
Post-History:   
Keywords:       Tk,listbox
Tcl-Version:    8.6.5


~ Abstract

Despite the '''listbox''' widget already having numerous configuration
options, some users need more refinements and have requested the possibility
to control the justification of the text displayed in the items of the
listbox. This TIP proposes to add this option.

~ Rationale

Currently the '''listbox''' widget always aligns its items leftwards. Some
users miss a configuration options allowing to justify items in the
'''listbox''' widget. These RFE include:

  * RFE 454303, [https://core.tcl.tk/tk/tktview/454303]

  * RFE 3f456a5bb9, [https://core.tcl.tk/tk/tktview/3f456a5bb9]

~ Proposed Change

It is proposed to add the '''-justify''' configuration option to the Tk
'''listbox''' widget.

Possible values are as already documented in the '''options''' manual page
(i.e., '''left''', '''center''', or '''right'''), and translate internally
into standard ''Tk_Justify'' values, i.e., TK_JUSTIFY_LEFT, TK_JUSTIFY_CENTER,
and TK_JUSTIFY_RIGHT, respectively.

Default value is '''left''' on all platforms, for backwards compatibility reasons.

~ Reference Implementation

A reference implementation is available in branch tip-441 of the fossil
repository.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|




|

|

|

|

|

|

|
|

|
|
|
|

|

|




|


>

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

# TIP 441: Add -justify Configuration Option to the listbox Widget

	Author:         François Vogel <[email protected]>
	Author:         François Vogel <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        18-Jan-2016
	Post-History:   
	Keywords:       Tk,listbox
	Tcl-Version:    8.6.5
-----

# Abstract

Despite the **listbox** widget already having numerous configuration
options, some users need more refinements and have requested the possibility
to control the justification of the text displayed in the items of the
listbox. This TIP proposes to add this option.

# Rationale

Currently the **listbox** widget always aligns its items leftwards. Some
users miss a configuration options allowing to justify items in the
**listbox** widget. These RFE include:

  * RFE 454303, <https://core.tcl.tk/tk/tktview/454303> 

  * RFE 3f456a5bb9, <https://core.tcl.tk/tk/tktview/3f456a5bb9> 

# Proposed Change

It is proposed to add the **-justify** configuration option to the Tk
**listbox** widget.

Possible values are as already documented in the **options** manual page
\(i.e., **left**, **center**, or **right**\), and translate internally
into standard _Tk\_Justify_ values, i.e., TK\_JUSTIFY\_LEFT, TK\_JUSTIFY\_CENTER,
and TK\_JUSTIFY\_RIGHT, respectively.

Default value is **left** on all platforms, for backwards compatibility reasons.

# Reference Implementation

A reference implementation is available in branch tip-441 of the fossil
repository.

# Copyright

This document has been placed in the public domain.

Name change from tip/442.tip to tip/442.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

TIP:            442
Title:          Display text in progressbars
Version:        $Revision: 1.11 $
Author:         Ren� Zaumseil <[email protected]>
Author:         Kevin B Kenny <[email protected]>
Author:         Andreas Leitgeb <[email protected]>
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        17-Feb-2016
Post-History:   
Keywords:       Tk
Tcl-Version:    8.7


~ Abstract

Horizontal progress bars should support the ability to display text inside the progress bar.
Buttons should allow justification of multiline texts.

~ Rationale

It is often useful to be able to display text directly on top of a progress
bar. This text might be a description of the progress percentage, what is
currently being done, or even just a label giving the overall task that is
progressing.

The '''ttk::progressbar''' command can easily enhanced to provide this
support, and there is no interference with existing code as this
functionality
can be done by just introducing new options.  The options required are from
the list of usual Tk well-known option names.

Also the '''ttk::button''' command can easily be enhanced to provide justification of multiline text.

~ Specification

Text will be displayed only on horizontal '''ttk::progressbar'''.
To control the text appearance the following new options will be added:

 -text: The string to display.

 -font: The font used to render the text.

 -foreground: The color of the text.

 -anchor: The anchoring of the text.

 -justify: The justification of the string.

 -wraplength: The length at which the string will be automatically wrapped.

To justify multiline text in '''ttk::button''' a new option will be added:

 -justify: The justification of the string.

~ Notes for future improvements

The underlying Tk text rendering engine supports rotated text, which would
make support on vertical progress bars possible. But control of the rotation
angle might be required (according to whether the text is rotated left or
right, or stays unrotated).

The most contrasting color of the text will depend where on the progress bar
it is placed. This is not an effect that is simply reproduced with the Tk
script level, but is easy to apply during rendering.

~ Implementation

A patch implementing these changes and updating the documentation is available
in the fossil repository in the tip-442 branch.

Implementation is heavily borrowed from the '''ttk::label''' widget featuring
these same options. The names, meanings, and default values of the options are
the same as for '''ttk::label'''. The rendering and processing is the same as
for this latter widget.

~ Example of use

|    package require Tk
|    proc moveit {} {
|      for {set i 0} {$i < 100} {incr i} {
|        .p step ; update ; after 100
|      }
|    }


|    pack [ttk::progressbar .p -value 0 -maximum 50 -orient horizontal -length 500]
|    .p configure -anchor c -foreground blue -justify right \
|            -text "-anchor c -foreground blue -justify right -wraplength 100" \
|            -wraplength 100
|    moveit
|    .p configure -anchor e -font {Arial 10 bold} -foreground green -justify center \
|            -text "-anchor e -font {Arial 10 bold} -foreground green -justify center -wraplength 250" \
|            -wraplength 250
|    moveit
|    .p configure -text "-anchor w -foreground red -justify left -wraplength 50" \
|            -anchor w -foreground red -justify left -wraplength 50
|    moveit
|    .p configure -orient vertical -text "Cannot be seen"
|    moveit

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
>

|




|






|





|

|

|














|



|



|
|





|




|

|


|

|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|


>

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

# TIP 442: Display text in progressbars

	Author:         René Zaumseil <[email protected]>
	Author:         Kevin B Kenny <[email protected]>
	Author:         Andreas Leitgeb <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        17-Feb-2016
	Post-History:   
	Keywords:       Tk
	Tcl-Version:    8.7
-----

# Abstract

Horizontal progress bars should support the ability to display text inside the progress bar.
Buttons should allow justification of multiline texts.

# Rationale

It is often useful to be able to display text directly on top of a progress
bar. This text might be a description of the progress percentage, what is
currently being done, or even just a label giving the overall task that is
progressing.

The **ttk::progressbar** command can easily enhanced to provide this
support, and there is no interference with existing code as this
functionality
can be done by just introducing new options.  The options required are from
the list of usual Tk well-known option names.

Also the **ttk::button** command can easily be enhanced to provide justification of multiline text.

# Specification

Text will be displayed only on horizontal **ttk::progressbar**.
To control the text appearance the following new options will be added:

 -text: The string to display.

 -font: The font used to render the text.

 -foreground: The color of the text.

 -anchor: The anchoring of the text.

 -justify: The justification of the string.

 -wraplength: The length at which the string will be automatically wrapped.

To justify multiline text in **ttk::button** a new option will be added:

 -justify: The justification of the string.

# Notes for future improvements

The underlying Tk text rendering engine supports rotated text, which would
make support on vertical progress bars possible. But control of the rotation
angle might be required \(according to whether the text is rotated left or
right, or stays unrotated\).

The most contrasting color of the text will depend where on the progress bar
it is placed. This is not an effect that is simply reproduced with the Tk
script level, but is easy to apply during rendering.

# Implementation

A patch implementing these changes and updating the documentation is available
in the fossil repository in the tip-442 branch.

Implementation is heavily borrowed from the **ttk::label** widget featuring
these same options. The names, meanings, and default values of the options are
the same as for **ttk::label**. The rendering and processing is the same as
for this latter widget.

# Example of use

	    package require Tk
	    proc moveit {} {
	      for {set i 0} {$i < 100} {incr i} {
	        .p step ; update ; after 100


	      }
	    }
	    pack [ttk::progressbar .p -value 0 -maximum 50 -orient horizontal -length 500]
	    .p configure -anchor c -foreground blue -justify right \
	            -text "-anchor c -foreground blue -justify right -wraplength 100" \
	            -wraplength 100
	    moveit
	    .p configure -anchor e -font {Arial 10 bold} -foreground green -justify center \
	            -text "-anchor e -font {Arial 10 bold} -foreground green -justify center -wraplength 250" \
	            -wraplength 250
	    moveit
	    .p configure -text "-anchor w -foreground red -justify left -wraplength 50" \
	            -anchor w -foreground red -justify left -wraplength 50
	    moveit
	    .p configure -orient vertical -text "Cannot be seen"
	    moveit

# Copyright

This document has been placed in the public domain.

Name change from tip/443.tip to tip/443.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

TIP:            443
Title:          More Tag Configuration Options for the Text Widget
Version:        $Revision: 1.9 $
Author:         Fran�ois Vogel <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        09-Feb-2016
Post-History:   
Keywords:       Tk
Tcl-Version:    8.6.6


~ Abstract

Despite the '''text''' widget already has numerous configuration options, some
users need more refinements and have requested new tag configuration options.
This TIP proposes to add these options, when deemed relevant.

~ Rationale

Several users have reported they miss different tag configuration options in
the '''text''' widget, stating they cannot achieve the rendering they target.
Such RFE include:

 * RFE 1759972 [https://core.tcl.tk/tk/tktview/1759972], with Patch
   3469780 [https://core.tcl.tk/tk/tktview/3469780]

 * RFE 220889 [https://core.tcl.tk/tk/tktview/220889]

 * RFE 1754048 [https://core.tcl.tk/tk/tktview/1754048]

~ Proposed Change

It is proposed to add the following tag configuration options to the Tk
'''text''' widget:

'''-selectbackground''' ''color'':

 > Specifies the background color to use
   when displaying selected items. It may have any of the forms accepted by
   '''Tk_GetColor'''. If ''color'' has not been specified, or if it is
   specified as an empty string, then the color specified by the
   '''-background''' tag option is used.

 > Note regarding the particular case of the "sel"
 tag: Currently, the "sel" tag '''-background''' tag option is mirrored with
 the '''-selectbackground''' text widget option. This makes sense. It does not
 make real sense to have '''-selectbackground''' applied to the "sel" tag (it
 is more intuitive to use '''-background''' for the "sel" tag). However, if the
 "sel" tag receives non-empty '''-selectbackground''', then this tag option
 prevails on the '''-background''' tag option for mirroring, i.e. the
 '''-selectbackground''' tag option is mirrored with the
 '''-selectbackground''' widget option.

'''-selectforeground''' ''color'':

 > Specifies the foreground color to use
   when displaying selected items. It may have any of the forms accepted by
   '''Tk_GetColor'''. If ''color'' has not been specified, or if it is
   specified as an empty string, then the color specified by the
   '''-foreground''' tag option is used.

 > Note regarding the particular case of the "sel"
 tag: same principle as above for '''-selectbackground'''.

'''-underlinefg''' ''color'':

 > Specifies the color to use when displaying
   the underline. It may have any of the forms accepted by '''Tk_GetColor'''.
   If ''color'' has not been specified, or if it is specified as an empty
   string, then the color specified by the '''-foreground''' tag option is
   used (if there is one, otherwise the the color specified by the
   '''-foreground''' widget option is used).

'''-overstrikefg''' ''color'':

 > Specifies the color to use when
   displaying the overstrike. It may have any of the forms accepted by
   '''Tk_GetColor'''. If ''color'' has not been specified, or if it is
   specified as an empty string, then the color specified by the
   '''-foreground''' tag option is used (if there is one, otherwise the
   color specified by the '''-foreground''' widget option is used).

'''-lmargincolor''' ''color'':

 > ''Color'' specifies the background color
   to use in regions that do not contain characters because they are
   indented by '''-lmargin1''' or '''-lmargin2'''. It may have any of the
   forms accepted by '''Tk_GetColor'''. If ''color'' has not been specified,
   or if it is specified as an empty string, then the color specified by the
   '''-background''' widget option is used.

'''-rmargincolor''' ''color'':

 > ''Color'' specifies the background color
   to use in regions that do not contain characters because they are
   indented by '''-rmargin'''. It may have any of the forms accepted by
   '''Tk_GetColor'''. If ''color'' has not been specified, or if it is
   specified as an empty string, then the color specified by the
   '''-background''' widget option is used.

~ Rejected additional tag configuration options

RFE 1759972 [https://core.tcl.tk/tk/tktview/1759972] requested stippling
('''-selectbgstipple''', '''-selectfgstipple''') for selected text. Also RFE 1754048 [https://core.tcl.tk/tk/tktview/1754048] requested stippling in left and right margins of the text widget ('''-lmargin1stipple''', '''-lmargin2stipple''', '''rmarginstipple''').

Any new stippling options was rejected during the discussion about this
TIP. Reasons were as follows:

 * "Stippling and anything related to Tk Bitmaps should be considered
   obsolete. Their use should be phased out, not expanded. (Bitmaps have
   very limited support in Tk, and stippling is virtually never used in
   modern user interfaces. In fact, AFAIK current graphics stacks --
   cairo, Quartz, Direct3D, &c -- don't even support this operation."

 * "Stippling is something that is an artefact of a prior time, and it
   looks pretty bad now. These days, a way to specify an alpha value for
   the tag would be far more relevant, since then it would end up with a
   blend of the text foreground and background."

~ Reference Implementation

A reference implementation is available in branch tip-443 of the fossil
repository.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|


|


|
|

|

|

|


|

|



|

|


|
|
|
|
|
|
|
|

|



|

|


|

|


|
|
|
|
|

|



|

|
|

|

|

|
|

|

|

|

|
|

|

|

|
|





|









|




|


>

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

# TIP 443: More Tag Configuration Options for the Text Widget

	Author:         François Vogel <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        09-Feb-2016
	Post-History:   
	Keywords:       Tk
	Tcl-Version:    8.6.6
-----

# Abstract

Despite the **text** widget already has numerous configuration options, some
users need more refinements and have requested new tag configuration options.
This TIP proposes to add these options, when deemed relevant.

# Rationale

Several users have reported they miss different tag configuration options in
the **text** widget, stating they cannot achieve the rendering they target.
Such RFE include:

 * RFE 1759972 <https://core.tcl.tk/tk/tktview/1759972> , with Patch
   3469780 <https://core.tcl.tk/tk/tktview/3469780> 

 * RFE 220889 <https://core.tcl.tk/tk/tktview/220889> 

 * RFE 1754048 <https://core.tcl.tk/tk/tktview/1754048> 

# Proposed Change

It is proposed to add the following tag configuration options to the Tk
**text** widget:

**-selectbackground** _color_:

 > Specifies the background color to use
   when displaying selected items. It may have any of the forms accepted by
   **Tk\_GetColor**. If _color_ has not been specified, or if it is
   specified as an empty string, then the color specified by the
   **-background** tag option is used.

 > Note regarding the particular case of the "sel"
 tag: Currently, the "sel" tag **-background** tag option is mirrored with
 the **-selectbackground** text widget option. This makes sense. It does not
 make real sense to have **-selectbackground** applied to the "sel" tag \(it
 is more intuitive to use **-background** for the "sel" tag\). However, if the
 "sel" tag receives non-empty **-selectbackground**, then this tag option
 prevails on the **-background** tag option for mirroring, i.e. the
 **-selectbackground** tag option is mirrored with the
 **-selectbackground** widget option.

**-selectforeground** _color_:

 > Specifies the foreground color to use
   when displaying selected items. It may have any of the forms accepted by
   **Tk\_GetColor**. If _color_ has not been specified, or if it is
   specified as an empty string, then the color specified by the
   **-foreground** tag option is used.

 > Note regarding the particular case of the "sel"
 tag: same principle as above for **-selectbackground**.

**-underlinefg** _color_:

 > Specifies the color to use when displaying
   the underline. It may have any of the forms accepted by **Tk\_GetColor**.
   If _color_ has not been specified, or if it is specified as an empty
   string, then the color specified by the **-foreground** tag option is
   used \(if there is one, otherwise the the color specified by the
   **-foreground** widget option is used\).

**-overstrikefg** _color_:

 > Specifies the color to use when
   displaying the overstrike. It may have any of the forms accepted by
   **Tk\_GetColor**. If _color_ has not been specified, or if it is
   specified as an empty string, then the color specified by the
   **-foreground** tag option is used \(if there is one, otherwise the
   color specified by the **-foreground** widget option is used\).

**-lmargincolor** _color_:

 > _Color_ specifies the background color
   to use in regions that do not contain characters because they are
   indented by **-lmargin1** or **-lmargin2**. It may have any of the
   forms accepted by **Tk\_GetColor**. If _color_ has not been specified,
   or if it is specified as an empty string, then the color specified by the
   **-background** widget option is used.

**-rmargincolor** _color_:

 > _Color_ specifies the background color
   to use in regions that do not contain characters because they are
   indented by **-rmargin**. It may have any of the forms accepted by
   **Tk\_GetColor**. If _color_ has not been specified, or if it is
   specified as an empty string, then the color specified by the
   **-background** widget option is used.

# Rejected additional tag configuration options

RFE 1759972 <https://core.tcl.tk/tk/tktview/1759972>  requested stippling
\(**-selectbgstipple**, **-selectfgstipple**\) for selected text. Also RFE 1754048 <https://core.tcl.tk/tk/tktview/1754048>  requested stippling in left and right margins of the text widget \(**-lmargin1stipple**, **-lmargin2stipple**, **rmarginstipple**\).

Any new stippling options was rejected during the discussion about this
TIP. Reasons were as follows:

 * "Stippling and anything related to Tk Bitmaps should be considered
   obsolete. Their use should be phased out, not expanded. \(Bitmaps have
   very limited support in Tk, and stippling is virtually never used in
   modern user interfaces. In fact, AFAIK current graphics stacks --
   cairo, Quartz, Direct3D, &c -- don't even support this operation."

 * "Stippling is something that is an artefact of a prior time, and it
   looks pretty bad now. These days, a way to specify an alpha value for
   the tag would be far more relevant, since then it would end up with a
   blend of the text foreground and background."

# Reference Implementation

A reference implementation is available in branch tip-443 of the fossil
repository.

# Copyright

This document has been placed in the public domain.

Name change from tip/444.tip to tip/444.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

TIP:            444
Title:          Add "weekdays" unit in clock add
Version:        $Revision: 1.6 $
Author:         Pietro Cerutti <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        23-Feb-2016
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes an enhancement to the '''clock add''' command to support
performing days arithmetic using weekdays only.

~ Rationale

The '''clock add''' command allows to perform time arithmetic using a variety
of time units, including days. However, it offers no easy way to skip
weekends. It is often desired to perform weekdays arithmetic that involves
adding or subtracting a number of non-weekend days to a certain date. This is
useful in example when computing delivery dates.

~ Proposal

The '''weekdays''' time-unit is added to the list accepted by the '''clock
add''' command. The '''count''' argument represents weekdays (Mon-Fri) to be
added (or subtracted in case of a negative value) to the date. The result of
adding weekdays to a date is never a weekend day, unless the starting day is
itself a weekend day and '''count''' is 0.

~ Reference Implementation

Available at http://core.tcl.tk/tcl/timeline?t=tip-444

~ Discussion

A point has been raised as to whether ''weekday'' is unambiguous enough. For instance, in Sweden there seems to be some disagreement on whether the translation ''vardag'' includes Saturdays. As an alternative, the term ''workday'' has been mentioned. This, however, has the downside of introducing the concept of working days vs. public holiday. Also, the working week is not Mon-Fri in all countries, see [https://en.wikipedia.org/wiki/Workweek_and_weekend#Around_the_world].

TIP does not try to accomodate locale-specific features and characteristics. For this reason, it seems best to stick to ''weekday'' as the name of the unit and specifically mention that (Mon-Fri) is intended in the documentation.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|


|

|





|

|
|
|

|

|

|

|

|

|

|


>

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

# TIP 444: Add "weekdays" unit in clock add

	Author:         Pietro Cerutti <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        23-Feb-2016
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes an enhancement to the **clock add** command to support
performing days arithmetic using weekdays only.

# Rationale

The **clock add** command allows to perform time arithmetic using a variety
of time units, including days. However, it offers no easy way to skip
weekends. It is often desired to perform weekdays arithmetic that involves
adding or subtracting a number of non-weekend days to a certain date. This is
useful in example when computing delivery dates.

# Proposal

The **weekdays** time-unit is added to the list accepted by the **clock
add** command. The **count** argument represents weekdays \(Mon-Fri\) to be
added \(or subtracted in case of a negative value\) to the date. The result of
adding weekdays to a date is never a weekend day, unless the starting day is
itself a weekend day and **count** is 0.

# Reference Implementation

Available at <http://core.tcl.tk/tcl/timeline?t=tip-444>

# Discussion

A point has been raised as to whether _weekday_ is unambiguous enough. For instance, in Sweden there seems to be some disagreement on whether the translation _vardag_ includes Saturdays. As an alternative, the term _workday_ has been mentioned. This, however, has the downside of introducing the concept of working days vs. public holiday. Also, the working week is not Mon-Fri in all countries, see <https://en.wikipedia.org/wiki/Workweek_and_weekend#Around_the_world> .

TIP does not try to accomodate locale-specific features and characteristics. For this reason, it seems best to stick to _weekday_ as the name of the unit and specifically mention that \(Mon-Fri\) is intended in the documentation.

# Copyright

This document has been placed in the public domain.

Name change from tip/445.tip to tip/445.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

TIP:            445
Title:          Tcl_ObjType Utility Routines
Version:        $Revision: 1.7 $
Author:         Don Porter <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        18-Mar-2016
Post-History:   
Tcl-Version:	8.7


~ Abstract

Proposes additional public routines useful for extensions that implement
custom '''Tcl_ObjType''s.

~ Background

When an extension creates a custom '''Tcl_ObjType''' it needs to operate on the fields of the '''Tcl_Obj''' and the '''Tcl_ObjType''' structs.

Almost all of these operations have been nicely encapsulated in utility routines, so for example, an extension calls '''Tcl_GetString''' to make sure a value is set for ''objPtr->bytes'', rather than worrying about the backing details of calling the routine ''objPtr->typePtr->updateStringProc'' (if present) for itself.  Likewise '''Tcl_DuplicateObj''' routes processing to type-specific routines as needed.

There are gaps in this interface.  Most glaring is the lack of any way to call the ''freeIntRepProc'' of an incumbent type other than directly through the ''typePtr'' field.  Another missing bit is an encapsulated way to set the string rep without direct manipulation of the ''bytes'' and ''length'' fields.  Within Tcl itself, there are internal utility macros '''TclFreeIntRep''' and '''TclInitStringRep''' for these tasks, but extensions have nothing.

Besides convenience, utility routines such as these improve chances for correctness, since they bring constraints into one place instead of many places.  For example, the requirement that when ''objPtr->typePtr'' is not NULL, it must be paired with an appropriate ''objPtr->internalRep''.  The '''TclFreeIntRep''' macro has a history of fixing such bugs.  A corresponding routine will offer the same benefit to extensions.

~ Proposal

Add to Tcl's stub table of public C routines a new routine

 > void '''Tcl_FreeIntRep'''(Tcl_Obj* ''objPtr'')

that performs precisely the same task as the existing internal
macro '''TclFreeIntRep'''.

Add to Tcl's stub table of public C routines a new routine 

 > char * '''Tcl_InitStringRep'''(Tcl_Obj* ''objPtr'', const char* ''bytes'', unsigned int ''numBytes'')

that performs the function of the existing internal
macro '''TclInitStringRep''', but is extended to return a pointer to the
string rep, and to accept NULL as a value for ''bytes''.  When ''bytes'' is
NULL and ''objPtr'' has no string rep, an uninitialzed buffer
of ''numBytes'' bytes is created for filling by the caller.
When ''bytes'' is NULL and ''objPtr'' has a string rep, the string rep will
be truncated to a length of ''numBytes'' bytes.  When ''numBytes'' is 
greater than zero, and the returned pointer is NULL, that indicates a
failure to allocate memory for the string representation.  The caller
may then choose whether to raise an error or panic.

Add to Tcl's stub table of public C routines a new routine 

 > int '''Tcl_HasStringRep'''(Tcl_Obj* ''objPtr'')

that returns a boolean indicating whether or not a string rep
is currently stored in ''objPtr''.  This is used when the caller
wants to act on ''objPtr'' differently depending on whether or
not it is a ''pure'' value.  Typically this only makes sense in
an extension if it is already known that ''objPtr'' possesses
an internal type that is managed by the extension.

Define a new public type

 > typedef union '''Tcl_ObjIntRep''' {...} '''Tcl_ObjIntRep'''

where the contents are exactly the existing contents of the union
in the ''internalRep'' field of the '''Tcl_Obj''' struct.  This definition
permits us to pass internal representations and pointers to them as
arguments and results in public routines.

Add to Tcl's stub table of public C routines a new routine 

 > void '''Tcl_StoreIntRep'''(Tcl_Obj* ''objPtr'', const Tcl_ObjType* ''typePtr'', const Tcl_ObjIntRep* ''irPtr'')

which stores in ''objPtr'' a copy of the internal representation pointed
to by ''irPtr'' and sets its type to ''typePtr''.  When ''irPtr'' is NULL,
this leaves ''objPtr'' without a representation for type ''typePtr''.

Add to Tcl's stub table of public C routines a new routine 

 > Tcl_ObjIntRep* '''Tcl_FetchIntRep'''(Tcl_Obj* ''objPtr'', const Tcl_ObjType* ''typePtr'')

which returns a pointer to the internal representation stored
in ''objPtr'' that matches the requested type ''typePtr''.

~ Compatibility

These are new routines, so they have no compatibility concerns in the sense of cause trouble for existing working code.

They do help set up an improved compatibility scenario for the future however.  Extensions that use these new routines to stop directly referring to the fields of the '''Tcl_Obj''' and '''Tcl_ObjType''' structs are prepared to support a source-compatible migration to a Tcl 9 that might then be free to make revisions to those structs.

~ Implementation

Taking shape on the tip-445 branch.

~ Rejected Alternatives

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|

|

|

|

|

|

|



|


|



|


|
|
|
|
|
|






|


|
|
|
|




|


|





|

|
|
|



|


|

|



|

|



|

|


>

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

# TIP 445: Tcl_ObjType Utility Routines

	Author:         Don Porter <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        18-Mar-2016
	Post-History:   
	Tcl-Version:	8.7
-----

# Abstract

Proposes additional public routines useful for extensions that implement
custom **Tcl\_ObjType_s.

# Background

When an extension creates a custom **Tcl\_ObjType** it needs to operate on the fields of the **Tcl\_Obj** and the **Tcl\_ObjType** structs.

Almost all of these operations have been nicely encapsulated in utility routines, so for example, an extension calls **Tcl\_GetString** to make sure a value is set for _objPtr->bytes_, rather than worrying about the backing details of calling the routine _objPtr->typePtr->updateStringProc_ \(if present\) for itself.  Likewise **Tcl\_DuplicateObj** routes processing to type-specific routines as needed.

There are gaps in this interface.  Most glaring is the lack of any way to call the _freeIntRepProc_ of an incumbent type other than directly through the _typePtr_ field.  Another missing bit is an encapsulated way to set the string rep without direct manipulation of the _bytes_ and _length_ fields.  Within Tcl itself, there are internal utility macros **TclFreeIntRep** and **TclInitStringRep** for these tasks, but extensions have nothing.

Besides convenience, utility routines such as these improve chances for correctness, since they bring constraints into one place instead of many places.  For example, the requirement that when _objPtr->typePtr_ is not NULL, it must be paired with an appropriate _objPtr->internalRep_.  The **TclFreeIntRep** macro has a history of fixing such bugs.  A corresponding routine will offer the same benefit to extensions.

# Proposal

Add to Tcl's stub table of public C routines a new routine

 > void **Tcl\_FreeIntRep**\(Tcl\_Obj\* _objPtr_\)

that performs precisely the same task as the existing internal
macro **TclFreeIntRep**.

Add to Tcl's stub table of public C routines a new routine 

 > char \* **Tcl\_InitStringRep**\(Tcl\_Obj\* _objPtr_, const char\* _bytes_, unsigned int _numBytes_\)

that performs the function of the existing internal
macro **TclInitStringRep**, but is extended to return a pointer to the
string rep, and to accept NULL as a value for _bytes_.  When _bytes_ is
NULL and _objPtr_ has no string rep, an uninitialzed buffer
of _numBytes_ bytes is created for filling by the caller.
When _bytes_ is NULL and _objPtr_ has a string rep, the string rep will
be truncated to a length of _numBytes_ bytes.  When _numBytes_ is 
greater than zero, and the returned pointer is NULL, that indicates a
failure to allocate memory for the string representation.  The caller
may then choose whether to raise an error or panic.

Add to Tcl's stub table of public C routines a new routine 

 > int **Tcl\_HasStringRep**\(Tcl\_Obj\* _objPtr_\)

that returns a boolean indicating whether or not a string rep
is currently stored in _objPtr_.  This is used when the caller
wants to act on _objPtr_ differently depending on whether or
not it is a _pure_ value.  Typically this only makes sense in
an extension if it is already known that _objPtr_ possesses
an internal type that is managed by the extension.

Define a new public type

 > typedef union **Tcl\_ObjIntRep** \{...\} **Tcl\_ObjIntRep**

where the contents are exactly the existing contents of the union
in the _internalRep_ field of the **Tcl\_Obj** struct.  This definition
permits us to pass internal representations and pointers to them as
arguments and results in public routines.

Add to Tcl's stub table of public C routines a new routine 

 > void **Tcl\_StoreIntRep**\(Tcl\_Obj\* _objPtr_, const Tcl\_ObjType\* _typePtr_, const Tcl\_ObjIntRep\* _irPtr_\)

which stores in _objPtr_ a copy of the internal representation pointed
to by _irPtr_ and sets its type to _typePtr_.  When _irPtr_ is NULL,
this leaves _objPtr_ without a representation for type _typePtr_.

Add to Tcl's stub table of public C routines a new routine 

 > Tcl\_ObjIntRep\* **Tcl\_FetchIntRep**\(Tcl\_Obj\* _objPtr_, const Tcl\_ObjType\* _typePtr_\)

which returns a pointer to the internal representation stored
in _objPtr_ that matches the requested type _typePtr_.

# Compatibility

These are new routines, so they have no compatibility concerns in the sense of cause trouble for existing working code.

They do help set up an improved compatibility scenario for the future however.  Extensions that use these new routines to stop directly referring to the fields of the **Tcl\_Obj** and **Tcl\_ObjType** structs are prepared to support a source-compatible migration to a Tcl 9 that might then be free to make revisions to those structs.

# Implementation

Taking shape on the tip-445 branch.

# Rejected Alternatives

# Copyright

This document has been placed in the public domain.

Name change from tip/446.tip to tip/446.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

TIP:            446
Title:          Introspect Undo/Redo Stack Depths
Version:        $Revision: 1.9 $
Author:         Fran�ois Vogel <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        05-Apr-2016
Post-History:   
Keywords:       Tk
Tcl-Version:    8.6.6


~ Abstract

Tk features a generic undo/redo mechanism (see [104]). This is used in
practice by the '''text''' widget, within the '''edit''' command. The present
TIP proposes to add two new subcommands to the '''edit''' command allowing the
user to know whether undo and redo is possible for a '''text''' widget.

~ Rationale

The undo/redo feature of Tk is handy and works very well. In modern GUIs,
there is usually a button in a menubar to call the "Undo" command, and
likewise for "Redo". It is good practice to enhance the user experience by
greying out or otherwise changing the button aspect when there is nothing to
undo (or redo). This cannot be achieved currently with the curent Tk
implementation because there is no way to know whether the undo and redo
stacks are empty or not.

This feature was requested for the text widget in RFE 1273358
[https://core.tcl.tk/tk/tktview/1273358]

~ Proposed Change

It is proposed to add the following subcommands to the '''text''' widget's
'''edit''' command:

'''canundo''':

 > Returns a boolean true if undo is possible, i.e. when the undo stack is
   not empty. Otherwise returns false.

'''canredo''':

 > Returns a boolean true if redo is possible, i.e. when the undo stack is
   not empty. Otherwise returns false.

When the '''-undo''' option of the text widget is false both subcommands return
false since indeed no undo nor redo action is possible in this case. The undo/redo
stacks are however not cleared, so that when -undo becomes eventually true again
the two new subcommands will return their value in accordance with the contents
of the stacks (this is current behavior of the undo/redo feature - the TIP does
not intend to change this).

This new capability will be implemented in the generic code for undo
(''generic/tkUndo.c''), so that any client of the generic undo/redo mechanism
can make use of it. Currently, only the '''text''' widget is concerned since
no other Tk widget is featuring undo/redo.

Besides the two new subcommands, it is also proposed to add a new virtual event
'''<<UndoStack>>''', that will trigger each time the undo or redo stack becomes
empty or unempty. When this condition is met, the event will trigger once for
each peer widget.

Despite this is a new feature, this TIP targets Tk 8.6.6 since no change of
any existing behavior is proposed: only new, additonal, features are proposed.
It is therefore believed there is no risk regarding backwards compatibility
in the 8.6.x series.

~ Example

|  package require Tk
|
|  pack [text .t -undo false -autoseparators false]
|
|  set nbUS 0
|  bind .t <<UndoStack>> {incr nbUS}
|
|  .t edit canundo    ; # 0
|  .t edit canredo    ; # 0
|
|  .t configure -undo true
|
|  .t edit canundo    ; # 0
|  .t edit canredo    ; # 0
|
|  .t insert end "ABC\n"
|  .t edit separator
|  .t insert end "DEF\n"
|  .t insert end "DEF again\n"
|  .t edit separator
|
|  .t edit canundo    ; # 1
|  .t edit canredo    ; # 0
|
|  .t edit undo
|
|  .t edit canundo    ; # 1
|  .t edit canredo    ; # 1
|
|  # A quick interactive testing environment...:
|  
|  pack [label .l]
|  
|  proc showit {} {
|    global nbUS
|    .l configure -text "Can undo: [.t edit canundo]\t\t\t \
|                        Can redo: [.t edit canredo]\t\t\t \
|                        <<UndoStack>> triggered: $nbUS"
|    after 200 showit
|  }

|  showit
|  
|  proc toggleautosep {} {
|    global autosepset
|    set autosepset [.t cget -autoseparators]
|    if {$autosepset} {
|      .t configure -autoseparators false
|    } else {
|      .t configure -autoseparators true
|    }

|    set autosepset [.t cget -autoseparators]
|  }

|  proc toggleundo {} {
|    global undoset
|    set undoset [.t cget -undo]
|    if {$undoset} {
|      .t configure -undo false
|    } else {
|      .t configure -undo true
|    }

|    set undoset [.t cget -undo]
|  }

|  button .b1 -text "Insert separator" -command {.t edit separator}
|  button .b2 -text "Undo" -command {.t edit undo}
|  button .b3 -text "Redo" -command {.t edit redo}
|  button .b32 -text "Reset" -command {.t edit reset}
|  checkbutton .b4 -text "-autoseparators" -command toggleautosep -variable autosepset
|  checkbutton .b5 -text "-undo" -command toggleundo -variable undoset ; .b5 select
|  
|  pack .b1 .b2 .b3 .b32 .b4 .b5 -side left -padx 10

~ Reference Implementation

A reference implementation is available in branch tip-446 of the fossil
repository. Credits for this implementation largely go to Neil Hodgson, the author of TkTextPlus (for canundo/canredo) and to Koen Danckaert (for <<UndoStack>>).

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|
|
|

|





|




|

|

|
|

|




|




|



|
|


|
|



|








|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
<
>
|
<
>
|
|
|
|
|
|
|
<
>
|
<
>
|
|
|
|
|
|
|
|

|


|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

# TIP 446: Introspect Undo/Redo Stack Depths

	Author:         François Vogel <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        05-Apr-2016
	Post-History:   
	Keywords:       Tk
	Tcl-Version:    8.6.6
-----

# Abstract

Tk features a generic undo/redo mechanism \(see [[104]](104.md)\). This is used in
practice by the **text** widget, within the **edit** command. The present
TIP proposes to add two new subcommands to the **edit** command allowing the
user to know whether undo and redo is possible for a **text** widget.

# Rationale

The undo/redo feature of Tk is handy and works very well. In modern GUIs,
there is usually a button in a menubar to call the "Undo" command, and
likewise for "Redo". It is good practice to enhance the user experience by
greying out or otherwise changing the button aspect when there is nothing to
undo \(or redo\). This cannot be achieved currently with the curent Tk
implementation because there is no way to know whether the undo and redo
stacks are empty or not.

This feature was requested for the text widget in RFE 1273358
<https://core.tcl.tk/tk/tktview/1273358> 

# Proposed Change

It is proposed to add the following subcommands to the **text** widget's
**edit** command:

**canundo**:

 > Returns a boolean true if undo is possible, i.e. when the undo stack is
   not empty. Otherwise returns false.

**canredo**:

 > Returns a boolean true if redo is possible, i.e. when the undo stack is
   not empty. Otherwise returns false.

When the **-undo** option of the text widget is false both subcommands return
false since indeed no undo nor redo action is possible in this case. The undo/redo
stacks are however not cleared, so that when -undo becomes eventually true again
the two new subcommands will return their value in accordance with the contents
of the stacks \(this is current behavior of the undo/redo feature - the TIP does
not intend to change this\).

This new capability will be implemented in the generic code for undo
\(_generic/tkUndo.c_\), so that any client of the generic undo/redo mechanism
can make use of it. Currently, only the **text** widget is concerned since
no other Tk widget is featuring undo/redo.

Besides the two new subcommands, it is also proposed to add a new virtual event
**<<UndoStack>>**, that will trigger each time the undo or redo stack becomes
empty or unempty. When this condition is met, the event will trigger once for
each peer widget.

Despite this is a new feature, this TIP targets Tk 8.6.6 since no change of
any existing behavior is proposed: only new, additonal, features are proposed.
It is therefore believed there is no risk regarding backwards compatibility
in the 8.6.x series.

# Example

	  package require Tk
	
	  pack [text .t -undo false -autoseparators false]
	
	  set nbUS 0
	  bind .t <<UndoStack>> {incr nbUS}
	
	  .t edit canundo    ; # 0
	  .t edit canredo    ; # 0
	
	  .t configure -undo true
	
	  .t edit canundo    ; # 0
	  .t edit canredo    ; # 0
	
	  .t insert end "ABC\n"
	  .t edit separator
	  .t insert end "DEF\n"
	  .t insert end "DEF again\n"
	  .t edit separator
	
	  .t edit canundo    ; # 1
	  .t edit canredo    ; # 0
	
	  .t edit undo
	
	  .t edit canundo    ; # 1
	  .t edit canredo    ; # 1
	
	  # A quick interactive testing environment...:
	  
	  pack [label .l]
	  
	  proc showit {} {
	    global nbUS
	    .l configure -text "Can undo: [.t edit canundo]\t\t\t \
	                        Can redo: [.t edit canredo]\t\t\t \
	                        <<UndoStack>> triggered: $nbUS"
	    after 200 showit

	  }
	  showit
	  
	  proc toggleautosep {} {
	    global autosepset
	    set autosepset [.t cget -autoseparators]
	    if {$autosepset} {
	      .t configure -autoseparators false
	    } else {
	      .t configure -autoseparators true

	    }
	    set autosepset [.t cget -autoseparators]

	  }
	  proc toggleundo {} {
	    global undoset
	    set undoset [.t cget -undo]
	    if {$undoset} {
	      .t configure -undo false
	    } else {
	      .t configure -undo true

	    }
	    set undoset [.t cget -undo]

	  }
	  button .b1 -text "Insert separator" -command {.t edit separator}
	  button .b2 -text "Undo" -command {.t edit undo}
	  button .b3 -text "Redo" -command {.t edit redo}
	  button .b32 -text "Reset" -command {.t edit reset}
	  checkbutton .b4 -text "-autoseparators" -command toggleautosep -variable autosepset
	  checkbutton .b5 -text "-undo" -command toggleundo -variable undoset ; .b5 select
	  
	  pack .b1 .b2 .b3 .b32 .b4 .b5 -side left -padx 10

# Reference Implementation

A reference implementation is available in branch tip-446 of the fossil
repository. Credits for this implementation largely go to Neil Hodgson, the author of TkTextPlus \(for canundo/canredo\) and to Koen Danckaert \(for <<UndoStack>>\).

# Copyright

This document has been placed in the public domain.

Name change from tip/447.tip to tip/447.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

TIP:            447
Title:          Execution Time Verbosity Levels in tcltest::configure
Version:        $Revision: 1.6 $
Author:         Pietro Cerutti <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        20-Apr-2016
Post-History:   
Keywords:       Tcl,tcltest
Tcl-Version:    8.7


~ Abstract

The '''-verbose''' option of the '''tcltest::configure''' command accepts a set of
verbosity levels to specify what pieces of information about tests the user
wants reported. This TIP proposes the addition of two new verbosity levels to
report information about the execution time of tests.

~ Rationale

When doing test-driven development, working on the refinement of a new
feature, or fixing a bug, it is very important to be able to measure the
effect of code changes on execution time.

The '''tcltest''' infrastructure is the testing framework used both by Tcl/Tk and
a number of extensions.  The '''tcltest''' infrastructure is highly configurable
and allows the user to choose which information on the tests being run are
reported. This can be done with the '''-verbose''' option of the
'''tcltest::configure''' command. Verbosity levels allow to report, e.g., when a
test passes, is skipped, or fails.

A proper way to measure the time spent running each test is currently missing.
Scope of this TIP is to address this issue by extending the set of verbosity
levels accepted.

~ Proposal

The '''-verbose''' option of the '''tcltest::configure''' command is modified to
accept the following new verbosity levels:

 usec (u): Report execution time of each test, in microseconds.

 msec (m): Report the execution time of each test, in milliseconds.

~ Example

This example demonstrates running a subset of the Tcl test suite with
verbosity level '''usec''' ('''u'''):

|$ make TESTFLAGS="-verbose u -match lsearch-1.*" test
|...
|lsearch.test
|++++ lsearch-1.1 took 521 us
|++++ lsearch-1.2 took 156 us
|++++ lsearch-1.3 took 187 us
|++++ lsearch-1.4 took 120 us

~ Discussion

~~ Additional Time Units

The implementation of additional verbosity levels to track execution times in
seconds, minutes, hours, and so on is trivial, but has been discarded as unit
or functional test are often meant to be fast. Another approach would be to
introduce a configurable verbosity level to carry information on the time unit
to be used. Examples could be '''time:usec''', '''time:msec''', and '''time:sec'''. This
option has also been discarded because it clashes with the current approach of
having verbosity level strings that can be shortened to a single character. It
is the author's opinion that milliseconds and microseconds should address most
use cases.

~~ When Timing Should be Displayed?

The current implementation dumps timing information before any reports of
success / failure. Example:

|---- tsv-lmdb-1.5 start
|++++ tsv-lmdb-1.5 took 828 us
|
|
|==== tsv-lmdb-1.5 tsv::exists - previously set exists FAILED
|---- Result was:
|1

|---- Result should have been (exact matching):
|0

|==== tsv-lmdb-1.5 FAILED

This allows for a simpler implementation that doesn't need to account for the
different code paths taken by '''tcltest''' when reporting success or failure. The
author doesn't have a strong opinion on this matter and is open to discussion,
should anybody have any counter-proposal.

~~ What to Print?

The current implementation decision to print "<testname> took <amount> <unit>"
is arbitrary. Again, the author has no strong opinion on the subject.

~~ On the Goodness of the Times Reported

FV, DGP, and and DKF have raised concerns on the mailing lists on the goodness
of the time values reported by the '''msec''' and '''usec''' verbosity levels.
In particular, the problem of repeatibility of the results has been mentioned,
and it has been noted that while the idea is good, this might not be the right
tool for (the|every) job.

My opinion is that the tool can be useful, given that its scope is made clear.
I followed DGP's suggestion and added [checkin 2b96ef] an explicit note in the
documentation about the "modest ambitions" of this enhancement.

~ Reference Implementation

In the gahr-tip-447 branch.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|




|





|
|

|
|






|

|


|

|

|


|

|
|
|
|
|
|
|

|

|





|





|




|
|
|
|
|
|
<
>
|
<
>
|


|



|




|


|


|





|



|


>

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

# TIP 447: Execution Time Verbosity Levels in tcltest::configure

	Author:         Pietro Cerutti <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        20-Apr-2016
	Post-History:   
	Keywords:       Tcl,tcltest
	Tcl-Version:    8.7
-----

# Abstract

The **-verbose** option of the **tcltest::configure** command accepts a set of
verbosity levels to specify what pieces of information about tests the user
wants reported. This TIP proposes the addition of two new verbosity levels to
report information about the execution time of tests.

# Rationale

When doing test-driven development, working on the refinement of a new
feature, or fixing a bug, it is very important to be able to measure the
effect of code changes on execution time.

The **tcltest** infrastructure is the testing framework used both by Tcl/Tk and
a number of extensions.  The **tcltest** infrastructure is highly configurable
and allows the user to choose which information on the tests being run are
reported. This can be done with the **-verbose** option of the
**tcltest::configure** command. Verbosity levels allow to report, e.g., when a
test passes, is skipped, or fails.

A proper way to measure the time spent running each test is currently missing.
Scope of this TIP is to address this issue by extending the set of verbosity
levels accepted.

# Proposal

The **-verbose** option of the **tcltest::configure** command is modified to
accept the following new verbosity levels:

 usec \(u\): Report execution time of each test, in microseconds.

 msec \(m\): Report the execution time of each test, in milliseconds.

# Example

This example demonstrates running a subset of the Tcl test suite with
verbosity level **usec** \(**u**\):

	$ make TESTFLAGS="-verbose u -match lsearch-1.*" test
	...
	lsearch.test
	++++ lsearch-1.1 took 521 us
	++++ lsearch-1.2 took 156 us
	++++ lsearch-1.3 took 187 us
	++++ lsearch-1.4 took 120 us

# Discussion

## Additional Time Units

The implementation of additional verbosity levels to track execution times in
seconds, minutes, hours, and so on is trivial, but has been discarded as unit
or functional test are often meant to be fast. Another approach would be to
introduce a configurable verbosity level to carry information on the time unit
to be used. Examples could be **time:usec**, **time:msec**, and **time:sec**. This
option has also been discarded because it clashes with the current approach of
having verbosity level strings that can be shortened to a single character. It
is the author's opinion that milliseconds and microseconds should address most
use cases.

## When Timing Should be Displayed?

The current implementation dumps timing information before any reports of
success / failure. Example:

	---- tsv-lmdb-1.5 start
	++++ tsv-lmdb-1.5 took 828 us
	
	
	==== tsv-lmdb-1.5 tsv::exists - previously set exists FAILED
	---- Result was:

	1
	---- Result should have been (exact matching):

	0
	==== tsv-lmdb-1.5 FAILED

This allows for a simpler implementation that doesn't need to account for the
different code paths taken by **tcltest** when reporting success or failure. The
author doesn't have a strong opinion on this matter and is open to discussion,
should anybody have any counter-proposal.

## What to Print?

The current implementation decision to print "<testname> took <amount> <unit>"
is arbitrary. Again, the author has no strong opinion on the subject.

## On the Goodness of the Times Reported

FV, DGP, and and DKF have raised concerns on the mailing lists on the goodness
of the time values reported by the **msec** and **usec** verbosity levels.
In particular, the problem of repeatibility of the results has been mentioned,
and it has been noted that while the idea is good, this might not be the right
tool for \(the\|every\) job.

My opinion is that the tool can be useful, given that its scope is made clear.
I followed DGP's suggestion and added [checkin 2b96ef] an explicit note in the
documentation about the "modest ambitions" of this enhancement.

# Reference Implementation

In the gahr-tip-447 branch.

# Copyright

This document has been placed in the public domain.

Name change from tip/448.tip to tip/448.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

TIP:		448
Title:		Update Tcl_SetNotifier to Reinitialize Event Loop
Version:	$Revision: 1.1 $
Author:		Jeff Rogers <[email protected]>
State:		Draft
Type:		Project
Tcl-Version:	8.7
Vote:		Pending
Created:	24-May-2016
Post-History:
Keywords: Tcl, C API


~ Abstract

Tcl_SetNotifier cannot be used in its current state to replace a notifier than
has been initialized because pointers to the old initialized value are kept in
the interp's private data.  This TIP proposes a way to change that.

~ Background

The '''Tcl_SetNotifier''' API was introduced to allow replacement of the
built-in notifier; it works by setting hooks for various notifier functions
that are called in place of the builtin functions.

It was expected that this function would only be called before the Tcl library
had been initialized and any state had been set up; however this prevents it
from being usable from a module loaded by a running interpreter.

This TIP proposes changing the behavior of this API to, in addition to setting
the function hooks will shut down a running notifier and restart the notifier
if it has been running previously.  This is the minimum change necessary to
allow a new notifier to be loaded from within a running interpreter.

It is probably not always possible to stop a running notifier, especially if
event sources have been created.  It is not necessarily easy to detect such
failure; the proposed implementation doesn't even try.  And there is no way to
report such failure if it was detected.  As such, this remains a somewhat
dangerous interface to use.

With this change in place, it will be possible to load a new notifier
implementation (e.g., a ''poll()'' or ''libevent'' based one) from a Tcl
program, provided it is the very first thing done.  An implementation of a
poll-based notifier that requires the functionality in this TIP can be found
at http://fossil.etoyoc.com/sandbox/tcllib/artifact/ad30080cdee762a3

~ Description

Change the implementation of '''Tcl_SetNotifier''' to check if a notifier is
currently running; if it is, the current notifier will be finalized before the
new hooks are swapped in, and afterwards the notifier will be re-initialized.
If the notifier is not already initialized, there is no change to
functionality.

~ Implementation

A patch implementing the proposed change can be found at
http://fossil.etoyoc.com/sandbox/tcllib/artifact/b2b272a285811272

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|

|



















|


|

|

|





|


|

|


>

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

# TIP 448: Update Tcl_SetNotifier to Reinitialize Event Loop

	Author:		Jeff Rogers <[email protected]>
	State:		Draft
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Pending
	Created:	24-May-2016
	Post-History:
	Keywords: Tcl, C API
-----

# Abstract

Tcl\_SetNotifier cannot be used in its current state to replace a notifier than
has been initialized because pointers to the old initialized value are kept in
the interp's private data.  This TIP proposes a way to change that.

# Background

The **Tcl\_SetNotifier** API was introduced to allow replacement of the
built-in notifier; it works by setting hooks for various notifier functions
that are called in place of the builtin functions.

It was expected that this function would only be called before the Tcl library
had been initialized and any state had been set up; however this prevents it
from being usable from a module loaded by a running interpreter.

This TIP proposes changing the behavior of this API to, in addition to setting
the function hooks will shut down a running notifier and restart the notifier
if it has been running previously.  This is the minimum change necessary to
allow a new notifier to be loaded from within a running interpreter.

It is probably not always possible to stop a running notifier, especially if
event sources have been created.  It is not necessarily easy to detect such
failure; the proposed implementation doesn't even try.  And there is no way to
report such failure if it was detected.  As such, this remains a somewhat
dangerous interface to use.

With this change in place, it will be possible to load a new notifier
implementation \(e.g., a _poll\(\)_ or _libevent_ based one\) from a Tcl
program, provided it is the very first thing done.  An implementation of a
poll-based notifier that requires the functionality in this TIP can be found
at <http://fossil.etoyoc.com/sandbox/tcllib/artifact/ad30080cdee762a3>

# Description

Change the implementation of **Tcl\_SetNotifier** to check if a notifier is
currently running; if it is, the current notifier will be finalized before the
new hooks are swapped in, and afterwards the notifier will be re-initialized.
If the notifier is not already initialized, there is no change to
functionality.

# Implementation

A patch implementing the proposed change can be found at
<http://fossil.etoyoc.com/sandbox/tcllib/artifact/b2b272a285811272>

# Copyright

This document has been placed in the public domain.

Name change from tip/449.tip to tip/449.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

TIP:            449
Title:          [text] undo/redo to Return Range of Characters
Version:        $Revision: 1.12 $
Author:         Fran�ois Vogel <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        07-Jun-2016
Post-History:   
Keywords:       Tk
Tcl-Version:    8.7


~ Abstract

Tk features an undo/redo mechanism for the '''text''' widget. This TIP
proposes that the '''edit undo''' and '''edit redo''' commands of the text
widget return the ranges of characters impacted by the undo or redo operation.

~ Rationale

In some applications using the '''text''' widget, say a text editor, modern
practice is to show the text with highlighting, colorization, or any other
ways of improving readablity for the human user. When undoing/redoing changes
in the text, these applications need to know which characters were impacted by
the undo or redo operation. This can be done by comparing the '''text'''
widget contents before the change with its contents after the change, but this
is very far from optimal especially with large texts.

Therefore a better way to get this information is proposed in the present TIP.

This feature was requested for the text widget in RFE 1217222
[https://core.tcl.tk/tk/tktview/1217222]

~ Proposed Change

Currently, '''edit undo''' and '''edit redo''' commands return the empty
string.

It is proposed to change this return value and make these commands return the
ranges of indices that were impacted by the undo or redo operation.

This return value is a list of indices, with an even number of elements.
Indeed, there can be several edits (insertions and deletions) between two
separators in the undo stack and all such edits have to report which range of
text they changed.

The returned ranges are made of indices making sense at undo/redo return
time, i.e. they refer to the text widget content at the time '''edit undo'''
and '''edit redo''' return. Moreover, the returned list of indices is optimal,
in the sense that the ranges contained in that list are all disjoint
(overlapping ranges are merged, and ranges already contained in another range
are not returned).

~ Backwards Compatibility

The proposed implementation makes use of temporary marks, that only exist
''during'' an undo or redo operation (and never before or after these
operations). This could be seen as a concern regarding backwards
compatibility, however it is believed that the names of these marks has been
chosen such that this should not be an issue. The chosen name is
'''tk::undoMark<g><ID>''', where '''<g>''' is either '''L''' or '''R''', and
'''<ID>''' is an integer identifier. The risk of name collision is therefore
deemed very low due to prefixing by '''tk::'''. This naming convention follows
what is already existing in the text widget (internal anchors).

~ Example

|  package require Tk
|
|  pack [text .t -undo true]
|  .t insert end "Hello World.\n"
|  .t edit separator
|  .t insert end "Again hello.\n"
|
|  .t edit undo  ; # will now return {2.0 3.0}
|  .t edit redo  ; # will now return {2.0 3.0}
|

More examples can be found by studying the new tests in the feature branch
tip-449 hosting the development.

~ Reference Implementation

A reference implementation is available in branch tip-449 of the Tk fossil
repository.

This new capability is implemented entirely in the code of the text widget. The undo/redo generic code (in ''generic/tkUndo.c'') is untouched.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|


|

|



|






|

|

|






|




|
|

|
|

|


|
|


|
|
|
|

|

|
|
|
|
|
|
|
|
|
|




|




|

|


>

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

# TIP 449: [text] undo/redo to Return Range of Characters

	Author:         François Vogel <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        07-Jun-2016
	Post-History:   
	Keywords:       Tk
	Tcl-Version:    8.7
-----

# Abstract

Tk features an undo/redo mechanism for the **text** widget. This TIP
proposes that the **edit undo** and **edit redo** commands of the text
widget return the ranges of characters impacted by the undo or redo operation.

# Rationale

In some applications using the **text** widget, say a text editor, modern
practice is to show the text with highlighting, colorization, or any other
ways of improving readablity for the human user. When undoing/redoing changes
in the text, these applications need to know which characters were impacted by
the undo or redo operation. This can be done by comparing the **text**
widget contents before the change with its contents after the change, but this
is very far from optimal especially with large texts.

Therefore a better way to get this information is proposed in the present TIP.

This feature was requested for the text widget in RFE 1217222
<https://core.tcl.tk/tk/tktview/1217222> 

# Proposed Change

Currently, **edit undo** and **edit redo** commands return the empty
string.

It is proposed to change this return value and make these commands return the
ranges of indices that were impacted by the undo or redo operation.

This return value is a list of indices, with an even number of elements.
Indeed, there can be several edits \(insertions and deletions\) between two
separators in the undo stack and all such edits have to report which range of
text they changed.

The returned ranges are made of indices making sense at undo/redo return
time, i.e. they refer to the text widget content at the time **edit undo**
and **edit redo** return. Moreover, the returned list of indices is optimal,
in the sense that the ranges contained in that list are all disjoint
\(overlapping ranges are merged, and ranges already contained in another range
are not returned\).

# Backwards Compatibility

The proposed implementation makes use of temporary marks, that only exist
_during_ an undo or redo operation \(and never before or after these
operations\). This could be seen as a concern regarding backwards
compatibility, however it is believed that the names of these marks has been
chosen such that this should not be an issue. The chosen name is
**tk::undoMark<g><ID>**, where **<g>** is either **L** or **R**, and
**<ID>** is an integer identifier. The risk of name collision is therefore
deemed very low due to prefixing by **tk::**. This naming convention follows
what is already existing in the text widget \(internal anchors\).

# Example

	  package require Tk
	
	  pack [text .t -undo true]
	  .t insert end "Hello World.\n"
	  .t edit separator
	  .t insert end "Again hello.\n"
	
	  .t edit undo  ; # will now return {2.0 3.0}
	  .t edit redo  ; # will now return {2.0 3.0}
	

More examples can be found by studying the new tests in the feature branch
tip-449 hosting the development.

# Reference Implementation

A reference implementation is available in branch tip-449 of the Tk fossil
repository.

This new capability is implemented entirely in the code of the text widget. The undo/redo generic code \(in _generic/tkUndo.c_\) is untouched.

# Copyright

This document has been placed in the public domain.

Name change from tip/45.tip to tip/45.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

TIP:            45
Title:          Empty index lists for [lindex] and [lset]
Version:        $Revision: 1.9 $
Author:         Kevin Kenny <[email protected]>
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        18-Jul-2001
Post-History:   
Discussions-To: news:comp.lang.tcl,mailto:[email protected]
Keywords:       lindex,lset,multiple arguments,sublists
Tcl-Version:    8.4b1


~ Abstract

TIP's #22 and #33 contain an oversight in specifying the behavior
of the multi-argument forms of ''lset'' and ''lindex'' when an empty
index list is specified.  The intended behavior is that an empty list
of indices designates the entire list.

~ Rationale

In the discussion of [33]
([http://www.geocrawler.com/archives/3/7375/2001/5/0/5784409/]), Jim
Ingham pointed out that the list of indices presented to the
multi-argument forms of ''lindex'' and ''lset'' is analogous to a
database cursor.  This cursor is conceptually navigating a tree
structure; the command:

|  lindex $list {1 2 3}

means, "extract the sublist at index 1 in $list, the sublist at
index 2 in that list, and the element at index 3 in that list".

When implementing this functionality, the author of this TIP
realized that [22] and [33] provide no way to
address the root of the tree -- the entire list being manipulated.
An empty list of indices is a convenient means of specifying the root.

~ Specification

 1. The specification of ''lindex'' in [22] shall be amended so that
    the forms:

|  lindex list

 >  and

|  lindex list {}

 >  will return the value of the entire list.  The ''list'' parameter
    is not required to be a well-formed Tcl list when
    this form is used.

 1. The specification of ''lset'' in [33] shall be amended so that
    the forms:

|  lset var value

 >  and

|  lset var {} value

 >  will simply store the supplied value into the variable named ''var''.
    Neither the old nor the new value of ''var'' is required to be
    a well-formed Tcl list when this form is used.  The return value of
    the operation, as with all other uses of ''lset'', is the
    new value of ''var''.

~ Reference implementation

Work progresses on implementing this functionality; the currently
committed version is on SourceForge in the branch labeled,
''kennykb-tcl-22-33''.

~ Discussion

Since this proposed change introduces syntax that is expressly forbidden in
[22] and [33], it does not have any impact on backward compatibility.
For the same reason, the author thought it unwise to proceed with its
implementation without a vote of the TCT.

~ See Also

[22], [33].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|
|



|

|
|

|



|





|



|

|


|

|

|

|



|


|

|

|

|
|

|
|

|



|

|


|



|

|

|


>

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

# TIP 45: Empty index lists for [lindex] and [lset]

	Author:         Kevin Kenny <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        18-Jul-2001
	Post-History:   
	Discussions-To: news:comp.lang.tcl,mailto:[email protected]
	Keywords:       lindex,lset,multiple arguments,sublists
	Tcl-Version:    8.4b1
-----

# Abstract

TIP's \#22 and \#33 contain an oversight in specifying the behavior
of the multi-argument forms of _lset_ and _lindex_ when an empty
index list is specified.  The intended behavior is that an empty list
of indices designates the entire list.

# Rationale

In the discussion of [[33]](33.md)
\(<http://www.geocrawler.com/archives/3/7375/2001/5/0/5784409/> \), Jim
Ingham pointed out that the list of indices presented to the
multi-argument forms of _lindex_ and _lset_ is analogous to a
database cursor.  This cursor is conceptually navigating a tree
structure; the command:

	  lindex $list {1 2 3}

means, "extract the sublist at index 1 in $list, the sublist at
index 2 in that list, and the element at index 3 in that list".

When implementing this functionality, the author of this TIP
realized that [[22]](22.md) and [[33]](33.md) provide no way to
address the root of the tree -- the entire list being manipulated.
An empty list of indices is a convenient means of specifying the root.

# Specification

 1. The specification of _lindex_ in [[22]](22.md) shall be amended so that
    the forms:

		  lindex list

	 >  and

		  lindex list {}

	 >  will return the value of the entire list.  The _list_ parameter
    is not required to be a well-formed Tcl list when
    this form is used.

 1. The specification of _lset_ in [[33]](33.md) shall be amended so that
    the forms:

		  lset var value

	 >  and

		  lset var {} value

	 >  will simply store the supplied value into the variable named _var_.
    Neither the old nor the new value of _var_ is required to be
    a well-formed Tcl list when this form is used.  The return value of
    the operation, as with all other uses of _lset_, is the
    new value of _var_.

# Reference implementation

Work progresses on implementing this functionality; the currently
committed version is on SourceForge in the branch labeled,
_kennykb-tcl-22-33_.

# Discussion

Since this proposed change introduces syntax that is expressly forbidden in
[[22]](22.md) and [[33]](33.md), it does not have any impact on backward compatibility.
For the same reason, the author thought it unwise to proceed with its
implementation without a vote of the TCT.

# See Also

[[22]](22.md), [[33]](33.md).

# Copyright

This document has been placed in the public domain.

Name change from tip/450.tip to tip/450.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

TIP:		450
Title:	Add [binary] subcommand "set" for in-place modification
Version:	$Revision: 1.1 $
Author:		Arjen Markus <[email protected]>
State:		Draft
Type:		Project
Vote:		Pending
Created:	18-Jul-2016
Post-History: 
Tcl-Version:	8.7
Keywords:	Tcl, binary data


~ Abstract

This TIP proposes a simpler extension of the [binary] command than the related
[418], namely just a subcommand '''set''' that updates an existing byte array
in a variable instead of creating a new one like '''binary format'''. It does
not propose an extension of the various formatting codes.

~ Rationale

As already argued in [418], the '''binary''' command is efficient in creating
new objects of binary data or in parsing existing objects with such data. It
is not currently efficient in ''updating'' existing objects. However, such
data objects are commonly used by compiled extensions.

As a consequence, if you want to manipulate such data objects from Tcl
directly, it is easier to parse the object into, say, a list of numbers, use
list commands like '''lset''' to replace individual values and pack it into a
new binary array before passing it to a compiled extension.

~ Specification

This TIP proposes to add a subcommand '''set''' to the '''binary''' command
with the following signature:

 > '''binary set''' ''varName formatString arg1 arg2 arg3 ...''

The effect of this subcommand is that the byte array data contained in the
variable "varName" is updated in a manner analogous to '''lset''', but using a
format string like '''binary format'''. It could be implemented in Tcl as:

 > set varName [binary format "a*$formatString" $varName $arg1 $arg2 $arg3 ...]

except that this allocates a new block of memory, sets that to null, copies
the contents of ''varName'' into that new block and then does the update.

The new command will have the effect that the first few steps are not
necessary anymore.

~ Implementation Notes

Besides the nominal case of a variable that contains a binary array that is to
be updated within the bounds of that array, three other cases exist and need
to be prepared for:

 * The variable varName does not exist yet

 * The variable varName does not contain a binary array

 * The updating would go past the memory allocated for the binary array

Each of these cases and perhaps others will have to be taken care of. The
first case might be treated as if '''binary format''' was meant. For the
second case the implementation can convert the current value.

The third case might either cause an error (we are updating an existing block
of memory after all) or silently extend the memory, effectively performing
what the Tcl implementation shown above would do. If an error is thrown, then
the first case should probably throw an error as well.

~ Reference Implementation

To be committed to a fossil branch.

A few remarks:

 * The third case is not completely treated yet (see "TODO" in the code)

 * The '''binary set''' command does not properly invalidate the string
   representation. The binary array is, however, updated properly - at least
   according to the very limited tests that were performed.

 * There are no proper test cases yet.

 * There is no proper performance measurement yet; this could be based
   on Wiki page http://wiki.tcl.tk/44363.

 * It does not deal with the possibility that the binary array is shared.

~ Copyright

This document is placed in public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|
|


|

|

|




|


|

|


|


|
|




|




|












|


|
|



|





|

|






|



|


>

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

# TIP 450: Add [binary] subcommand "set" for in-place modification

	Author:		Arjen Markus <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		Pending
	Created:	18-Jul-2016
	Post-History: 
	Tcl-Version:	8.7
	Keywords:	Tcl, binary data
-----

# Abstract

This TIP proposes a simpler extension of the [binary] command than the related
[[418]](418.md), namely just a subcommand **set** that updates an existing byte array
in a variable instead of creating a new one like **binary format**. It does
not propose an extension of the various formatting codes.

# Rationale

As already argued in [[418]](418.md), the **binary** command is efficient in creating
new objects of binary data or in parsing existing objects with such data. It
is not currently efficient in _updating_ existing objects. However, such
data objects are commonly used by compiled extensions.

As a consequence, if you want to manipulate such data objects from Tcl
directly, it is easier to parse the object into, say, a list of numbers, use
list commands like **lset** to replace individual values and pack it into a
new binary array before passing it to a compiled extension.

# Specification

This TIP proposes to add a subcommand **set** to the **binary** command
with the following signature:

 > **binary set** _varName formatString arg1 arg2 arg3 ..._

The effect of this subcommand is that the byte array data contained in the
variable "varName" is updated in a manner analogous to **lset**, but using a
format string like **binary format**. It could be implemented in Tcl as:

 > set varName [binary format "a*$formatString" $varName $arg1 $arg2 $arg3 ...]

except that this allocates a new block of memory, sets that to null, copies
the contents of _varName_ into that new block and then does the update.

The new command will have the effect that the first few steps are not
necessary anymore.

# Implementation Notes

Besides the nominal case of a variable that contains a binary array that is to
be updated within the bounds of that array, three other cases exist and need
to be prepared for:

 * The variable varName does not exist yet

 * The variable varName does not contain a binary array

 * The updating would go past the memory allocated for the binary array

Each of these cases and perhaps others will have to be taken care of. The
first case might be treated as if **binary format** was meant. For the
second case the implementation can convert the current value.

The third case might either cause an error \(we are updating an existing block
of memory after all\) or silently extend the memory, effectively performing
what the Tcl implementation shown above would do. If an error is thrown, then
the first case should probably throw an error as well.

# Reference Implementation

To be committed to a fossil branch.

A few remarks:

 * The third case is not completely treated yet \(see "TODO" in the code\)

 * The **binary set** command does not properly invalidate the string
   representation. The binary array is, however, updated properly - at least
   according to the very limited tests that were performed.

 * There are no proper test cases yet.

 * There is no proper performance measurement yet; this could be based
   on Wiki page <http://wiki.tcl.tk/44363.>

 * It does not deal with the possibility that the binary array is shared.

# Copyright

This document is placed in public domain.

Name change from tip/451.tip to tip/451.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

TIP:            451
Title:          Modify [update] to Give Full Script Access to Tcl_DoOneEvent
Version:        $Revision: 1.2 $
Author:         Colin McCormack <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        10-Aug-2016
Post-History:   
Keywords:       Tcl,event loop
Tcl-Version:    8.7


~ Abstract

This TIP add flags to '''update''' to represent all the flag values available
to the underlying API, ''Tcl_DoOneEvent()'', exposing them to script access.

~ Rationale

The '''update''' command provides a way into the event loop in addition to '''vwait'''.  Because the Tcl event system derived historically from Tk, '''update''' was written specifically to support Tk's window and idle events.
When Tcl adopted the event system for timers and file events, the '''update''' command was anomalously not updated to cater for these new event types.

The reason this anomaly is worth correcting is that Tcl_DoOneEvent is the actual entry into the event loop and there is no good or sufficient reason for '''update''' to limit the flags to those specific to Tk only.

While '''vwait''' provides a reasonable way into and out of the event loop, there's no good reason to impose that communication mechanism on the application when there are other approaches possible, arguably more useful, and amply provided for by the underlying C implementation.

~ Proposal

The '''update''' command should have the following flags added to it:

 * '''idletasks''' - process any pending window events or idle events, do not wait (this is as currently supported)

 * '''window''' - process window events

 * '''file''' - process file events

 * '''timer''' - process timer events

 * '''onlyidle''' - process only idle events

 * '''all''' - process all events

 * '''wait''' - wait until at least one event has been processed

 * '''nowait''' - return immediately if no events are pending.

 and they should be painted Pantone 13-1520

The somewhat klunky and denormalised logical form of these flags is imposed by the requirement to minimally disrupt existing '''update''' functionality.

~ Reference Implementation

A reference implementation is available in Tcl core fossil under tag
''updateextended''.

~ Use Case 1

Application of '''after idle''' constructs a collection of ''idle tasks.''  An ''idle task'' represents something to be performed when no events are pending.  This proposal exposes the idle state directly to a Tcl script and the application can do what it will in that state.

Use Case Summary: "I would like to handle ''idle tasks'' in some particular or specific order, at script level."

~ Use Case 2

A script may have accepted network file i/o for some time, and have a number of pending background (aka idle) tasks to perform as a result of that i/o.  It may wish to throttle acceptance of connections, or further read events, pending that background processing.

Use Case Summary: As a special case of "I would like direct control over my 'idle' time.", "I would like to throttle network input."

~ Rejected Alternatives

One could create a new command for this functionality, but the minimal impact
on most Tcl users doesn't seem to me to warrant additional population of the
:: command namespace.

One could move '''update''' out of Tcl altogether (to avoid its explicit dependency on Tk events) into Tk.  This would open up the :: namespace to a more general event-handling mechanism.

~ Copyright

This document has been placed in the public domain. In legislations where this
concept does not exist the CC0 license applies.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|

|

|
|

|

|

|

|

|

|

|

|

|

|

|

|



|

|


|

|

|

|

|

|



|





|

|



>

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

# TIP 451: Modify [update] to Give Full Script Access to Tcl_DoOneEvent

	Author:         Colin McCormack <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        10-Aug-2016
	Post-History:   
	Keywords:       Tcl,event loop
	Tcl-Version:    8.7
-----

# Abstract

This TIP add flags to **update** to represent all the flag values available
to the underlying API, _Tcl\_DoOneEvent\(\)_, exposing them to script access.

# Rationale

The **update** command provides a way into the event loop in addition to **vwait**.  Because the Tcl event system derived historically from Tk, **update** was written specifically to support Tk's window and idle events.
When Tcl adopted the event system for timers and file events, the **update** command was anomalously not updated to cater for these new event types.

The reason this anomaly is worth correcting is that Tcl\_DoOneEvent is the actual entry into the event loop and there is no good or sufficient reason for **update** to limit the flags to those specific to Tk only.

While **vwait** provides a reasonable way into and out of the event loop, there's no good reason to impose that communication mechanism on the application when there are other approaches possible, arguably more useful, and amply provided for by the underlying C implementation.

# Proposal

The **update** command should have the following flags added to it:

 * **idletasks** - process any pending window events or idle events, do not wait \(this is as currently supported\)

 * **window** - process window events

 * **file** - process file events

 * **timer** - process timer events

 * **onlyidle** - process only idle events

 * **all** - process all events

 * **wait** - wait until at least one event has been processed

 * **nowait** - return immediately if no events are pending.

 and they should be painted Pantone 13-1520

The somewhat klunky and denormalised logical form of these flags is imposed by the requirement to minimally disrupt existing **update** functionality.

# Reference Implementation

A reference implementation is available in Tcl core fossil under tag
_updateextended_.

# Use Case 1

Application of **after idle** constructs a collection of _idle tasks._  An _idle task_ represents something to be performed when no events are pending.  This proposal exposes the idle state directly to a Tcl script and the application can do what it will in that state.

Use Case Summary: "I would like to handle _idle tasks_ in some particular or specific order, at script level."

# Use Case 2

A script may have accepted network file i/o for some time, and have a number of pending background \(aka idle\) tasks to perform as a result of that i/o.  It may wish to throttle acceptance of connections, or further read events, pending that background processing.

Use Case Summary: As a special case of "I would like direct control over my 'idle' time.", "I would like to throttle network input."

# Rejected Alternatives

One could create a new command for this functionality, but the minimal impact
on most Tcl users doesn't seem to me to warrant additional population of the
:: command namespace.

One could move **update** out of Tcl altogether \(to avoid its explicit dependency on Tk events\) into Tk.  This would open up the :: namespace to a more general event-handling mechanism.

# Copyright

This document has been placed in the public domain. In legislations where this
concept does not exist the CC0 license applies.

Name change from tip/452.tip to tip/452.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

TIP:            452
Title:          Add "stubs" Package to or Along Side of TclTest
Version:        $Revision: 1.8 $
Author:         Gerald Lester <[email protected]>
Author:         Gerald W. Lester <[email protected]>
Author:         Gerald W. Lester <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        10-Aug-2016
Post-History:   
Tcl-Version:    8.6


~ Abstract

This TIP proposes an enhancement to the '''tcltest''' package to add support
for easy creation of test stubs, mocks and seams.

~ Rationale

The '''tcltest''' package allows for automated testing of Tcl code. However,
doing proper automated unit testing requires that the unit under test (i.e.,
the method or procedure) not invoke the actual implementation of other units,
but rather should invoke stub or mock units that are under the control of the
test being performed as to the results they return and any exceptions they
raise.

This TIP adds support for building these mechanisms, making it significantly
easier to create isolated unit tests of Tcl code.

~ Proposal

That a framework to easily create test stubs/mocks of
Tcl commands be added to the '''tcltest'' package.  Additionally, to facilitate the creation of automated test for legacy Tcl code.  Commands supporting ''test
seam'' creation and specification would also be included proposed package.

~~ Description

It provides a fully functional implementation of the
following commands:

 * '''::tcltest::TestSetup''' - Defines which procedures/commands are stubbed out
   and how they should behave for each invocation. This should only be called
   once per test.

 * '''::tcltest::AddStub''' - Adds a procedures/commands to the list that are
   stubbed out.

 * '''::tcltest::SaveVars''' - Saves the values of variables to be restored later.
   This should only be called once per test.

 * '''::tcltest::AddVars''' - Add a variable to the list of variables to be
   restored later

 * '''::tcltest::CallCount''' - Returns a dictionary sorted list of the stubbed
   out procedures and how many times they were called.

 * '''::tcltest::TestCleanup''' - Restores saved variables and stubbed out
   procedures.

 * '''::tcltest::SortedArrayData''' - Return the values of an array as a list of
   key-value pairs sorted by the keys.

 * '''::tcltest::CallProc''' - Call the real implementation of a stubbed out
   procedure.

 * '''::tcltest::Seam''' - Test seam definition and injection (aka enabling).  This command is available without requiring the tcltest package. 

~ Reference Implementation

See the tip-452 branch (http://core.tcl.tk/tcl/timeline?n=100&r=tip-452), in particular, see http-tip-452.test for an example of using the procedures added by this package.

~~ Origins of Reference Implementation

The reference implementation was done at SAP Labs, LLC (a subsidiary of SAP
Americal, Inc.) and approved for release as Open Source under a BSD license.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|

|
|
|







|


|
|

|




|



|


|


|


|


|


|


|


|

|

|

|

|
|

|


>

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

# TIP 452: Add "stubs" Package to or Along Side of TclTest

	Author:         Gerald Lester <[email protected]>
	Author:         Gerald W. Lester <[email protected]>
	Author:         Gerald W. Lester <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        10-Aug-2016
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes an enhancement to the **tcltest** package to add support
for easy creation of test stubs, mocks and seams.

# Rationale

The **tcltest** package allows for automated testing of Tcl code. However,
doing proper automated unit testing requires that the unit under test \(i.e.,
the method or procedure\) not invoke the actual implementation of other units,
but rather should invoke stub or mock units that are under the control of the
test being performed as to the results they return and any exceptions they
raise.

This TIP adds support for building these mechanisms, making it significantly
easier to create isolated unit tests of Tcl code.

# Proposal

That a framework to easily create test stubs/mocks of
Tcl commands be added to the **tcltest_ package.  Additionally, to facilitate the creation of automated test for legacy Tcl code.  Commands supporting _test
seam_ creation and specification would also be included proposed package.

## Description

It provides a fully functional implementation of the
following commands:

 * **::tcltest::TestSetup** - Defines which procedures/commands are stubbed out
   and how they should behave for each invocation. This should only be called
   once per test.

 * **::tcltest::AddStub** - Adds a procedures/commands to the list that are
   stubbed out.

 * **::tcltest::SaveVars** - Saves the values of variables to be restored later.
   This should only be called once per test.

 * **::tcltest::AddVars** - Add a variable to the list of variables to be
   restored later

 * **::tcltest::CallCount** - Returns a dictionary sorted list of the stubbed
   out procedures and how many times they were called.

 * **::tcltest::TestCleanup** - Restores saved variables and stubbed out
   procedures.

 * **::tcltest::SortedArrayData** - Return the values of an array as a list of
   key-value pairs sorted by the keys.

 * **::tcltest::CallProc** - Call the real implementation of a stubbed out
   procedure.

 * **::tcltest::Seam** - Test seam definition and injection \(aka enabling\).  This command is available without requiring the tcltest package. 

# Reference Implementation

See the tip-452 branch \(<http://core.tcl.tk/tcl/timeline?n=100&r=tip-452\),> in particular, see http-tip-452.test for an example of using the procedures added by this package.

## Origins of Reference Implementation

The reference implementation was done at SAP Labs, LLC \(a subsidiary of SAP
Americal, Inc.\) and approved for release as Open Source under a BSD license.

# Copyright

This document has been placed in the public domain.

Name change from tip/453.tip to tip/453.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
136

137
138
139
140
141
142
143
144
145
146
147
148


149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191

TIP:            453
Title:          Tcl Based Automation for tcl/pkgs
Version:        $Revision: 1.2 $
Author:         Sean Woods <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        13-Sep-2016
Post-History:   
Keywords:       Build tooling
Tcl-Version:    8.7


~ Abstract

This TIP proposes replacing the '''make package''' process currently employed
by the core with a Tcl-based build automation tool.

~ Background

[376] provides for the distribution of third party packages in the Tcl/Tk core
distributions. To support that TIP currently requires three separate build
automations: a Makefile based automation in Unix, and both an nmake and
Makefile based automation for Windows. These automation systems can get out of
sync and they assume that their job is to build dynamic libraries for local
installation.

~ The Pitch

By the time '''make packages''' has run, the local Tcl interpreter has been
built already. Rather than rely on delicate hacks and makefile tricks, core
distributed packages could be built and installed via exec commands inside a
Tcl script. In addition, this same automation could handle functions like
injecting a core distributed package into a virtual file system, as well as
bundling the Tcl/Tk library file system for [430].

~ The Implementation

For the ''practcl'' branch of tclconfig, I put together a 4000 line
self-contained package and kit building library of tools. This library is
TclOO based, and provides a rudimentary (but functional) system for templating
C code in Tcl, as well as a build system that is capable of nesting
sub-projects. It also steals the useful bits from the '''fileutil''' module of
tcllib, providing implementations for concatenating files, performing file
searches, and building a global package index from a soup of modules. The
library also has a wrapper to download external sources from fossil. It also
contains procs that can compile a static library, dynamic library, or self
contained shell directly from exec calls.

I would propose that this tool system (or a new creation by the community in a
similar spirit) be included in the library/ section of the tcl core. The
provisional name for this tool set would be '''practcl'''. A version of this
tool could also be provided in tcllib to allow 8.5 and 8.6 based cores to
continue to build extensions.

In the new scheme, '''make packages''' (in all its forms) would be replaced
with a call to "''$(TCLSH) ${srcdir}/pkgs/make.tcl build''". '''make
packages-install''' would be replaced by a call to "''$(TCLSH)
${srcdir}/pkgs/make.tcl install''". For advanced users, these toplevel commands
'''build''' and '''install''' will accept additional arguments. For instance,
to install the core distributed packages into the VFS of a kit: "''$(TCLSH)
${srcdir}/make.tcl install -destdir ${MyVFS}/lib''".

~ pkgs/make.tcl

'''make.tcl''' would be maintained as part of the core, and provide the
top-level control system to build, install, or repackage the core distributed
extensions. That script will also provide mechanisms to populate the pkgs file
system for developers who build the tcl core from fossil checkouts.

Commands:

 * '''basekit'''

 > Compile a ZipFs style basekit suitable for the '''wrap''' command.

 * '''build''' ?'''all'''? ?''package''? ?''package...''?

 > Compile the source code for core distributed packages into binary products
   (as applicable.) If '''all''' is given, an attempt is made to compile all
   packages under ''pkgs/''. Any other argument is interpreted to be the name
   of an individual package to be compiled.

 * '''install''' ?'''-destdir''' ''destinationpath''?

 > Install all core distributed packages locally. If '''-destdir''' is given,
   install the packages relative to ''destinationpath'' in the same way that
   "'''make DESTDIR=''' ''destdir''" would. If '''-destdir''' is not given, or
   is an empty string, perform an install relative to the '''exec_prefix''' in
   '''tclConfig.sh'''

 * '''wrap''' ''exename'' ''vfspath'' ?''dir...''?

 > Generate a self contained executable constructed from the virtual file
    system amalgamated from ''vfspath'' and any other directories given as
    arguments. This VFS will automatically be populated with the
    '''library/''' file system from Tcl.

 * '''distribution'''

> Download packages listed in the "packages.tcl" file, unpack their source 
    code in the /pkgs folder, and perform any steps required to prepare those
    extensions for inclusion in a core snapshot for distribution.

 * '''developer'''

> Download packages listed in the "packages.tcl" file, unpack their source 
    code in the parent folder to the one the core has been unpacked from,
    and perform any steps required to prepare those extensions to be compiled
    locally as part of a developer build. This is intended for developers who work
    from fossil checkouts of the Tcl core.

 * '''package-list'''

> Stream to stdout a list of all of the packages in the packages.tcl file, in a flat
    machine readable format.

~ Tk

This same mechanism will be adapted for Tk. Tk will be also provide a
'''pkgs/''' directory. Its base kits will be based on a modified ''wish''
instead of a modified ''tclsh''.

~ Normal Operation

During the build/install/etc phase each directory will be scanned for either
a "configure" file or a "prac.tcl" file. Standard TEA extensions will be detected
by the presence of a "configure" file. The prac.tcl file is a hint to the build
system that the package needs either additional instructions and guidance.
The contents of the file are interpreted by the object which is implementing the
extension's ambassador to the build system.

If one were to decide to bundle tcllib, and wished to exercise its SAK based installer
the prac.tcl file would read:

|# Implement the install routine for tcllib
|#

|oo::objdefine [self] {
|  method install DEST {
|    set pkg [my define get pkg_name [my define get name]]
|    my unpack
|    set prefix [string trimleft [my <project> define get prefix] /] 
|    set srcdir [my define get srcdir]
|    ::practcl::dotclexec [file join $srcdir installer.tcl] \
|      -pkg-path [file join $DEST $prefix lib $pkg] \ -no-examples -no-html -no-nroff \
|      -no-wait -no-gui -no-apps
|  }
|}



~ Maintaining the Package List

Each '''pkgs/''' file system for both Tcl and Tk will also contain a file
'''packages.tcl'''. This file will be human and machine readable. It contains
a description of every core distributed package, where the sources can be
found, as well as which fossil tags can be utilized as either development or
release with this particular version of the core.

'''packages.txt''' contains a series of keywords populating a data structure.

A simple example would by the tclconfig templates from TEA:

|EXTENSION tclconfig {
|   tag  trunk
|   fossil_url http://core.tcl.tk/tclconfig
|}


The EXTENSION keyword is intended to take the following arguments:

 > ''name'' ''key/value-configuration-dict''

~~Reserved keys

~~~tag
Source code management tag for the release bundled with this edition of the core

~~~fossil_url
If the extension is managed via fossil, a url that can be fed to "fossil clone". If no tag is specified "trunk" is assumed.

~~~git_url
If the extension is managed via git, a url that can be fed to "git clone". If no tag is specified "HEAD" is assumed

~~~file_url
If the extension is only available via source snapshot, a url where the file can be downloaded. 
Supported formats are .tar.gz and .zip.

The list is kept separate from the actual '''make.tcl''' so that users can simply
steal the list for making "batteries included" distributions. It also allows the package list
to remain distinct for each branch of the core.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|






|

|




|

|

|

|

|






|
|
|



|
|
|
|
|
|
|

|

|






|

|

|

|
|
|


|

|
|
|
|
|

|

|
|

|

|

|



|

|





|

|


|


|
|

|











|
<
>
|
|
|
|
|
|
|
|
|
<
<
|
>
>
|

|
|




|



|
|
|
<
>



|

|

|


|


|


|



|



|


>

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
136
137
138
139
140
141
142
143
144


145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191

# TIP 453: Tcl Based Automation for tcl/pkgs

	Author:         Sean Woods <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        13-Sep-2016
	Post-History:   
	Keywords:       Build tooling
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes replacing the **make package** process currently employed
by the core with a Tcl-based build automation tool.

# Background

[[376]](376.md) provides for the distribution of third party packages in the Tcl/Tk core
distributions. To support that TIP currently requires three separate build
automations: a Makefile based automation in Unix, and both an nmake and
Makefile based automation for Windows. These automation systems can get out of
sync and they assume that their job is to build dynamic libraries for local
installation.

# The Pitch

By the time **make packages** has run, the local Tcl interpreter has been
built already. Rather than rely on delicate hacks and makefile tricks, core
distributed packages could be built and installed via exec commands inside a
Tcl script. In addition, this same automation could handle functions like
injecting a core distributed package into a virtual file system, as well as
bundling the Tcl/Tk library file system for [[430]](430.md).

# The Implementation

For the _practcl_ branch of tclconfig, I put together a 4000 line
self-contained package and kit building library of tools. This library is
TclOO based, and provides a rudimentary \(but functional\) system for templating
C code in Tcl, as well as a build system that is capable of nesting
sub-projects. It also steals the useful bits from the **fileutil** module of
tcllib, providing implementations for concatenating files, performing file
searches, and building a global package index from a soup of modules. The
library also has a wrapper to download external sources from fossil. It also
contains procs that can compile a static library, dynamic library, or self
contained shell directly from exec calls.

I would propose that this tool system \(or a new creation by the community in a
similar spirit\) be included in the library/ section of the tcl core. The
provisional name for this tool set would be **practcl**. A version of this
tool could also be provided in tcllib to allow 8.5 and 8.6 based cores to
continue to build extensions.

In the new scheme, **make packages** \(in all its forms\) would be replaced
with a call to "_$\(TCLSH\) $\{srcdir\}/pkgs/make.tcl build_". **make
packages-install** would be replaced by a call to "_$\(TCLSH\)
$\{srcdir\}/pkgs/make.tcl install_". For advanced users, these toplevel commands
**build** and **install** will accept additional arguments. For instance,
to install the core distributed packages into the VFS of a kit: "_$\(TCLSH\)
$\{srcdir\}/make.tcl install -destdir $\{MyVFS\}/lib_".

# pkgs/make.tcl

**make.tcl** would be maintained as part of the core, and provide the
top-level control system to build, install, or repackage the core distributed
extensions. That script will also provide mechanisms to populate the pkgs file
system for developers who build the tcl core from fossil checkouts.

Commands:

 * **basekit**

	 > Compile a ZipFs style basekit suitable for the **wrap** command.

 * **build** ?**all**? ?_package_? ?_package..._?

	 > Compile the source code for core distributed packages into binary products
   \(as applicable.\) If **all** is given, an attempt is made to compile all
   packages under _pkgs/_. Any other argument is interpreted to be the name
   of an individual package to be compiled.

 * **install** ?**-destdir** _destinationpath_?

	 > Install all core distributed packages locally. If **-destdir** is given,
   install the packages relative to _destinationpath_ in the same way that
   "**make DESTDIR=** _destdir_" would. If **-destdir** is not given, or
   is an empty string, perform an install relative to the **exec\_prefix** in
   **tclConfig.sh**

 * **wrap** _exename_ _vfspath_ ?_dir..._?

	 > Generate a self contained executable constructed from the virtual file
    system amalgamated from _vfspath_ and any other directories given as
    arguments. This VFS will automatically be populated with the
    **library/** file system from Tcl.

 * **distribution**

	> Download packages listed in the "packages.tcl" file, unpack their source 
    code in the /pkgs folder, and perform any steps required to prepare those
    extensions for inclusion in a core snapshot for distribution.

 * **developer**

	> Download packages listed in the "packages.tcl" file, unpack their source 
    code in the parent folder to the one the core has been unpacked from,
    and perform any steps required to prepare those extensions to be compiled
    locally as part of a developer build. This is intended for developers who work
    from fossil checkouts of the Tcl core.

 * **package-list**

	> Stream to stdout a list of all of the packages in the packages.tcl file, in a flat
    machine readable format.

# Tk

This same mechanism will be adapted for Tk. Tk will be also provide a
**pkgs/** directory. Its base kits will be based on a modified _wish_
instead of a modified _tclsh_.

# Normal Operation

During the build/install/etc phase each directory will be scanned for either
a "configure" file or a "prac.tcl" file. Standard TEA extensions will be detected
by the presence of a "configure" file. The prac.tcl file is a hint to the build
system that the package needs either additional instructions and guidance.
The contents of the file are interpreted by the object which is implementing the
extension's ambassador to the build system.

If one were to decide to bundle tcllib, and wished to exercise its SAK based installer
the prac.tcl file would read:

	# Implement the install routine for tcllib

	#
	oo::objdefine [self] {
	  method install DEST {
	    set pkg [my define get pkg_name [my define get name]]
	    my unpack
	    set prefix [string trimleft [my <project> define get prefix] /] 
	    set srcdir [my define get srcdir]
	    ::practcl::dotclexec [file join $srcdir installer.tcl] \
	      -pkg-path [file join $DEST $prefix lib $pkg] \ -no-examples -no-html -no-nroff \
	      -no-wait -no-gui -no-apps


	  }
	}

# Maintaining the Package List

Each **pkgs/** file system for both Tcl and Tk will also contain a file
**packages.tcl**. This file will be human and machine readable. It contains
a description of every core distributed package, where the sources can be
found, as well as which fossil tags can be utilized as either development or
release with this particular version of the core.

**packages.txt** contains a series of keywords populating a data structure.

A simple example would by the tclconfig templates from TEA:

	EXTENSION tclconfig {
	   tag  trunk
	   fossil_url http://core.tcl.tk/tclconfig

	}

The EXTENSION keyword is intended to take the following arguments:

 > _name_ _key/value-configuration-dict_

## Reserved keys

### tag
Source code management tag for the release bundled with this edition of the core

### fossil\_url
If the extension is managed via fossil, a url that can be fed to "fossil clone". If no tag is specified "trunk" is assumed.

### git\_url
If the extension is managed via git, a url that can be fed to "git clone". If no tag is specified "HEAD" is assumed

### file\_url
If the extension is only available via source snapshot, a url where the file can be downloaded. 
Supported formats are .tar.gz and .zip.

The list is kept separate from the actual **make.tcl** so that users can simply
steal the list for making "batteries included" distributions. It also allows the package list
to remain distinct for each branch of the core.

# Copyright

This document has been placed in the public domain.

Name change from tip/454.tip to tip/454.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

TIP:            454
Title:          Automatically Resize Frames After Last Child Removed
Version:        $Revision: 1.19 $
Author:         Harald Oehlmann <[email protected]>
Author:         Harald Oehlmann <[email protected]>
Author:         Francois Vogel <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        21-Sep-2016
Post-History:   
Keywords:       Tk
Tcl-Version:    8.6.6


~ Abstract

A '''frame'''-like widget has 1x1 required size if created.
If children are added by pack/grid and the last children is unpacked/grid, the frame-like widget does not return to the 1x1 required size.
Instead, it keeps the size of the last packed item.
It should automatically or under control resize to the initial requested size of 1x1.

~ Rationale

A '''frame''' keeping a size without reason just feels like a bug and mostly leads to unwanted results.

Mostly, it looks just ugly, but there are critical use-cases, specially in scrolled frames.

When the BWidget autoscroll package is used, which displays scrollbars on demand, the scrollbars do not disappear if the contents is gone.
And there is nothing, a programmer can do, as the Configure event does not fire on the scrolled frame widget.

Another example is the scrolledwindow example by Emiliano in ticket 2863003fff [https://core.tcl.tk/tk/info/12006979562649c9], where the solution 2 specific part may be removed (or is ignored).

A typical workaround is to configure the width/height manually after the last children was unmapped.
Unfortunately, this fact may not be determined for example by scrolling widgets etc. An eventual Configure binding is not firing.

~ Example

Here is an example to ilustrate the issue.
It consisting of a simple scrolling megawidget.
The megawidget exposes a frame where a user may pack or grid other widgets and the scrollbar is adjusted following the changing content.
This works well when widgets are added or removed. Only removing the last client will not update the scrollbar. With the proposed patch applied, it will update the scrollbar also when the last user widget is removed.

Please paste the code below to a wish console or execute it.
On startup it shows on the console:
|requested frame height: 1

Then press the "+" button to add a user widget. The console output is:
|+

|requested frame height: 100
Technically, the frame ".c.f.i1" was packed into the client frame ".c.f".
The client frame ".c.f" changes its requested size to hold the new child, which invokes the Convigure event and adjustes the scrolling region of the canvas.
The new scrolling region is shown graphically by the scrollbar.

Then press the "-" button to remove the user widget. The console output is:
|-

So, the child widget ".c.f.i1" is destroyed, but the frame ".c.f" does not rechange its requested size to 1x1 (initial value) but stays at 100x100 showing an empty plane.
The scrollbar is not updated and the megawidget has no possibility to adjust that (expect additional user action to inform that the last child was removed).

One may also try to add two childs and to remove them. It gets clear, that the widget is resized on removel if it is not the last widget.

With the proposed patch applied, the removal of the last widget would restore the initial frame size of 1x1 which would invoke the Configure event and the scrollbar would be adjusted.

|wm geometry . 90x90
|# Button to add box on scrolling canvas
|set itemNo 0
|pack [button .b1 -command newBox -text +] -side left -fill y
|proc newBox {} {
|    puts +
|    incr ::itemNo
|    pack  [frame .c.f.i$::itemNo -borderwidth 4 -relief raised -bg red -width 100 -height 100] -side top
|}

|# Button to remove box on scrolling canvas
|pack [button .b2 -command removeBox -text -] -side left -fill y
|proc removeBox {} {
|    puts -
|    if {$::itemNo == 0} {return}
|    destroy .c.f.i$::itemNo
|    incr ::itemNo -1
|}

|
|# This is the scrolling megawidget which exposes frame .c.f for users to pack or grid clients
|# It has no knowledge, when the user adds or removes clients, e.g. when +/- is pressed
|pack [scrollbar .s -command {.c yview}] -side right -fill y
|pack [canvas .c -borderwidth 0 -yscrollcommand {.s set}] -side left -fill both
|frame .c.f
|.c create window 0 0 -window .c.f -anchor nw -tags win
|proc frameConfigure {} {
|    set y [winfo reqheight .c.f]
|    puts "requested frame height: $y"
|    .c configure -scrollregion [list 0 0 100 $y]
|}

|frameConfigure
|bind .c.f <Configure> frameConfigure

~ Proposal

The proposal is to change request size of the frame automatically to 1x1 if the last children is unpacked/ungridded/destroyed.

Koen Dankart has passed a patch for this solution containing 3 additional lines of C code.
It is available in branch bug-d6b95ce492-alt: [http://core.tcl.tk/tk/timeline?r=bug-d6b95ce492-alt&nd&c=2016-09-22+09%3A16%3A21&n=200].

It just solves the issue by restoring initial size if the last children is unpacked/ungridded.

This is not backward compatible.
But that is a side effect of fixing this bug.

~ Rejected Proposal

Another proposal is to invoke the virtual event <<GeometryManager>> when the last children is unpacked/ungridded/destroyed.

Emiliano has provided a ticket 2863003fff [https://core.tcl.tk/tk/info/2863003fff] with the implementation in branch bug-d6b95ce492 [https://core.tcl.tk/tk/timeline?r=bug-d6b95ce492&nd&c=2016-09-21+06%3A32%3A55&n=200]:

The virtual event '''<<GeometryManager>>''' is defined which informs the master (a frame-like widget) that it has no child widget any more and that its size is not managed any more by grid/pack.

The program may bind to this event and resize to size 1x1:

|   bind .c <<GeometryManager>> "resizeFrame %W"
|   proc resizeFrame w {
|      $w configure -height 1 -width 1
|      $w configure -height 0 -width 0
|   }


Discussion:

   *   Backward compatible, no visual change to present code

   *   Requires additional code to fix the bug (auto-resizing to 1x1)

   *   The information of the last size is preserved and may be queried by the script (winfo reqheight)

   *   Other sizes may be set on this event

   *   May extend the first solution, maybe in another TIP.

   *   May be emulated by a Configure event and some code, if the first solution is used.

   *   Feels like a workaround to me.

~ Voted as yes and withdrawn due to implementation and compatibility issues

The TIP was voted yes. (only this section was added after voting)

Nevertheless, it was withdrawn due to the following compatibility issues:

   *   flickering

Moen wrote on the core list on 2016-10-26 18:53:

I have to say though that I'm getting less sure about this TIP. I found some comments in the code indicating that the old behaviour was not so much a design choice, but rather an implementation issue. Specifically, this comment in tkGrid.c:1735.

|    /*
|     * If the master has no slaves anymore, then don't do anything at all:
|     * just leave the master's size as-is. Otherwise there is no way to
|     * "relinquish" control over the master so another geometry manager can
|     * take over.
|     */

The current patch for TIP 454 bypasses this by doing the Tk_GeometryRequest() immediately instead of at idle time. The result is that another geometry manager can still take over, but it introduces some flickering (collapse + expand):

|  pack [text .t]
|  pack forget .t; grid .t
|  grid forget .t; pack .t

   *   Additional Configure

The patch introduces an additional Configure event where applications may not be aware of.
Brian worte on 2016-10-26 19:46:

It turns out that this "flicker" is also what is causing our tests to hang.  Our UI is a complex set of nested and tabbed panes where the implementation that manages the panes relies on a complex dance of <Configure>, <Map> and <Unmap> events to make the right things happen.  The consequence of adding one more <Configure> event is causing a hang at a [tkwait visibility $win] where $win never appears.  $win is a single child in a frame that is unmanaged and (re)managed based on various conditions.

The hang is easily solved, but that means that the behavior is different.  (the difference is not right or wrong, just different*)  This difference is also demonstrated in the textWind failures.  It could be asserted that these tk tests are confirming that the comment in the tkGrid.c has been faithfully implemented.

I cannot write just one piece of code that works in both 8.6.6 and 8.6.7.  I contend that this sort of thing is forbidden in a minor patch release, and questionable in a major patch relase (e.g. 8.7).  I'm struggling with this, but I think this kind of change might have to be deferred to 9.0.

*: the change in our code means removing some code.  From a perspective of "less is more", the patch is "better".

Due to those issues, the TIP is withdrawn.
A way to solve the issue in a compatible and working way is to use Emilianos additional virtual event, as described in the section 'rejected alternatives'.

~ Additional information and examples

   *   frame wiki page http://wiki.tcl.tk/frame

   *   Tk bug ticket [https://core.tcl.tk/tk/info/d6b95ce49207c823]

   *   Discussion on the core list [http://code.activestate.com/lists/tcl-core/16363/]

~ Compatibility

Fixing the issue breaks visual compatibility.  Nevertheless, as it is seen as a bug, this is OK.

~ Reference Implementation

Reference implementations are mentioned in the solution sections.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|




|

|






|




|








|

|
<
>
|





<
>
|
|





|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|

|




|






|



|

|



|
|
|
|
<
>





|

|









|

|









|
|
|
|
|
|

|

|
|
|






|

|

|






|

|

|

|

|



|



|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

# TIP 454: Automatically Resize Frames After Last Child Removed

	Author:         Harald Oehlmann <[email protected]>
	Author:         Harald Oehlmann <[email protected]>
	Author:         Francois Vogel <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        21-Sep-2016
	Post-History:   
	Keywords:       Tk
	Tcl-Version:    8.6.6
-----

# Abstract

A **frame**-like widget has 1x1 required size if created.
If children are added by pack/grid and the last children is unpacked/grid, the frame-like widget does not return to the 1x1 required size.
Instead, it keeps the size of the last packed item.
It should automatically or under control resize to the initial requested size of 1x1.

# Rationale

A **frame** keeping a size without reason just feels like a bug and mostly leads to unwanted results.

Mostly, it looks just ugly, but there are critical use-cases, specially in scrolled frames.

When the BWidget autoscroll package is used, which displays scrollbars on demand, the scrollbars do not disappear if the contents is gone.
And there is nothing, a programmer can do, as the Configure event does not fire on the scrolled frame widget.

Another example is the scrolledwindow example by Emiliano in ticket 2863003fff <https://core.tcl.tk/tk/info/12006979562649c9> , where the solution 2 specific part may be removed \(or is ignored\).

A typical workaround is to configure the width/height manually after the last children was unmapped.
Unfortunately, this fact may not be determined for example by scrolling widgets etc. An eventual Configure binding is not firing.

# Example

Here is an example to ilustrate the issue.
It consisting of a simple scrolling megawidget.
The megawidget exposes a frame where a user may pack or grid other widgets and the scrollbar is adjusted following the changing content.
This works well when widgets are added or removed. Only removing the last client will not update the scrollbar. With the proposed patch applied, it will update the scrollbar also when the last user widget is removed.

Please paste the code below to a wish console or execute it.
On startup it shows on the console:
	requested frame height: 1

Then press the "\+" button to add a user widget. The console output is:

	+
	requested frame height: 100
Technically, the frame ".c.f.i1" was packed into the client frame ".c.f".
The client frame ".c.f" changes its requested size to hold the new child, which invokes the Convigure event and adjustes the scrolling region of the canvas.
The new scrolling region is shown graphically by the scrollbar.

Then press the "-" button to remove the user widget. The console output is:

	-
So, the child widget ".c.f.i1" is destroyed, but the frame ".c.f" does not rechange its requested size to 1x1 \(initial value\) but stays at 100x100 showing an empty plane.
The scrollbar is not updated and the megawidget has no possibility to adjust that \(expect additional user action to inform that the last child was removed\).

One may also try to add two childs and to remove them. It gets clear, that the widget is resized on removel if it is not the last widget.

With the proposed patch applied, the removal of the last widget would restore the initial frame size of 1x1 which would invoke the Configure event and the scrollbar would be adjusted.

	wm geometry . 90x90
	# Button to add box on scrolling canvas
	set itemNo 0
	pack [button .b1 -command newBox -text +] -side left -fill y
	proc newBox {} {
	    puts +
	    incr ::itemNo
	    pack  [frame .c.f.i$::itemNo -borderwidth 4 -relief raised -bg red -width 100 -height 100] -side top

	}
	# Button to remove box on scrolling canvas
	pack [button .b2 -command removeBox -text -] -side left -fill y
	proc removeBox {} {
	    puts -
	    if {$::itemNo == 0} {return}
	    destroy .c.f.i$::itemNo
	    incr ::itemNo -1

	}
	
	# This is the scrolling megawidget which exposes frame .c.f for users to pack or grid clients
	# It has no knowledge, when the user adds or removes clients, e.g. when +/- is pressed
	pack [scrollbar .s -command {.c yview}] -side right -fill y
	pack [canvas .c -borderwidth 0 -yscrollcommand {.s set}] -side left -fill both
	frame .c.f
	.c create window 0 0 -window .c.f -anchor nw -tags win
	proc frameConfigure {} {
	    set y [winfo reqheight .c.f]
	    puts "requested frame height: $y"
	    .c configure -scrollregion [list 0 0 100 $y]

	}
	frameConfigure
	bind .c.f <Configure> frameConfigure

# Proposal

The proposal is to change request size of the frame automatically to 1x1 if the last children is unpacked/ungridded/destroyed.

Koen Dankart has passed a patch for this solution containing 3 additional lines of C code.
It is available in branch bug-d6b95ce492-alt: <http://core.tcl.tk/tk/timeline?r=bug-d6b95ce492-alt&nd&c=2016-09-22+09%3A16%3A21&n=200> .

It just solves the issue by restoring initial size if the last children is unpacked/ungridded.

This is not backward compatible.
But that is a side effect of fixing this bug.

# Rejected Proposal

Another proposal is to invoke the virtual event <<GeometryManager>> when the last children is unpacked/ungridded/destroyed.

Emiliano has provided a ticket 2863003fff <https://core.tcl.tk/tk/info/2863003fff>  with the implementation in branch bug-d6b95ce492 <https://core.tcl.tk/tk/timeline?r=bug-d6b95ce492&nd&c=2016-09-21+06%3A32%3A55&n=200> :

The virtual event **<<GeometryManager>>** is defined which informs the master \(a frame-like widget\) that it has no child widget any more and that its size is not managed any more by grid/pack.

The program may bind to this event and resize to size 1x1:

	   bind .c <<GeometryManager>> "resizeFrame %W"
	   proc resizeFrame w {
	      $w configure -height 1 -width 1
	      $w configure -height 0 -width 0

	   }

Discussion:

   *   Backward compatible, no visual change to present code

   *   Requires additional code to fix the bug \(auto-resizing to 1x1\)

   *   The information of the last size is preserved and may be queried by the script \(winfo reqheight\)

   *   Other sizes may be set on this event

   *   May extend the first solution, maybe in another TIP.

   *   May be emulated by a Configure event and some code, if the first solution is used.

   *   Feels like a workaround to me.

# Voted as yes and withdrawn due to implementation and compatibility issues

The TIP was voted yes. \(only this section was added after voting\)

Nevertheless, it was withdrawn due to the following compatibility issues:

   *   flickering

Moen wrote on the core list on 2016-10-26 18:53:

I have to say though that I'm getting less sure about this TIP. I found some comments in the code indicating that the old behaviour was not so much a design choice, but rather an implementation issue. Specifically, this comment in tkGrid.c:1735.

	    /*
	     * If the master has no slaves anymore, then don't do anything at all:
	     * just leave the master's size as-is. Otherwise there is no way to
	     * "relinquish" control over the master so another geometry manager can
	     * take over.
	     */

The current patch for TIP 454 bypasses this by doing the Tk\_GeometryRequest\(\) immediately instead of at idle time. The result is that another geometry manager can still take over, but it introduces some flickering \(collapse \+ expand\):

	  pack [text .t]
	  pack forget .t; grid .t
	  grid forget .t; pack .t

   *   Additional Configure

The patch introduces an additional Configure event where applications may not be aware of.
Brian worte on 2016-10-26 19:46:

It turns out that this "flicker" is also what is causing our tests to hang.  Our UI is a complex set of nested and tabbed panes where the implementation that manages the panes relies on a complex dance of <Configure>, <Map> and <Unmap> events to make the right things happen.  The consequence of adding one more <Configure> event is causing a hang at a [tkwait visibility $win] where $win never appears.  $win is a single child in a frame that is unmanaged and \(re\)managed based on various conditions.

The hang is easily solved, but that means that the behavior is different.  \(the difference is not right or wrong, just different\*\)  This difference is also demonstrated in the textWind failures.  It could be asserted that these tk tests are confirming that the comment in the tkGrid.c has been faithfully implemented.

I cannot write just one piece of code that works in both 8.6.6 and 8.6.7.  I contend that this sort of thing is forbidden in a minor patch release, and questionable in a major patch relase \(e.g. 8.7\).  I'm struggling with this, but I think this kind of change might have to be deferred to 9.0.

*: the change in our code means removing some code.  From a perspective of "less is more", the patch is "better".

Due to those issues, the TIP is withdrawn.
A way to solve the issue in a compatible and working way is to use Emilianos additional virtual event, as described in the section 'rejected alternatives'.

# Additional information and examples

   *   frame wiki page <http://wiki.tcl.tk/frame>

   *   Tk bug ticket <https://core.tcl.tk/tk/info/d6b95ce49207c823> 

   *   Discussion on the core list <http://code.activestate.com/lists/tcl-core/16363/> 

# Compatibility

Fixing the issue breaks visual compatibility.  Nevertheless, as it is seen as a bug, this is OK.

# Reference Implementation

Reference implementations are mentioned in the solution sections.

# Copyright

This document has been placed in the public domain.

Name change from tip/455.tip to tip/455.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

TIP:	455
Title:	 Extensions to [vwait]: Variable Sets and Scripted Access to Tcl_DoOneEvent
Version:	$Revision: 1.2 $
Author:	Christian Werner <[email protected]>
State:	Draft
Type:	Project
Tcl-Version:	8.7
Vote:	Pending
Created:	07-Oct-2016
Keywords:	Tcl, event loop
Post-History: 


~ Abstract

This TIP generalizes the '''vwait''' command to allow waiting on zero, one, or
more variable changes, on zero or more file events, to time-limit the wait,
and to control on which kinds of events is to be waited by partially exposing
the underlying API, namely ''Tcl_DoOneEvent()''.

~ Rationale

One remarkable property of Tcl is the ability to add traces, i.e., the
execution of callback functions, on certain operations affecting variables.
The '''vwait''' command combines the variable trace facility with the (a)
event loop, i.e., the (a) program main loop waiting and processing various
types of events generated by I/O channels, time, and internal activities of
the running Tcl program.

The current implementation of '''vwait''' allows to open an unconstrained
event loop which is terminated by writing or unsetting exactly one global
variable given as argument to '''vwait'''.

This proposal extends '''vwait''' to terminate its event loop on occurence of

 1. zero or more variable modifications

 2. readability/writability of zero or more file channels (usually sockets)

 3. an optional timeout specified as milliseconds as in the '''after'''
    command.

Additional flags to '''vwait''' control which types of events are to be dealt
with in its event loop, i.e. the underlying ''Tcl_DoOneEvent()'' API.

When more than one kind of active input (both, variables and file channels) is
involved in an instance of '''vwait''', another flag controls if any one of
the inputs or all inputs must have been activated in order to terminate the
event loop. This allows for scenarios, where '''vwait''' can be used as a kind
of "barrier" getting broken if all required conditions are fulfilled, i.e.,
axe, saw, spade, fire accelerant, water, in order to demolish, burn down,
extinct the glow, and finally bury the trellis-work fence.

However, in contrast to the illustrious demolition job, the order of occurence
of events breaking that "barrier" is indeterminate.

If the '''vwait''' is constrained by a timeout, and the time limit is reached,
its event loop terminates early and '''vwait''' indicates that timeout by a
negative integer result. Otherwise, the return value is the remaining number
of milliseconds (positive integer which can be zero) of the timeout
constraint. This property combined with [302] allows to implement (soft
real-time) control loops.

~ Proposal

The '''vwait''' command shall have the following signature:

 > '''vwait''' ''variable-name'' - well known and implemented behaviour

 > '''vwait''' ''options'' ?''variable-names''? - all available enhanced
    features; more than one variable name may be given, in which case the wait
    will terminate when any of the variables are written to (unless the
    '''-all''' option below is given)

where ''options'' are:

  --:                              indicates end of options

  -all:                            all (except timeout) conditions must be met

  -nofileevents:                   don't consider file events

  -noidleevents:                   don't consider idle events

  -notimerevents:                  don't consider timer events

  -nowindowevents:                 don't consider window system events

  -readable <chan>:                ''<chan>'' becomes readable

  -timeout <ms>: timeout in milliseconds; return the estimated number of
    milliseconds remaining in the wait.

  -writable <chan>:                ''<chan>'' becomes writable

The return value of '''vwait''' shall be the empty string except when the
'''-timeout''' option is in effect (see above).

Where the combination of options doesn't make sense, or even conflicts, an
appropriate error message shall be thrown, e.g., '''-timeout''' and
'''-notimerevents''' can't be specified at the same time.

If all event types except idle events are excluded, the event loop
(''Tcl_DoOneEvent'') shall be constrained by '''TCL_DONT_WAIT'''.

Interesting analogies to the '''update''' command can be infered: '''vwait
--''' is equivalent to '''update''', '''vwait -nofileevents -notimerevents
-nowindoevents''' is equivalent to '''update idletasks'''.

~ Copyright

This document has been placed in the public domain. In legislations where this
concept does not exist the CC0 license applies.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|



|
|



|

|

|



|

|


|
|

|
|

|







|
|

|
|
|

|

|

|

|

|
|

|



|









|




|

|
|


|
|


|

|
|
|

|



>

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

# TIP 455: Extensions to [vwait]: Variable Sets and Scripted Access to Tcl_DoOneEvent

	Author:	Christian Werner <[email protected]>
	State:	Draft
	Type:	Project
	Tcl-Version:	8.7
	Vote:	Pending
	Created:	07-Oct-2016
	Keywords:	Tcl, event loop
	Post-History: 
-----

# Abstract

This TIP generalizes the **vwait** command to allow waiting on zero, one, or
more variable changes, on zero or more file events, to time-limit the wait,
and to control on which kinds of events is to be waited by partially exposing
the underlying API, namely _Tcl\_DoOneEvent\(\)_.

# Rationale

One remarkable property of Tcl is the ability to add traces, i.e., the
execution of callback functions, on certain operations affecting variables.
The **vwait** command combines the variable trace facility with the \(a\)
event loop, i.e., the \(a\) program main loop waiting and processing various
types of events generated by I/O channels, time, and internal activities of
the running Tcl program.

The current implementation of **vwait** allows to open an unconstrained
event loop which is terminated by writing or unsetting exactly one global
variable given as argument to **vwait**.

This proposal extends **vwait** to terminate its event loop on occurence of

 1. zero or more variable modifications

 2. readability/writability of zero or more file channels \(usually sockets\)

 3. an optional timeout specified as milliseconds as in the **after**
    command.

Additional flags to **vwait** control which types of events are to be dealt
with in its event loop, i.e. the underlying _Tcl\_DoOneEvent\(\)_ API.

When more than one kind of active input \(both, variables and file channels\) is
involved in an instance of **vwait**, another flag controls if any one of
the inputs or all inputs must have been activated in order to terminate the
event loop. This allows for scenarios, where **vwait** can be used as a kind
of "barrier" getting broken if all required conditions are fulfilled, i.e.,
axe, saw, spade, fire accelerant, water, in order to demolish, burn down,
extinct the glow, and finally bury the trellis-work fence.

However, in contrast to the illustrious demolition job, the order of occurence
of events breaking that "barrier" is indeterminate.

If the **vwait** is constrained by a timeout, and the time limit is reached,
its event loop terminates early and **vwait** indicates that timeout by a
negative integer result. Otherwise, the return value is the remaining number
of milliseconds \(positive integer which can be zero\) of the timeout
constraint. This property combined with [[302]](302.md) allows to implement \(soft
real-time\) control loops.

# Proposal

The **vwait** command shall have the following signature:

 > **vwait** _variable-name_ - well known and implemented behaviour

 > **vwait** _options_ ?_variable-names_? - all available enhanced
    features; more than one variable name may be given, in which case the wait
    will terminate when any of the variables are written to \(unless the
    **-all** option below is given\)

where _options_ are:

  --:                              indicates end of options

  -all:                            all \(except timeout\) conditions must be met

  -nofileevents:                   don't consider file events

  -noidleevents:                   don't consider idle events

  -notimerevents:                  don't consider timer events

  -nowindowevents:                 don't consider window system events

  -readable <chan>:                _<chan>_ becomes readable

  -timeout <ms>: timeout in milliseconds; return the estimated number of
    milliseconds remaining in the wait.

  -writable <chan>:                _<chan>_ becomes writable

The return value of **vwait** shall be the empty string except when the
**-timeout** option is in effect \(see above\).

Where the combination of options doesn't make sense, or even conflicts, an
appropriate error message shall be thrown, e.g., **-timeout** and
**-notimerevents** can't be specified at the same time.

If all event types except idle events are excluded, the event loop
\(_Tcl\_DoOneEvent_\) shall be constrained by **TCL\_DONT\_WAIT**.

Interesting analogies to the **update** command can be infered: **vwait
--** is equivalent to **update**, **vwait -nofileevents -notimerevents
-nowindoevents** is equivalent to **update idletasks**.

# Copyright

This document has been placed in the public domain. In legislations where this
concept does not exist the CC0 license applies.

Name change from tip/456.tip to tip/456.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

TIP:            456
Title:          Extend the C API to Support Passing Options to TCP Server Creation
Version:        $Revision: 1.6 $
Author:         LemonBoy <[email protected]>
Author:         lime boy <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        18-Nov-2016
Post-History:   
Keywords:       Tcl,socket,SO_REUSEPORT,SO_REUSEADDR
Tcl-Version:    8.7


~ Abstract

The '''Tcl_OpenTcpServer''' interface doesn't provide enough flexibility as
experienced during the implementation of the scaffolding necessary to support
the '''SO_REUSEPORT''' flag for sockets. This TIP adds that capability through
a new API function, '''Tcl_OpenTcpServerEx''', that takes extra options.

~ Rationale

Currently there's no way to pass extra informations to '''Tcl_OpenTcpServer'''
which is the function that does the heavy lifting by wrapping the socket
creation and connection phase.

For example, during the implementation of a '''-reuseport''' option for the
'''socket''' command, a roadblock was hit since informing
'''Tcl_OpenTcpServer''' about the presence of the new flag was only possible
via hacks such as exploiting the upper unused bits of the port parameter or
its sign bit.

A clean solution that also paves the way to the implementation of other
switches (such as one for the SO_REUSEADDR flag) is to introduce another
function named '''Tcl_OpenTcpServerEx''' whose signature closely matches the
'''Tcl_OpenTcpServer''' but allows passing a set of flags to customize its
behaviour.

Following the aforementioned changes to the C API the '''socket''' command is
enhanced with two new options allowing the user to take advantage of the newly
introduced flags.

~ Specification

A '''Tcl_OpenTcpServerEx''' function is introduced with the following
signature:

 > Tcl_Channel '''Tcl_OpenTcpServerEx'''(Tcl_Interp *''interp'', const char *
    ''service'', const char *''myHost'', unsigned int ''flags'', 
    Tcl_TcpAcceptProc *''acceptProc'', ClientData ''acceptProcData'')

Most arguments are identical to '''Tcl_OpenTcpServer''' with the exception of
the ''port'' parameter being replaced by the ''service'' one taking a string
instead of an integer.  Two entries for the ''flags'' bitset are defined by this 
TIP:

 * '''TCL_TCPSERVER_REUSEADDR''' - indicate that the socket flag SO_REUSEADDR (or
   equivalent) should be set.

 * '''TCL_TCPSERVER_REUSEPORT''' - indicate that the socket flag SO_REUSEPORT (or
   equivalent) should be set.

The '''Tcl_OpenTcpServer''' function is then rewritten to be an alias of
'''Tcl_OpenTcpServerEx''' with the '''flags''' parameter set by default to
TCL_TCPSERVER_REUSEADDR so that we keep the API and behaviour compatible with the
previous Tcl versions.

As for the Tcl side, the '''socket''' command gains two new optional switches
that are only valid for server sockets: '''?-reuseaddr boolean?''' and
'''?-reuseport boolean?''', both accepting a boolean argument to either turn off
or on the selected behaviour.

~ Reference Implementation

Please refer to the ''tip-456'' branch of the core Tcl repository.

~ Backwards Compatibility

Since '''Tcl_OpenTcpServer''' can be easily re-implemented in terms of 
'''Tcl_OpenTcpServerEx''' the old behaviour is retained.

The '''socket''' command defaults to '''-reuseaddr''' set to ''yes'' as it was
already doing before, the user is now able to turn off this behaviour by using
'''-reuseaddr no'''.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|

|
|

|

|



|
|
|




|
|
|


|



|

|


|
|
|

|
|
|


|
|

|
|

|
|
|


|
|
|


|

|

|

|
|

|

|

|


>

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

# TIP 456: Extend the C API to Support Passing Options to TCP Server Creation

	Author:         LemonBoy <[email protected]>
	Author:         lime boy <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        18-Nov-2016
	Post-History:   
	Keywords:       Tcl,socket,SO_REUSEPORT,SO_REUSEADDR
	Tcl-Version:    8.7
-----

# Abstract

The **Tcl\_OpenTcpServer** interface doesn't provide enough flexibility as
experienced during the implementation of the scaffolding necessary to support
the **SO\_REUSEPORT** flag for sockets. This TIP adds that capability through
a new API function, **Tcl\_OpenTcpServerEx**, that takes extra options.

# Rationale

Currently there's no way to pass extra informations to **Tcl\_OpenTcpServer**
which is the function that does the heavy lifting by wrapping the socket
creation and connection phase.

For example, during the implementation of a **-reuseport** option for the
**socket** command, a roadblock was hit since informing
**Tcl\_OpenTcpServer** about the presence of the new flag was only possible
via hacks such as exploiting the upper unused bits of the port parameter or
its sign bit.

A clean solution that also paves the way to the implementation of other
switches \(such as one for the SO\_REUSEADDR flag\) is to introduce another
function named **Tcl\_OpenTcpServerEx** whose signature closely matches the
**Tcl\_OpenTcpServer** but allows passing a set of flags to customize its
behaviour.

Following the aforementioned changes to the C API the **socket** command is
enhanced with two new options allowing the user to take advantage of the newly
introduced flags.

# Specification

A **Tcl\_OpenTcpServerEx** function is introduced with the following
signature:

 > Tcl\_Channel **Tcl\_OpenTcpServerEx**\(Tcl\_Interp \*_interp_, const char \*
    _service_, const char \*_myHost_, unsigned int _flags_, 
    Tcl\_TcpAcceptProc \*_acceptProc_, ClientData _acceptProcData_\)

Most arguments are identical to **Tcl\_OpenTcpServer** with the exception of
the _port_ parameter being replaced by the _service_ one taking a string
instead of an integer.  Two entries for the _flags_ bitset are defined by this 
TIP:

 * **TCL\_TCPSERVER\_REUSEADDR** - indicate that the socket flag SO\_REUSEADDR \(or
   equivalent\) should be set.

 * **TCL\_TCPSERVER\_REUSEPORT** - indicate that the socket flag SO\_REUSEPORT \(or
   equivalent\) should be set.

The **Tcl\_OpenTcpServer** function is then rewritten to be an alias of
**Tcl\_OpenTcpServerEx** with the **flags** parameter set by default to
TCL\_TCPSERVER\_REUSEADDR so that we keep the API and behaviour compatible with the
previous Tcl versions.

As for the Tcl side, the **socket** command gains two new optional switches
that are only valid for server sockets: **?-reuseaddr boolean?** and
**?-reuseport boolean?**, both accepting a boolean argument to either turn off
or on the selected behaviour.

# Reference Implementation

Please refer to the _tip-456_ branch of the core Tcl repository.

# Backwards Compatibility

Since **Tcl\_OpenTcpServer** can be easily re-implemented in terms of 
**Tcl\_OpenTcpServerEx** the old behaviour is retained.

The **socket** command defaults to **-reuseaddr** set to _yes_ as it was
already doing before, the user is now able to turn off this behaviour by using
**-reuseaddr no**.

# Copyright

This document has been placed in the public domain.

Name change from tip/457.tip to tip/457.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396

TIP:            457
Title:          Add Support for Named Arguments
Version:        $Revision: 1.22 $
Author:         Mathieu Lafon <[email protected]>
Author:         Andreas Leitgeb <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        21-Nov-2016
Post-History:   
Keywords:       Tcl,procedure,argument handling
Tcl-Version:    8.7


~ Abstract

This TIP proposes an enhancement of the Tcl language to support named
arguments and additional features when calling a procedure.

~ Rationale

The naming of arguments to procedures is a computer language feature which
allow developers to specify the name of an argument when calling a function.
This is especially useful when dealing with arguments with default values, as
this does not require to specify all previous arguments when only one argument
is required to be specified.

As such, this is a commonly requested feature by Tcl developers, who have
created various code snippets [http://wiki.tcl.tk/10702] to simulate it. These
snippets have drawbacks: not intuitive for new users, require to add extra
code at the start of each procedure, no standard on the format to use, few
errors handling, etc.

After discussing various possibilities with the community, it has been
decided to extend the argument specification of the ''proc'' command
and allow users to define options on arguments. This can be used to
support named arguments but also add additional enhancements:
flag arguments, pass-by-name (''upvar'') arguments, non-required
arguments, ...

The others possibilities discussed are detailed in the ''Discussion''
section at the end of the document.

~ Specification

The ''proc'' documentation currently define argument specifiers as a list
of one or two fields where the first field is the name of the argument and
the optional second field is its default value.

The proposed modification is to support an alternate specifier format where
the first field is also the name of the argument, followed by a paired list
of options and their values. This format does not prevent the original format
to be used as they can be easily distinguished: the new format uses an
odd size list with a minimal size of three fields.

~~ Available argument specifiers

The following argument specifiers are defined in this TIP:

 * '''-default VALUE''' defines the default value for the argument.
   It is ignored if ''-required 1'' is also used.

|% proc p { { a -default {} } } { list a $a }
|% p
|a {}
|% p foo
|a foo

 * '''-name NAME''' defines the argument to be a named argument.
   NAME defines the name of the argument when it is  defined as a
   single string. If NAME is a list of strings, it is the list of
   names that can be used to refer to the argument (i.e. aliases).
   On the call-site, the name of the argument is prefixed by a single dash
   and followed by the value.

|% proc p1 { { v -name val } } { list v $v }
|% p1 -val 1
|v 1

|% proc p2 { { v -name {v val value} } } { list v $v }
|% p2 -value 2
|v 2
|% p2 -v 2
|v 2

 * '''-switch SWITCHES''' defines that the argument is defined on the
   call-site as a flag-only/switch parameter. SWITCHES is a list of
   possible switches. Each switch is defined either as a single string
   (switch name) or as a list of two entries (switch name and related
   value). On the call-site, the name of the switch is prefixed by a
   single dash and is not followed by any value. The value assigned to
   the argument is either the switch name or the related value depending
   on how it was defined.

|% proc p { { dbg -default 0 -switch debug } } { list dbg $dbg }
|% p
|dbg 0
|% p -debug
|dbg debug

|% proc p { { level -switch {{quiet 0} {verbose 9}} } { list level $level }
|% p -quiet
|level 0
|% p -verbose
|level 9

 * '''-required BOOLEAN''' defines that the value is required to be set.
   If set to true, the argument is required and any default  value is
   ignored. It is the default handling for non-named argument without a
   default value. If set to false, the argument is not required to be set
   and the related argument will be left unset if there is no default value.
   It is the default  handling for named argument.  

|% proc p { { v -required 0 }  } {
|    if {[info exist v]} {list v $v} {return "v is unset"}
|  }

|% p 5
|v 5
|% p
|v is unset

 * '''-upvar LEVEL''' defines, that the local argument will become an
   alias to the variable in the frame at level LEVEL corresponding to
   the parameter value. This is similar to what is achieved when using
   the ''upvar'' command.
   This  specifier is incompatible with the ''-switch'' specifier.

|% proc p { { v -upvar 1 } } { incr v }
|% set a 2
|2

|% p a
|3

|% set a
|3


Further argument specifiers may be added in future TIP. Examples of
new argument specifiers which may be added in the future:

 * type assertion ('''-assume TYPE''')

 * argument documentation ('''-docstring DOC''')

 * ...

~~ Named arguments

The following rules define how named arguments are expected to be specified
on the call-site:

 * Named arguments must always be specified using their name, they can't be
   specified as positional arguments.

|% proc p { {a -name A} } { list a $a }
|% p aa
|wrong # args: should be "p |-A a|"
|% p -A aa
|a aa

 * When several names (using ''-name'' or ''-switch'' options) are
   specified for the same argument, only one is required to be used on
   the call-site, unless a default value is also specified. If more than
   one is used, the latest value/switch is kept.

|% proc p { { v -name {v val} } } { list v $v }
|% p -v 6 -val 8
|v 8

 * Both ''-name'' and ''-switch'' specifiers can be used on the same
   argument.

|% proc p { { level -name level -switch {{quiet 0} {verbose 9}} } {
|    list level $level
|  }

|% p -level 4
|level 4
|% p -verbose
|level 9

 * A group of contiguous named arguments are handled together and are not
   required to be specified in the same order as defined.

|% proc p { {a -name A} {b -name B} } { list a $a b $b }
|% p -B bb -A aa
|% a aa b bb

 * The handling of a group of contiguous named arguments (which can be
   only one argument) is ended on the first argument which is either
   a parameter not starting with a dash or the special ''--'' end-of-options
   marker. Remaining arguments will then be assigned to following positional
   arguments.

|% proc p { {o -name opt} args } { list o $o args $args }
|% p -opt O 5
|o O args 5
|% p -opt O -1 0
|wrong # args: should be "p |-opt o| ?arg ...?"
|% p -opt O -- -1 0
|o O args {-1 0}

 * If there is a fixed number of non-optional positional arguments and no
   special ''args'' variable after the named group, the handling of a named
   group will also be ended when the remaining arguments to assign
   will be equal to the number of positional arguments after the group.

|% proc p { {o -name opt} posarg } { list o $o posarg $posarg }
|% p -opt O -1
|o O posarg -1

~~ Generated usage description

The error message, automatically generated when the input arguments are
invalid, is updated regarding new options:

 * Pass-by-name arguments (specified using ''-upvar level'' option) are
   surrounded by the '&' character.

|% proc p { { v -upvar 1 } } { }
|% p
|wrong # args: should be "p &v&"

 * Named arguments are showed how they should be called and surounded
   by the '|' character. If several names have been specified,
   they are grouped together.

|% proc p { { l -name level -switch {high low} -required 1} } {}
|% p
|wrong # args: should be "p |-level l|-high|-low|"

 * When an argument is optional, '?' is used.

|% proc p { { v -name var } a } {}
|% p
|wrong # args: should be "p ?|-var v|? a"

~~ Introspection

The ''info argspec proc'' command is added to get the argument specification
of all arguments or of a specific argument.

|% proc p { a { b 1 } { c -name c } } {}
|% info argspec proc p
|a { b -default 1 } { c -name c }
|% info argspec proc p c
|-name c

Similar ''info argspec'' subcommands are also added for lambda, object
method and object constructor.

The ''info argspec specifiers'' command is added to get the specifiers 
supported by the current interpreter.

|% info argspec specifiers
|-default -name -required -switch -upvar

~~ Other use cases

Extended argument specifiers can also be used with other ''proc''-like
functions. The following functions are supported and can use extended
argument specifiers:

 * anonymous functions (lambda), used with ''apply'' command ;

 * TclOO constructor or methods.

~~ Performance

The proposed modification has no significant performance impact:

 * existing code (and code not using extended argspec) is not impacted
   by the change as the current initialisation code is still available
   and used ;

 * code using extended argspec ''may'' be impacted because the
   initialisation code is different and is required to loop on each
   argument, but initial testing does not show a significant slowdown.

When using named arguments specifiers to replace a similar handling done
in Tcl-pure code, there is however a significant increase in performance.

See [https://gist.github.com/mlafon/70480877a28f3571e0377eabc0cee7be]
for details on performance testing done on the proposed implementation.

~ Implementation

This document proposes the following changes to the Tcl core:

 1. Add ExtendedArgSpec structure which is linked from CompiledLocal
    and contains information about extended argument specification;

 2. Add a flags field in the Proc structure to later identify a proc
    with at least one argument defined with an extended argument
    specification (PROC_HAS_EXT_ARG_SPEC);

 3. Update proc creation to handle the extended argument specification
    and fill the ExtendedArgSpec structure;

 4. Update InitArgsAndLocals to initialize the compiled locals using
    a dedicated function if the PROC_HAS_EXT_ARG_SPEC flag has been
    set on the proc. If unset, the original initialization code is
    still used.

 5. Update ProcWrongNumArgs to generate an appropriate error message
    when an argument has been defined using an extended argument
    specification;

 6. Add ''info argspec'' command;

 7. Update documentation in doc/proc.n and doc/info.n;

 8. Update impacted tests and add dedicated tests in tests/proc-enh.test.

~~ Reference Implementation

The reference implementation is available in the tip-457
[http://core.tcl.tk/tcl/timeline?r=tip-457] branch.

The code is licensed under the BSD license.

~ Discussion

This section details some of the alternate solutions for this feature or
specific comments about it.

Initial approaches that tried to work with unmodified procedures are
not detailed here for clarity.

~~ Dedicated builtin command

A dedicated command can be used to handle the named arguments, using an
''-option value'' syntax, before calling the target procedures with all
arguments correctly prepared.

|% call -opts myproc -optC foo -optB {5 5} -- "some pos arg"

An implementation of this proposal is available at
[https://github.com/mlafon/tcl/tree/457-CALL-CMD]. This proposal was
abandoned as it was not enough intuitive for users.

~~ Modification in how proc are defined

Tcl-pure procedures can be defined in a way which state that the procedure
will automatically handle ''-option value'' arguments.

|% proc -np myproc { varA { optB defB } { optC defC } { optD defD } args } { .. }
|% myproc -optC foo -optB {5 5} -- "some pos arg"

An other possibility is to support options on arguments and allow name
specification:

|% proc myproc { varA { optB -default defB -name B } args } { .. }
|% myproc a -B b zz

This is the currently proposed solution in this TIP. It requires the
procedures to be modified but allow additional features.

Some people have expressed concern about the modification of the ''proc''
command, which is a core command of Tcl. A particular attention has been paid
to ensure that existing code will not be impacted and that future usage could
be later added by adding new specifiers.

~~ Argument Parsing command

Cyan Ogilvie's paper from Tcl2016
[https://www.tcl.tk/community/tcl2016/assets/talk33/parse_args-paper.pdf]
describes a C extension to provide core-like argument parsing at speed
comparable to ''proc'' argument handling, in a terse and self-documenting
way.

Alexandre Ferrieux has proposed
[http://code.activestate.com/lists/tcl-core/18447/] to use the same
argument specifiers than this proposal, but with a dedicated command which
can be called from the proc body. This has the advantage to not alter the
''proc'' command and could be located in an extension.

Although the ''proc'' usage will not be modified, this new command will
probably have to access or modify internal proc structures, for example
to support introspection.

Having to declare final local variables in the body, also seems confusing
for users.

~~ Preventing Data-dependent bugs

It has been proposed by Christian Gollwitzer
[http://code.activestate.com/lists/tcl-core/18457/] to make the special '--'
end-of-options marker mandatory when the number of positional arguments after
the named group is not fixed. This would suppress any potential Data-Dependent
bugs related to the search of the initial dash and remove any unwanted object
stringification, at the expense of forcing the user to explicitely use
the end-of-option marker.

This proposal is currently not implemented but the documentation has been
modified to list the cases for which '--' should be use.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|




|








|





|


|


|


|

|









|



|
|

|
|
|
|
|

|


|



|
|
|

|
|
|
|
|

|


|
|




|
|
|
|
|

|
|
|
|
|

|






|
|
<
>
|
|
|
|

|


|
|

|
|
<
>
|
<
>
|
<
>




|

|



|







|
|
|
|
|

|




|
|
|

|


|
|
<
>
|
|
|
|




|
|
|

|
|
|



|
|
|
|
|
|
|


|



|
|
|

|




|


|
|
|


|


|
|
|



|
|
|

|

|


|
|
|
|
|

|


|


|
|

|

|



|



|



|



|






|


|








|





|







|





|


|



|







|


|


|


|


|


|

|
|




|
|




|




|


|

|



|


|

|






|


|









|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170

171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396

# TIP 457: Add Support for Named Arguments

	Author:         Mathieu Lafon <[email protected]>
	Author:         Andreas Leitgeb <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        21-Nov-2016
	Post-History:   
	Keywords:       Tcl,procedure,argument handling
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes an enhancement of the Tcl language to support named
arguments and additional features when calling a procedure.

# Rationale

The naming of arguments to procedures is a computer language feature which
allow developers to specify the name of an argument when calling a function.
This is especially useful when dealing with arguments with default values, as
this does not require to specify all previous arguments when only one argument
is required to be specified.

As such, this is a commonly requested feature by Tcl developers, who have
created various code snippets <http://wiki.tcl.tk/10702>  to simulate it. These
snippets have drawbacks: not intuitive for new users, require to add extra
code at the start of each procedure, no standard on the format to use, few
errors handling, etc.

After discussing various possibilities with the community, it has been
decided to extend the argument specification of the _proc_ command
and allow users to define options on arguments. This can be used to
support named arguments but also add additional enhancements:
flag arguments, pass-by-name \(_upvar_\) arguments, non-required
arguments, ...

The others possibilities discussed are detailed in the _Discussion_
section at the end of the document.

# Specification

The _proc_ documentation currently define argument specifiers as a list
of one or two fields where the first field is the name of the argument and
the optional second field is its default value.

The proposed modification is to support an alternate specifier format where
the first field is also the name of the argument, followed by a paired list
of options and their values. This format does not prevent the original format
to be used as they can be easily distinguished: the new format uses an
odd size list with a minimal size of three fields.

## Available argument specifiers

The following argument specifiers are defined in this TIP:

 * **-default VALUE** defines the default value for the argument.
   It is ignored if _-required 1_ is also used.

		% proc p { { a -default {} } } { list a $a }
		% p
		a {}
		% p foo
		a foo

 * **-name NAME** defines the argument to be a named argument.
   NAME defines the name of the argument when it is  defined as a
   single string. If NAME is a list of strings, it is the list of
   names that can be used to refer to the argument \(i.e. aliases\).
   On the call-site, the name of the argument is prefixed by a single dash
   and followed by the value.

		% proc p1 { { v -name val } } { list v $v }
		% p1 -val 1
		v 1

		% proc p2 { { v -name {v val value} } } { list v $v }
		% p2 -value 2
		v 2
		% p2 -v 2
		v 2

 * **-switch SWITCHES** defines that the argument is defined on the
   call-site as a flag-only/switch parameter. SWITCHES is a list of
   possible switches. Each switch is defined either as a single string
   \(switch name\) or as a list of two entries \(switch name and related
   value\). On the call-site, the name of the switch is prefixed by a
   single dash and is not followed by any value. The value assigned to
   the argument is either the switch name or the related value depending
   on how it was defined.

		% proc p { { dbg -default 0 -switch debug } } { list dbg $dbg }
		% p
		dbg 0
		% p -debug
		dbg debug

		% proc p { { level -switch {{quiet 0} {verbose 9}} } { list level $level }
		% p -quiet
		level 0
		% p -verbose
		level 9

 * **-required BOOLEAN** defines that the value is required to be set.
   If set to true, the argument is required and any default  value is
   ignored. It is the default handling for non-named argument without a
   default value. If set to false, the argument is not required to be set
   and the related argument will be left unset if there is no default value.
   It is the default  handling for named argument.  

		% proc p { { v -required 0 }  } {
		    if {[info exist v]} {list v $v} {return "v is unset"}

		  }
		% p 5
		v 5
		% p
		v is unset

 * **-upvar LEVEL** defines, that the local argument will become an
   alias to the variable in the frame at level LEVEL corresponding to
   the parameter value. This is similar to what is achieved when using
   the _upvar_ command.
   This  specifier is incompatible with the _-switch_ specifier.

		% proc p { { v -upvar 1 } } { incr v }
		% set a 2

		2
		% p a

		3
		% set a

		3

Further argument specifiers may be added in future TIP. Examples of
new argument specifiers which may be added in the future:

 * type assertion \(**-assume TYPE**\)

 * argument documentation \(**-docstring DOC**\)

 * ...

## Named arguments

The following rules define how named arguments are expected to be specified
on the call-site:

 * Named arguments must always be specified using their name, they can't be
   specified as positional arguments.

		% proc p { {a -name A} } { list a $a }
		% p aa
		wrong # args: should be "p |-A a|"
		% p -A aa
		a aa

 * When several names \(using _-name_ or _-switch_ options\) are
   specified for the same argument, only one is required to be used on
   the call-site, unless a default value is also specified. If more than
   one is used, the latest value/switch is kept.

		% proc p { { v -name {v val} } } { list v $v }
		% p -v 6 -val 8
		v 8

 * Both _-name_ and _-switch_ specifiers can be used on the same
   argument.

		% proc p { { level -name level -switch {{quiet 0} {verbose 9}} } {
		    list level $level

		  }
		% p -level 4
		level 4
		% p -verbose
		level 9

 * A group of contiguous named arguments are handled together and are not
   required to be specified in the same order as defined.

		% proc p { {a -name A} {b -name B} } { list a $a b $b }
		% p -B bb -A aa
		% a aa b bb

 * The handling of a group of contiguous named arguments \(which can be
   only one argument\) is ended on the first argument which is either
   a parameter not starting with a dash or the special _--_ end-of-options
   marker. Remaining arguments will then be assigned to following positional
   arguments.

		% proc p { {o -name opt} args } { list o $o args $args }
		% p -opt O 5
		o O args 5
		% p -opt O -1 0
		wrong # args: should be "p |-opt o| ?arg ...?"
		% p -opt O -- -1 0
		o O args {-1 0}

 * If there is a fixed number of non-optional positional arguments and no
   special _args_ variable after the named group, the handling of a named
   group will also be ended when the remaining arguments to assign
   will be equal to the number of positional arguments after the group.

		% proc p { {o -name opt} posarg } { list o $o posarg $posarg }
		% p -opt O -1
		o O posarg -1

## Generated usage description

The error message, automatically generated when the input arguments are
invalid, is updated regarding new options:

 * Pass-by-name arguments \(specified using _-upvar level_ option\) are
   surrounded by the '&' character.

		% proc p { { v -upvar 1 } } { }
		% p
		wrong # args: should be "p &v&"

 * Named arguments are showed how they should be called and surounded
   by the '\|' character. If several names have been specified,
   they are grouped together.

		% proc p { { l -name level -switch {high low} -required 1} } {}
		% p
		wrong # args: should be "p |-level l|-high|-low|"

 * When an argument is optional, '?' is used.

		% proc p { { v -name var } a } {}
		% p
		wrong # args: should be "p ?|-var v|? a"

## Introspection

The _info argspec proc_ command is added to get the argument specification
of all arguments or of a specific argument.

	% proc p { a { b 1 } { c -name c } } {}
	% info argspec proc p
	a { b -default 1 } { c -name c }
	% info argspec proc p c
	-name c

Similar _info argspec_ subcommands are also added for lambda, object
method and object constructor.

The _info argspec specifiers_ command is added to get the specifiers 
supported by the current interpreter.

	% info argspec specifiers
	-default -name -required -switch -upvar

## Other use cases

Extended argument specifiers can also be used with other _proc_-like
functions. The following functions are supported and can use extended
argument specifiers:

 * anonymous functions \(lambda\), used with _apply_ command ;

 * TclOO constructor or methods.

## Performance

The proposed modification has no significant performance impact:

 * existing code \(and code not using extended argspec\) is not impacted
   by the change as the current initialisation code is still available
   and used ;

 * code using extended argspec _may_ be impacted because the
   initialisation code is different and is required to loop on each
   argument, but initial testing does not show a significant slowdown.

When using named arguments specifiers to replace a similar handling done
in Tcl-pure code, there is however a significant increase in performance.

See <https://gist.github.com/mlafon/70480877a28f3571e0377eabc0cee7be> 
for details on performance testing done on the proposed implementation.

# Implementation

This document proposes the following changes to the Tcl core:

 1. Add ExtendedArgSpec structure which is linked from CompiledLocal
    and contains information about extended argument specification;

 2. Add a flags field in the Proc structure to later identify a proc
    with at least one argument defined with an extended argument
    specification \(PROC\_HAS\_EXT\_ARG\_SPEC\);

 3. Update proc creation to handle the extended argument specification
    and fill the ExtendedArgSpec structure;

 4. Update InitArgsAndLocals to initialize the compiled locals using
    a dedicated function if the PROC\_HAS\_EXT\_ARG\_SPEC flag has been
    set on the proc. If unset, the original initialization code is
    still used.

 5. Update ProcWrongNumArgs to generate an appropriate error message
    when an argument has been defined using an extended argument
    specification;

 6. Add _info argspec_ command;

 7. Update documentation in doc/proc.n and doc/info.n;

 8. Update impacted tests and add dedicated tests in tests/proc-enh.test.

## Reference Implementation

The reference implementation is available in the tip-457
<http://core.tcl.tk/tcl/timeline?r=tip-457>  branch.

The code is licensed under the BSD license.

# Discussion

This section details some of the alternate solutions for this feature or
specific comments about it.

Initial approaches that tried to work with unmodified procedures are
not detailed here for clarity.

## Dedicated builtin command

A dedicated command can be used to handle the named arguments, using an
_-option value_ syntax, before calling the target procedures with all
arguments correctly prepared.

	% call -opts myproc -optC foo -optB {5 5} -- "some pos arg"

An implementation of this proposal is available at
<https://github.com/mlafon/tcl/tree/457-CALL-CMD> . This proposal was
abandoned as it was not enough intuitive for users.

## Modification in how proc are defined

Tcl-pure procedures can be defined in a way which state that the procedure
will automatically handle _-option value_ arguments.

	% proc -np myproc { varA { optB defB } { optC defC } { optD defD } args } { .. }
	% myproc -optC foo -optB {5 5} -- "some pos arg"

An other possibility is to support options on arguments and allow name
specification:

	% proc myproc { varA { optB -default defB -name B } args } { .. }
	% myproc a -B b zz

This is the currently proposed solution in this TIP. It requires the
procedures to be modified but allow additional features.

Some people have expressed concern about the modification of the _proc_
command, which is a core command of Tcl. A particular attention has been paid
to ensure that existing code will not be impacted and that future usage could
be later added by adding new specifiers.

## Argument Parsing command

Cyan Ogilvie's paper from Tcl2016
<https://www.tcl.tk/community/tcl2016/assets/talk33/parse_args-paper.pdf> 
describes a C extension to provide core-like argument parsing at speed
comparable to _proc_ argument handling, in a terse and self-documenting
way.

Alexandre Ferrieux has proposed
<http://code.activestate.com/lists/tcl-core/18447/>  to use the same
argument specifiers than this proposal, but with a dedicated command which
can be called from the proc body. This has the advantage to not alter the
_proc_ command and could be located in an extension.

Although the _proc_ usage will not be modified, this new command will
probably have to access or modify internal proc structures, for example
to support introspection.

Having to declare final local variables in the body, also seems confusing
for users.

## Preventing Data-dependent bugs

It has been proposed by Christian Gollwitzer
<http://code.activestate.com/lists/tcl-core/18457/>  to make the special '--'
end-of-options marker mandatory when the number of positional arguments after
the named group is not fixed. This would suppress any potential Data-Dependent
bugs related to the search of the initial dash and remove any unwanted object
stringification, at the expense of forcing the user to explicitely use
the end-of-option marker.

This proposal is currently not implemented but the documentation has been
modified to list the cases for which '--' should be use.

# Copyright

This document has been placed in the public domain.

Name change from tip/458.tip to tip/458.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

TIP:            458
Title:          Add Support for epoll() and kqueue() in the Notifier
Version:        $Revision: 1.6 $
Author:         Lucio Andr�s Illanes Albornoz <[email protected]>
Author:         Lucio Andr�s Illanes Albornoz <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        24-Nov-2016
Post-History:   
Keywords:       event loop,scalability
Tcl-Version:    8.7


~ Abstract

This TIP proposes to replace ''select''(2) in the notifier implementation with ''epoll''(7) and ''kqueue''(2) on Linux and DragonFly-, Free-, Net-, and OpenBSD respectively. This is to remove a major bottleneck in the ability of Tcl to scale up to thousands and tens of thousands of sockets (aka '''C10K''').
Furthermore, this should also provide sufficient infrastructure in order to permit adding support for other platform-specific event mechanisms in the future, such as IOCPs on Solaris and Windows.

~ Rationale

The drawbacks associated with ''poll''(2) and ''select''(2) and the tremendously improved ability to scale of ''epoll''(7) and ''kqueue''(2) are well-known [https://en.wikipedia.org/wiki/C10k_problem]; a previous attempt at implementing this feature elaborates on this subject and can be found at [https://sourceforge.net/p/tcl/mailman/tcl-core/?viewmonth=200909&viewday=10].

Initially, the notifier thread was retained to provide for event notification and inter-thread IPC. This eventually proved unnecessary and thus the ''epoll''(7)/''kqueue''(2) source modules now no longer contain the notifier thread and its infrastructure, particularly as this also reduces code size and complexity.

Threads that intend to wait on one or more file descriptors they own will now directly call ''epoll_wait''(2)/''kevent''(2) themselves during ''Tcl_WaitForEvent''().  Inter-thread IPC is provided for by a per-thread trigger pipe, analogous to the trigger pipe of the notifier thread. On Linux, an ''eventfd''(2) is used instead, which only requires one single fd. Furthermore, events for regular files are not processed via ''epoll''(7), as it does not support them at present. Instead, events for regular files are immediately returned by the notifier when waiting for events.

The new implementation of the notifier only has two minor drawbacks:

 1. Each thread that has called ''Tcl_WaitForEvent''() at least once will create an ''epoll''(7)/''kqueue''(2) file descriptor.

 2. All threads create two ''pipe''(2) file descriptors for inter-thread IPC; on Linux, one single ''eventfd''(2) is created and used.

Therefore, threads that have waited on events at least once now own an additional amount of three/two file descriptors. Whether this could prove to be a problem remains a point of contention that should be subject to further discussion.

As far as the notifier implementation is concerned, threads do not share data structures or file descriptors; IPC is provided for explicitly. However, a thread may queue events to and then alert another thread in order to allow for less primitive forms of IPC. Therefore, the previously static mutex protecting the notifier list has become a per-thread mutex. Instead of protecting the notifier list, it protects per-thread event queues from event queue/unqueue race conditions. This only applies to the ''epoll''(7)/''kqueue''(2)-based notifier implementations.

The majority of Tcl code should be unable to observe any difference at the script level.

~ Specification

At present, code changes are almost entirely constrained to either ''unix/tclEpollNotfy.c'' wherever ''epoll''(7) is supported or ''unix/tclKqueueNotfy.c'' wherever ''kqueue''(2) is supported. The original ''select''(2)-based notifier implementation now lives in ''unix/tclSelectNotfy.c''.

Subroutines shared between ''unix/tcl{Epoll,Kqueue}Notfy.c'' have been moved to ''unix/tclUnixNotfy.c'', which is '''#include'''d by the former. As explained in the last section of this document, the previously static mutex in ''generic/tclNotify.c'' has become a per-thread mutex.

The new code associates the newly introduced (but private) ''PlatformEventData'' structure with each file descriptor to wait on and its corresponding ''FileHandler'' struct. ''PlatformEventData'' contains:

 1. A pointer to the ''FileHandler'' the file descriptor belongs to. This specifically facilitates updating the platform-specific mask of new events for the file descriptor of a ''FileHandler'' after returning from ''epoll_wait''(2)/''kevent''(2) in ''NotifierThreadProc''().

 2. A pointer to the ''ThreadSpecificData'' of the thread to whom the ''FileHandler'' belongs. This specifically facilitates alerting threads waiting on one or more ''FileHandlers'' in ''NotifierThreadProc''().

The core implementation is found in a set of six (6) newly introduced static subroutines in ''unix/tcl{Epoll,Kqueue}Notfy.c'':

 1. ''PlatformEventsControl''() - abstracts ''epoll_ctl''(2)/''kevent''(2). Called by ''Tcl_{Create,Delete}FileHandler''() to add/update event masks for a new or an old ''FileHandler'' and ''NotifierThreadProc''() in order to include the ''receivePipe'' fd when waiting for and processing events.

 2. ''PlatformEventsFinalize''() - abstracts ''close''(2) and ''ckfree''(). Called by ''Tcl_FinalizeNotifier''().

 3. ''PlatformEventsGet''() - abstracts iterating over an array of events. Called by ''NotifierThreadProc''().

 4. ''PlatformEventsInit''() - abstracts ''epoll_create''(2)/''kqueue''(2). Called by ''PlatformEvents{Control,Wait}''() and ''Tcl_WaitForEvent''().

 5. ''PlatformEventsTranslate''() - translates platform-specific event masks to '''TCL_{READABLE,WRITABLE,EXCEPTION}''' bits. Called by ''Tcl_WaitForEvent''().

 6. ''PlatformEventsWait''() - abstracts ''epoll_wait''(2)/''kevent''(2). Called by ''Tcl_WaitForEvent''() and ''NotifierThreadProc''(). 

Two additional subroutine are used in all three code paths (''epoll'', ''kqueue'', ''select'') to reduce code redundancy:

 1. ''AlertSingleThread''() - notify a single thread that is waiting on I/O. Called by ''NotifierThreadProc''().

 2. ''TclUnixWaitForFile() - reimplemented via ''poll''(2) instead of ''select''(2), as ''poll''(2) does not suffer the '''FD_SETSIZE''' limit on file descriptors that can be passed to ''select''(2) and is available on a sufficiently large number of platforms. Most importantly, this code would not benefit from using ''epoll''(7) or ''kqueue''(2) as this subroutine only waits on one single file descriptor at a time.

''PlatformEventsInit''() currently defaults to allocating space for 128 array members of ''struct epoll_event/kevent''. This could preferably be handled through e.g. ''fconfigure''.

Originally, a mutex used to protect the ''epoll''(7)/''kqueue''(2) file descriptor and the above mentioned array. This proved to be redundant as ''epoll_ctl''(2) can be called whilst blocking on ''epoll_wait''(2) on Linux and as ''kevent''(2) can be called whilst blocking on ''kevent''(2) on FreeBSD.

Lastly, the ''configure'' script is updated to define '''HAVE_EPOLL''' or '''HAVE_KQUEUE''' as appropriate.

~ Reference implementation

Please refer to the ''tip-458'' branch. The code is licensed under the BSD license.

~ Copyright

This document has been placed in the public domain. In legislations where this concept does not exist the BSD license applies.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|

|

|

|



|

|



|



|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|


>

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

# TIP 458: Add Support for epoll() and kqueue() in the Notifier

	Author:         Lucio Andrés Illanes Albornoz <[email protected]>
	Author:         Lucio Andrés Illanes Albornoz <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        24-Nov-2016
	Post-History:   
	Keywords:       event loop,scalability
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to replace _select_\(2\) in the notifier implementation with _epoll_\(7\) and _kqueue_\(2\) on Linux and DragonFly-, Free-, Net-, and OpenBSD respectively. This is to remove a major bottleneck in the ability of Tcl to scale up to thousands and tens of thousands of sockets \(aka **C10K**\).
Furthermore, this should also provide sufficient infrastructure in order to permit adding support for other platform-specific event mechanisms in the future, such as IOCPs on Solaris and Windows.

# Rationale

The drawbacks associated with _poll_\(2\) and _select_\(2\) and the tremendously improved ability to scale of _epoll_\(7\) and _kqueue_\(2\) are well-known <https://en.wikipedia.org/wiki/C10k_problem> ; a previous attempt at implementing this feature elaborates on this subject and can be found at <https://sourceforge.net/p/tcl/mailman/tcl-core/?viewmonth=200909&viewday=10> .

Initially, the notifier thread was retained to provide for event notification and inter-thread IPC. This eventually proved unnecessary and thus the _epoll_\(7\)/_kqueue_\(2\) source modules now no longer contain the notifier thread and its infrastructure, particularly as this also reduces code size and complexity.

Threads that intend to wait on one or more file descriptors they own will now directly call _epoll\_wait_\(2\)/_kevent_\(2\) themselves during _Tcl\_WaitForEvent_\(\).  Inter-thread IPC is provided for by a per-thread trigger pipe, analogous to the trigger pipe of the notifier thread. On Linux, an _eventfd_\(2\) is used instead, which only requires one single fd. Furthermore, events for regular files are not processed via _epoll_\(7\), as it does not support them at present. Instead, events for regular files are immediately returned by the notifier when waiting for events.

The new implementation of the notifier only has two minor drawbacks:

 1. Each thread that has called _Tcl\_WaitForEvent_\(\) at least once will create an _epoll_\(7\)/_kqueue_\(2\) file descriptor.

 2. All threads create two _pipe_\(2\) file descriptors for inter-thread IPC; on Linux, one single _eventfd_\(2\) is created and used.

Therefore, threads that have waited on events at least once now own an additional amount of three/two file descriptors. Whether this could prove to be a problem remains a point of contention that should be subject to further discussion.

As far as the notifier implementation is concerned, threads do not share data structures or file descriptors; IPC is provided for explicitly. However, a thread may queue events to and then alert another thread in order to allow for less primitive forms of IPC. Therefore, the previously static mutex protecting the notifier list has become a per-thread mutex. Instead of protecting the notifier list, it protects per-thread event queues from event queue/unqueue race conditions. This only applies to the _epoll_\(7\)/_kqueue_\(2\)-based notifier implementations.

The majority of Tcl code should be unable to observe any difference at the script level.

# Specification

At present, code changes are almost entirely constrained to either _unix/tclEpollNotfy.c_ wherever _epoll_\(7\) is supported or _unix/tclKqueueNotfy.c_ wherever _kqueue_\(2\) is supported. The original _select_\(2\)-based notifier implementation now lives in _unix/tclSelectNotfy.c_.

Subroutines shared between _unix/tcl\{Epoll,Kqueue\}Notfy.c_ have been moved to _unix/tclUnixNotfy.c_, which is **\#include**d by the former. As explained in the last section of this document, the previously static mutex in _generic/tclNotify.c_ has become a per-thread mutex.

The new code associates the newly introduced \(but private\) _PlatformEventData_ structure with each file descriptor to wait on and its corresponding _FileHandler_ struct. _PlatformEventData_ contains:

 1. A pointer to the _FileHandler_ the file descriptor belongs to. This specifically facilitates updating the platform-specific mask of new events for the file descriptor of a _FileHandler_ after returning from _epoll\_wait_\(2\)/_kevent_\(2\) in _NotifierThreadProc_\(\).

 2. A pointer to the _ThreadSpecificData_ of the thread to whom the _FileHandler_ belongs. This specifically facilitates alerting threads waiting on one or more _FileHandlers_ in _NotifierThreadProc_\(\).

The core implementation is found in a set of six \(6\) newly introduced static subroutines in _unix/tcl\{Epoll,Kqueue\}Notfy.c_:

 1. _PlatformEventsControl_\(\) - abstracts _epoll\_ctl_\(2\)/_kevent_\(2\). Called by _Tcl\_\{Create,Delete\}FileHandler_\(\) to add/update event masks for a new or an old _FileHandler_ and _NotifierThreadProc_\(\) in order to include the _receivePipe_ fd when waiting for and processing events.

 2. _PlatformEventsFinalize_\(\) - abstracts _close_\(2\) and _ckfree_\(\). Called by _Tcl\_FinalizeNotifier_\(\).

 3. _PlatformEventsGet_\(\) - abstracts iterating over an array of events. Called by _NotifierThreadProc_\(\).

 4. _PlatformEventsInit_\(\) - abstracts _epoll\_create_\(2\)/_kqueue_\(2\). Called by _PlatformEvents\{Control,Wait\}_\(\) and _Tcl\_WaitForEvent_\(\).

 5. _PlatformEventsTranslate_\(\) - translates platform-specific event masks to **TCL\_\{READABLE,WRITABLE,EXCEPTION\}** bits. Called by _Tcl\_WaitForEvent_\(\).

 6. _PlatformEventsWait_\(\) - abstracts _epoll\_wait_\(2\)/_kevent_\(2\). Called by _Tcl\_WaitForEvent_\(\) and _NotifierThreadProc_\(\). 

Two additional subroutine are used in all three code paths \(_epoll_, _kqueue_, _select_\) to reduce code redundancy:

 1. _AlertSingleThread_\(\) - notify a single thread that is waiting on I/O. Called by _NotifierThreadProc_\(\).

 2. _TclUnixWaitForFile\(\) - reimplemented via _poll_\(2\) instead of _select_\(2\), as _poll_\(2\) does not suffer the **FD\_SETSIZE** limit on file descriptors that can be passed to _select_\(2\) and is available on a sufficiently large number of platforms. Most importantly, this code would not benefit from using _epoll_\(7\) or _kqueue_\(2\) as this subroutine only waits on one single file descriptor at a time.

_PlatformEventsInit_\(\) currently defaults to allocating space for 128 array members of _struct epoll\_event/kevent_. This could preferably be handled through e.g. _fconfigure_.

Originally, a mutex used to protect the _epoll_\(7\)/_kqueue_\(2\) file descriptor and the above mentioned array. This proved to be redundant as _epoll\_ctl_\(2\) can be called whilst blocking on _epoll\_wait_\(2\) on Linux and as _kevent_\(2\) can be called whilst blocking on _kevent_\(2\) on FreeBSD.

Lastly, the _configure_ script is updated to define **HAVE\_EPOLL** or **HAVE\_KQUEUE** as appropriate.

# Reference implementation

Please refer to the _tip-458_ branch. The code is licensed under the BSD license.

# Copyright

This document has been placed in the public domain. In legislations where this concept does not exist the BSD license applies.

Name change from tip/459.tip to tip/459.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

TIP:            459
Title:          Tcl Package Introspection Improvements
Version:        $Revision: 1.6 $
Author:         Jan Nijtmans <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        08-Dec-2016
Post-History:   
Keywords:       Tcl,package
Tcl-Version:    8.7


~ Abstract

This TIP proposes to improve package introspection by providing a new command
'''package files'''.

~ Rationale

This TIP is inspired by a request from FlightAware to improve Tcl's package
introspection possibilities. Although only a '''package files''' command was
requested, extending '''info loaded''' gives the possibility to find a shared
library contained in a package more easily than searching a list.

~ Specification of the proposed Change

Two new additions are proposed, to the '''package''' and '''info''' commands.

 1. '''package files''' ''name''

  > This command returns a list of filenames which were sourced during the
    initialization of package ''name''. More specific, the files that were
    sourced during running the script registered using '''package ifneeded'''.
    Left out are Tcl's own tclIndex and pkgIndex.tcl files, which might have been
    accessed due to dependancy searches, otherwise this would give very
    misleading results.

 1. '''info loaded''' ?''interpreter''? ?''name''?

  > The '''info loaded''' command already exists, it gives a list of package
    names with corresponding shared library names which were actually loaded
    in the give interpreter. The additional ''name'' argument restricts the
    result to the filename of the loaded library only.

Tcl packages don't have to do anything special in order to be introspected
correctly, just note that files containing auto_loaded commands cannot be
introspected because they are not sourced during package initialization.

~ Rejected alternatives

  > Use of ''source -nopkg'' in tclIndex files. Even though this addition in the
  earlier TIP was explicitly undocumented, it lead to the misunderstanding
  that other Tcl extensions should do the same.

  > Earlier implementation of this TIP didn't handle the second argument of
  '''info loaded''' correctly in all cases, and the handling in safe
  interpreters was not complete. This is all corrected in the current implementation.

  > All filenames should be converted to absolute. This is rejected for performance
  and for practical reasons. It could be quite expensive to calculate because
  the disk has to be accessed for possible hyper-links. Second, the package
  mechanism is already designed such that all sourced paths are absolute (see
  below example). Extensions using the '''source''' command with relative
  paths are in danger already, this should be fixed in the extension in
  stead of being masked in the '''package files''' command.

  > Additional information about the sourced files (like mtime or checksum) was
  suggested to be part of the introspection information, but this has been
  rejected as overkill. It is much more than requested in the Tcl-bounty, and
  it is difficult to imagine what actual use this would bring.

~ Reference Implementation

This is available in the ''package_files'' branch
[http://core.tcl.tk/tcl/timeline?r=package_files].

~ Examples

|$ tclsh8.7
|% package files Tcl
|/usr/lib/tcl8.7/init.tcl
|% package require Tk
|8.7a0
|% package files msgcat
|/usr/lib/tcl8/8.5/msgcat-1.6.0.tm
|% package files Tk
|/usr/lib/tk8.7/tk.tcl /usr/lib/tk8.7/msgs/en.msg /usr/lib/tk8.7/icons.tcl ...
|% info loaded {} Tk
|/usr/lib/libtk8.7.so

Note that '''package require Tk''' has the side-effect of loading the ''msgcat'' package, which is required by Tk.

~ Copyright

This document has been placed in the public domain.

Please note that any correspondence to the author concerning this TIP is
considered in the public domain unless otherwise specifically requested by the
individual(s) authoring said correspondence. This is to allow information
about the TIP to be placed in a public forum for discussion.

<
|
<
|
|
|
|
|
|
|
|
>

|


|

|


|
|


|

|

|

|
|
|




|

|

|



|


|

|




|





|
|

|

|




|

|
|

|

|
|
|
|
|
|
|
|
|
|
|

|

|





|

>

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

# TIP 459: Tcl Package Introspection Improvements

	Author:         Jan Nijtmans <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        08-Dec-2016
	Post-History:   
	Keywords:       Tcl,package
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to improve package introspection by providing a new command
**package files**.

# Rationale

This TIP is inspired by a request from FlightAware to improve Tcl's package
introspection possibilities. Although only a **package files** command was
requested, extending **info loaded** gives the possibility to find a shared
library contained in a package more easily than searching a list.

# Specification of the proposed Change

Two new additions are proposed, to the **package** and **info** commands.

 1. **package files** _name_

	  > This command returns a list of filenames which were sourced during the
    initialization of package _name_. More specific, the files that were
    sourced during running the script registered using **package ifneeded**.
    Left out are Tcl's own tclIndex and pkgIndex.tcl files, which might have been
    accessed due to dependancy searches, otherwise this would give very
    misleading results.

 1. **info loaded** ?_interpreter_? ?_name_?

	  > The **info loaded** command already exists, it gives a list of package
    names with corresponding shared library names which were actually loaded
    in the give interpreter. The additional _name_ argument restricts the
    result to the filename of the loaded library only.

Tcl packages don't have to do anything special in order to be introspected
correctly, just note that files containing auto\_loaded commands cannot be
introspected because they are not sourced during package initialization.

# Rejected alternatives

  > Use of _source -nopkg_ in tclIndex files. Even though this addition in the
  earlier TIP was explicitly undocumented, it lead to the misunderstanding
  that other Tcl extensions should do the same.

  > Earlier implementation of this TIP didn't handle the second argument of
  **info loaded** correctly in all cases, and the handling in safe
  interpreters was not complete. This is all corrected in the current implementation.

  > All filenames should be converted to absolute. This is rejected for performance
  and for practical reasons. It could be quite expensive to calculate because
  the disk has to be accessed for possible hyper-links. Second, the package
  mechanism is already designed such that all sourced paths are absolute \(see
  below example\). Extensions using the **source** command with relative
  paths are in danger already, this should be fixed in the extension in
  stead of being masked in the **package files** command.

  > Additional information about the sourced files \(like mtime or checksum\) was
  suggested to be part of the introspection information, but this has been
  rejected as overkill. It is much more than requested in the Tcl-bounty, and
  it is difficult to imagine what actual use this would bring.

# Reference Implementation

This is available in the _package\_files_ branch
<http://core.tcl.tk/tcl/timeline?r=package_files> .

# Examples

	$ tclsh8.7
	% package files Tcl
	/usr/lib/tcl8.7/init.tcl
	% package require Tk
	8.7a0
	% package files msgcat
	/usr/lib/tcl8/8.5/msgcat-1.6.0.tm
	% package files Tk
	/usr/lib/tk8.7/tk.tcl /usr/lib/tk8.7/msgs/en.msg /usr/lib/tk8.7/icons.tcl ...
	% info loaded {} Tk
	/usr/lib/libtk8.7.so

Note that **package require Tk** has the side-effect of loading the _msgcat_ package, which is required by Tk.

# Copyright

This document has been placed in the public domain.

Please note that any correspondence to the author concerning this TIP is
considered in the public domain unless otherwise specifically requested by the
individual\(s\) authoring said correspondence. This is to allow information
about the TIP to be placed in a public forum for discussion.

Name change from tip/46.tip to tip/46.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

TIP:		46
Title:          Consistent Overlap Behavior of Area-Defining Canvas Items 
Version:        $Revision: 1.5 $
Author:         Gerhard Hintermayer <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        18-Jul-2001
Post-History:   
Tcl-Version:	8.5


~ Abstract

This document proposes that all canvas items that define an area
should behave the same in terms of interior points, i.e. points that
return the enclosing object id when submitted to
''[$canvas find overlapping]''.  Currently polygons behave differently
from the rest (rectangle, arc, oval).

~ Rationale

As long as these area-defining canvas items are filled, there's no problem.
The interior points belong to the object. But when the object is not filled
(i.e. -fill "" is used), only polygons consider inside points as overlapping.
For the rest of the area-defining canvas items, an interior point is ''not''
considered to overlap the object.  This makes it impossible to

   * define invisible or not filled mouse sensitive areas other than polygons
     because moving the pointer inside of an arc/oval/rectangle creates both
     an ''<Enter>'' and a ''<Leave>'' event, even though the pointer is still
     inside the item.

   * do object-oriented selection on a canvas. Consider you want to select
     a (not filled) oval, you ''have to'' click on the vertice, or else you
     won't find a overlapping item.

Well, I see the point, that this proposal might break existing code, but
from the number of replies to my postings at news:comp.lang.tcl ,
''[$canvas find overlapping]'' is not used very often.

One possibility to fix the backward compatibility is to introduce 2
different fill colors for the 2 cases - object either hollow or solid
but not filled. Then inside points would not overlap hollow objects, but
would overlap solid objects.

~ Proposal

We should either choose a wire frame model or an object-oriented model
for canvas objects. To my mind an object-oriented approach is better.
Right now we have a mixture of both. Polygons are objects, arcs, ovals and
rectangles are wire frames.

What I'd like is: all points which are inside of an area object should return
the enclosing object when passed to find overlap, ''regardless'' of the fill
color of the item.

~ Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > This would remove useful behaviour that is used rather more often
   than people think.  If people want unfilled polygons with the other
   style of overlap behaviour, they should use lines.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|




|
|

|



|
|




|



|




|






|







|


|









|


>

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

# TIP 46: Consistent Overlap Behavior of Area-Defining Canvas Items

	Author:         Gerhard Hintermayer <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        18-Jul-2001
	Post-History:   
	Tcl-Version:	8.5
-----

# Abstract

This document proposes that all canvas items that define an area
should behave the same in terms of interior points, i.e. points that
return the enclosing object id when submitted to
_[$canvas find overlapping]_.  Currently polygons behave differently
from the rest \(rectangle, arc, oval\).

# Rationale

As long as these area-defining canvas items are filled, there's no problem.
The interior points belong to the object. But when the object is not filled
\(i.e. -fill "" is used\), only polygons consider inside points as overlapping.
For the rest of the area-defining canvas items, an interior point is _not_
considered to overlap the object.  This makes it impossible to

   * define invisible or not filled mouse sensitive areas other than polygons
     because moving the pointer inside of an arc/oval/rectangle creates both
     an _<Enter>_ and a _<Leave>_ event, even though the pointer is still
     inside the item.

   * do object-oriented selection on a canvas. Consider you want to select
     a \(not filled\) oval, you _have to_ click on the vertice, or else you
     won't find a overlapping item.

Well, I see the point, that this proposal might break existing code, but
from the number of replies to my postings at news:comp.lang.tcl ,
_[$canvas find overlapping]_ is not used very often.

One possibility to fix the backward compatibility is to introduce 2
different fill colors for the 2 cases - object either hollow or solid
but not filled. Then inside points would not overlap hollow objects, but
would overlap solid objects.

# Proposal

We should either choose a wire frame model or an object-oriented model
for canvas objects. To my mind an object-oriented approach is better.
Right now we have a mixture of both. Polygons are objects, arcs, ovals and
rectangles are wire frames.

What I'd like is: all points which are inside of an area object should return
the enclosing object when passed to find overlap, _regardless_ of the fill
color of the item.

# Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > This would remove useful behaviour that is used rather more often
   than people think.  If people want unfilled polygons with the other
   style of overlap behaviour, they should use lines.

# Copyright

This document has been placed in the public domain.

Name change from tip/460.tip to tip/460.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
136
137
138
139
140
141

142
143
144
145
146
147
148
149
150
151
152
153

154
155
156
157
158

159
160
161
162
163
164
165
166
167
168
169
170
171
172

173
174
175
176
177
178

179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

TIP:            460
Title:          An Alternative to Upvar
Version:        $Revision: 1.5 $
Author:         Don Hathway <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        08-Dec-2016
Post-History:   
Keywords:       Tcl,variable,link,upvar
Tcl-Version:    9.0


~ Abstract

Variable linking with the ''upvar'' command is not as intuitive or effecient
as it should be. This TIP proposes an alternative through automatic variable
linking.

~Rationale

The current strategy used to link a variable in a called procedure to the
caller, is to pass the name of the variable to the procedure, and use the
''upvar'' command to create a new variable, which is then linked to the
original. Thus linking to a variable requires two components; the variable
name and a newly created variable.

It is possible to instruct Tcl to do this linking automatically in an idiomatic way
and dispense with the ''upvar'' command call.

Also, the requirement (by ''upvar'') that the name of the new link variable be a 
different name from the original is arguably considered counter-intuitive.

Benefits to this TIP as proposed:

 1. '''No code to perform explicit linking within the procedure's body.'''
    Unlike ''upvar'', this method requires no additional code to be entered in
    the body of the procedure. Less code, less bugs, easier to use! It has
    been said that Tcl'ers should make more use of variable linking in their
    code. Making it easier for them should have an encouraging effect, similar
    to how most Tcl'ers prefer ''$var'' over ''set var''.

 2. '''Clearly defines links in the procedure's parameter list.''' Readers
    should instantly know what the links are.  Clarity is important,
    especially for people that read code all day. There are no special project
    naming conventions to follow. A reader doesn't have to rely on docs or
    assume that a parameter name of "varName", "_var", or "varLnk" is to be
    linked by an upvar call, of which may be pushed down in the procedure's
    body by comments or other code.

 3. '''Alleviates arguably messy ''upvar'' chain linking.'''

~~ Upvar Chaining Example

Below are three ''upvar''s with the same arguments. As you can see, there is
quite a bit of arguably unnecessary code duplication, and that is bug prone.

| proc foo {a} {
|    upvar 1 $a la
|    maybe do something with la
|    bar la
| }

| proc bar {a} {
|    upvar 1 $a la
|    maybe do something with la
|    baz la
| }

| proc baz {a} {
|    upvar 1 $a la
|    maybe do something with la
| }

| foo begin

This could be written more succinctly:

| proc foo {*a} {
|    maybe do something with a
|    bar a
| }

| proc bar {*a} {
|    maybe do something with a
|    baz a
| }

| proc baz {*a} {
|    maybe do something with a
| }

| foo begin

~ Specification

Add support to procedure handling to allow for a parametric hint to procedure
definitions with respect to the intent to link variables accordingly. We use
the asterisk character "'''*'''" as the symbol to declare this intent; which
shall prefix the parameter's name. Consequently, the "'''*'''" character becomes 
special, but only inside the procedure parameter list. A procedure definition using 
this facility would then have the signature:

| proc foo {*a *b} {...}

Where '''*a''' and '''*b''' are the procedure's parameters to be linked to the
caller's arguments. New variables are then created for the future linking. In this example
'''*a''' creates a new link variable named '''a''', and likewise done for '''*b'''.
'''*a''' and '''*b''' holds the values passed in by the caller.

The formal parameter's shall retain the same values provided by the caller.

The link variable's name shall always have one '''*''' symbol less than its counterpart parameter, for the sake of consistency.  In example, a parameter named '''***a''' shall have a counterpart link variable named '''**a'''. Similarily '''**a''' shall have a counterpart link named '''*a'''.

Where there are duplicate link parameter names (i.e. proc P {*a *a}) the behavior shall be the same as if there were duplicate '''upvar''' statements.

It is legal to have empty link variable names. It shall be possible with a single '''*''' in
the procedure's parameter list (i.e. proc P {*} {incr ""}). The same duplicate name rule applies.

If the variable to be linked does not exist, it shall be created, if necessary. It shall have the same behavior as '''upvar 1''' in such instances.

When a link's construction fails, the behavior shall be the same as if '''upvar''' had failed, the procedure will
return with an error before any other commands (with exception to any commands involved in the link's construction) in its body are executed.

It is illegal for a link parameter to have a default value. It shall invoke an error during procedure
creation time and result in failed procedure creation with the error code:

| Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC","FORMALARGUMENTFORMAT", NULL);

An example of such an error for:
| proc P {{*a foo}} {...}
Would be: "procedure "P": formal parameter "*a"  is to be linked and must not have a default value"

In that example, proc '''P''' is never created, the attempt failed due to the error.

It is the caller's responsibility to provide the names of variables to be linked. This 
constraint exists in the spirit of promoting good coding practices and to help avoid 
obscure and subtle bugs. For the same reasons, this TIP only searches one level up.
Therefore, It shall have the same behavior as '''upvar 1'''.

'''*args''' is a valid parameter name. For example, '''args''' is simply a
link in:

| proc foo {a *args} {
|     incr args
| }

Note that as of this TIP ''proc foo {args args} {...}'' is legal Tcl. In this

instance only the first ''scalar'' '''args''' is usable by the procedure. The
rest of the arguments are inaccessible by the script. They're not internally
lost, but Tcl's variable lookup mechanics will choose whichever is found first
when a script references it. This behavior is inherited for ''proc foo {*args
args} {...}''. Where '''args''' will be a link.

To further illustrate this proposal with an example:

| proc foo {*a *b} {
|   bar a b
| }


| proc bar {*a *b} {
|   incr a
|   incr b
| }


| set v1 0
| set v2 1
| foo v1 v2
| puts $v1
| # prints 1
| puts $v2
| # prints 2

| # Version of foo using upvar:
| proc foo {a b} {
|    # Note, upvar $a a would be an error.
|    upvar 1 $a la $b lb
|    bar la lb
| }

| proc bar {a b} {
|    upvar 1 $a la $b lb
|    incr la
|    incr lb
| }


The "'''*'''" character was chosen primarily because it
resembles a star or a snowflake and has a pleasantry to it. It is one of the few
ascii characters that '''sticks out''' from its surrounding text. 

It is also familiar to users of other languages where the same symbol exhibits similar
semantics (to wit: a link in Tcl acts as a reference to another variable and doesn't perform 
a copy when the reference is written to, as it would if it weren't a link). However, 
unlike other languages, the Tcl core does not expose operations to user scripts that work directly on 
memory, so the "'''*'''" character should not be mistaken to behave the same or suffer from the same 
pitfalls as it does in C, C++, Golang, etc. The '''*''' symbol simply instructs Tcl to 
create a link if it is able to do so.

~~ Consequences

 1. Breaks scripts using the special "'''*'''" as the first character in their
    procedure's parameters (i.e. '''*var''').

  > The impact of this should be minimal because these variable names require
    the user to wrap it in curly braces (i.e. '''${*var}''') to fetch their
    values, unless they're using the less common form of '''set varname'''.

~Reference Implementation

See branch ''dah-proc-arg-upvar''

~~Implementation Notes

 tclInt.h: Add a new field named ''numArgsCompiledLocals'' to the Proc struct.
  The new field holds the number of parameters along with any other relevant
  local variables which follow immediately after the parameters. For this TIP,
  these additional locals are variables with the VAR_LINK flag and to be resolved 
  as links to the values of arguments they've been configured to link with.

  The additional field was a hard choice, but is necessary because ''TclProcCompileProc'' 
  enforces ''procPtr->numCompiledLocals'' to be the same value as ''procPtr->numArgs''. 
  The local variable table is evidently not growable until later.

 tclProc.c: Modify ''InitArgsAndLocals'' to do the automatic linking. Note
  that this is a ''very hot'' function and that was kept in mind while making
  the necessary adjustments. There are two additional branches in the function
  (the second only visited when an error happens). The first to check if the
  command has any parameters that need linking and if so, process them with
  link support handling code. The second branch is to simply check if the link
  handling code set an error when an error occurs, so this branch should not
  be a concern as to performance impact. Due to branch prediction and this
  function being so hot, there should be virtually nil of a performance impact 
  on any code which doesn't make use of the new automatic linking facility.

 tclProc.c: Modify ''TclCreateProc'' to add additional locals after the list
 of parameter locals (if any) when there are parameters flagged for auto linking.

~Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|



|



|




|

|




|
|



|

|



|



|

|

|


|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
<
>
|



|
|
|
<
>
|
|
|
<
>
|
|
<
>
|

|



|
|



|

|

|
|



|

|

|
|

|

|
|




|


|
|

|




|

|


|
|
<
|
|
>
|


|
|



|
|
<
|
>
|
|
|
<
|
>
|
|
|
|
|
|
|

|
|
|
|
|
<
>
|
|
|
|
<
|
>
|

|


|
|

|
|


|

|
|

|
|
|

|

|

|

|


|


|
|


|
|

|







|
|

|


>

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
136
137

138
139
140
141
142
143
144
145
146
147
148
149
150

151
152
153
154
155

156
157
158
159
160
161
162
163
164
165
166
167
168
169
170

171
172
173
174
175

176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

# TIP 460: An Alternative to Upvar

	Author:         Don Hathway <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        08-Dec-2016
	Post-History:   
	Keywords:       Tcl,variable,link,upvar
	Tcl-Version:    9.0
-----

# Abstract

Variable linking with the _upvar_ command is not as intuitive or effecient
as it should be. This TIP proposes an alternative through automatic variable
linking.

# Rationale

The current strategy used to link a variable in a called procedure to the
caller, is to pass the name of the variable to the procedure, and use the
_upvar_ command to create a new variable, which is then linked to the
original. Thus linking to a variable requires two components; the variable
name and a newly created variable.

It is possible to instruct Tcl to do this linking automatically in an idiomatic way
and dispense with the _upvar_ command call.

Also, the requirement \(by _upvar_\) that the name of the new link variable be a 
different name from the original is arguably considered counter-intuitive.

Benefits to this TIP as proposed:

 1. **No code to perform explicit linking within the procedure's body.**
    Unlike _upvar_, this method requires no additional code to be entered in
    the body of the procedure. Less code, less bugs, easier to use! It has
    been said that Tcl'ers should make more use of variable linking in their
    code. Making it easier for them should have an encouraging effect, similar
    to how most Tcl'ers prefer _$var_ over _set var_.

 2. **Clearly defines links in the procedure's parameter list.** Readers
    should instantly know what the links are.  Clarity is important,
    especially for people that read code all day. There are no special project
    naming conventions to follow. A reader doesn't have to rely on docs or
    assume that a parameter name of "varName", "\_var", or "varLnk" is to be
    linked by an upvar call, of which may be pushed down in the procedure's
    body by comments or other code.

 3. **Alleviates arguably messy _upvar_ chain linking.**

## Upvar Chaining Example

Below are three _upvar_s with the same arguments. As you can see, there is
quite a bit of arguably unnecessary code duplication, and that is bug prone.

	 proc foo {a} {
	    upvar 1 $a la
	    maybe do something with la
	    bar la

	 }
	 proc bar {a} {
	    upvar 1 $a la
	    maybe do something with la
	    baz la

	 }
	 proc baz {a} {
	    upvar 1 $a la
	    maybe do something with la

	 }
	 foo begin

This could be written more succinctly:

	 proc foo {*a} {
	    maybe do something with a
	    bar a

	 }
	 proc bar {*a} {
	    maybe do something with a
	    baz a

	 }
	 proc baz {*a} {
	    maybe do something with a

	 }
	 foo begin

# Specification

Add support to procedure handling to allow for a parametric hint to procedure
definitions with respect to the intent to link variables accordingly. We use
the asterisk character "**\***" as the symbol to declare this intent; which
shall prefix the parameter's name. Consequently, the "**\***" character becomes 
special, but only inside the procedure parameter list. A procedure definition using 
this facility would then have the signature:

	 proc foo {*a *b} {...}

Where **\*a** and **\*b** are the procedure's parameters to be linked to the
caller's arguments. New variables are then created for the future linking. In this example
**\*a** creates a new link variable named **a**, and likewise done for **\*b**.
**\*a** and **\*b** holds the values passed in by the caller.

The formal parameter's shall retain the same values provided by the caller.

The link variable's name shall always have one **\*** symbol less than its counterpart parameter, for the sake of consistency.  In example, a parameter named **\*\*\*a** shall have a counterpart link variable named **\*\*a**. Similarily **\*\*a** shall have a counterpart link named **\*a**.

Where there are duplicate link parameter names \(i.e. proc P \{\*a \*a\}\) the behavior shall be the same as if there were duplicate **upvar** statements.

It is legal to have empty link variable names. It shall be possible with a single **\*** in
the procedure's parameter list \(i.e. proc P \{\*\} \{incr ""\}\). The same duplicate name rule applies.

If the variable to be linked does not exist, it shall be created, if necessary. It shall have the same behavior as **upvar 1** in such instances.

When a link's construction fails, the behavior shall be the same as if **upvar** had failed, the procedure will
return with an error before any other commands \(with exception to any commands involved in the link's construction\) in its body are executed.

It is illegal for a link parameter to have a default value. It shall invoke an error during procedure
creation time and result in failed procedure creation with the error code:

	 Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC","FORMALARGUMENTFORMAT", NULL);

An example of such an error for:
	 proc P {{*a foo}} {...}
Would be: "procedure "P": formal parameter "\*a"  is to be linked and must not have a default value"

In that example, proc **P** is never created, the attempt failed due to the error.

It is the caller's responsibility to provide the names of variables to be linked. This 
constraint exists in the spirit of promoting good coding practices and to help avoid 
obscure and subtle bugs. For the same reasons, this TIP only searches one level up.
Therefore, It shall have the same behavior as **upvar 1**.

**\*args** is a valid parameter name. For example, **args** is simply a
link in:

	 proc foo {a *args} {
	     incr args

	 }

Note that as of this TIP _proc foo \{args args\} \{...\}_ is legal Tcl. In this
instance only the first _scalar_ **args** is usable by the procedure. The
rest of the arguments are inaccessible by the script. They're not internally
lost, but Tcl's variable lookup mechanics will choose whichever is found first
when a script references it. This behavior is inherited for _proc foo \{\*args
args\} \{...\}_. Where **args** will be a link.

To further illustrate this proposal with an example:

	 proc foo {*a *b} {
	   bar a b

	 }

	 proc bar {*a *b} {
	   incr a
	   incr b

	 }

	 set v1 0
	 set v2 1
	 foo v1 v2
	 puts $v1
	 # prints 1
	 puts $v2
	 # prints 2

	 # Version of foo using upvar:
	 proc foo {a b} {
	    # Note, upvar $a a would be an error.
	    upvar 1 $a la $b lb
	    bar la lb

	 }
	 proc bar {a b} {
	    upvar 1 $a la $b lb
	    incr la
	    incr lb

	 }

The "**\***" character was chosen primarily because it
resembles a star or a snowflake and has a pleasantry to it. It is one of the few
ascii characters that **sticks out** from its surrounding text. 

It is also familiar to users of other languages where the same symbol exhibits similar
semantics \(to wit: a link in Tcl acts as a reference to another variable and doesn't perform 
a copy when the reference is written to, as it would if it weren't a link\). However, 
unlike other languages, the Tcl core does not expose operations to user scripts that work directly on 
memory, so the "**\***" character should not be mistaken to behave the same or suffer from the same 
pitfalls as it does in C, C\+\+, Golang, etc. The **\*** symbol simply instructs Tcl to 
create a link if it is able to do so.

## Consequences

 1. Breaks scripts using the special "**\***" as the first character in their
    procedure's parameters \(i.e. **\*var**\).

	  > The impact of this should be minimal because these variable names require
    the user to wrap it in curly braces \(i.e. **$\{\*var\}**\) to fetch their
    values, unless they're using the less common form of **set varname**.

# Reference Implementation

See branch _dah-proc-arg-upvar_

## Implementation Notes

 tclInt.h: Add a new field named _numArgsCompiledLocals_ to the Proc struct.
  The new field holds the number of parameters along with any other relevant
  local variables which follow immediately after the parameters. For this TIP,
  these additional locals are variables with the VAR\_LINK flag and to be resolved 
  as links to the values of arguments they've been configured to link with.

  The additional field was a hard choice, but is necessary because _TclProcCompileProc_ 
  enforces _procPtr->numCompiledLocals_ to be the same value as _procPtr->numArgs_. 
  The local variable table is evidently not growable until later.

 tclProc.c: Modify _InitArgsAndLocals_ to do the automatic linking. Note
  that this is a _very hot_ function and that was kept in mind while making
  the necessary adjustments. There are two additional branches in the function
  \(the second only visited when an error happens\). The first to check if the
  command has any parameters that need linking and if so, process them with
  link support handling code. The second branch is to simply check if the link
  handling code set an error when an error occurs, so this branch should not
  be a concern as to performance impact. Due to branch prediction and this
  function being so hot, there should be virtually nil of a performance impact 
  on any code which doesn't make use of the new automatic linking facility.

 tclProc.c: Modify _TclCreateProc_ to add additional locals after the list
 of parameter locals \(if any\) when there are parameters flagged for auto linking.

# Copyright

This document has been placed in the public domain.

Name change from tip/461.tip to tip/461.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222

TIP:            461
Title:          Separate Numeric and String Comparison Operators
Version:        $Revision: 1.6 $
Author:         Kevin B Kenny <[email protected]>
Author:         Kevin B Kenny <[email protected]>
Author:         Kevin Kenny <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        24-Jan-2017
Post-History:   
Keywords:       Tcl,expression
Tcl-Version:    8.7


~ Abstract

This TIP proposes to complete the separation between string and numeric
comparison operations in [[expr]] and related commands ([[for]], [[if]],
[[while]], etc.). It introduces new comparison operators '''ge''', '''gt''',
'''le''', and '''lt''', (along with the corresponding commands in the
'''::tcl::mathop''' namespace), and encourages programmers to restrict the six operators '''==''', '''>=''', '''>''', '''<=''', '''<''' and '''!=''' to comparisons of numeric
values.

~ Rationale

Tcl throughout its history has had comparison operators that freely compare
numeric and string values. These operators behave as expected if both their
arguments are numeric: they compare values on the real number line. Hence, 15
< 0x10 < 0b10001. Similarly, if presented with non-numeric strings, they
compare the strings in lexicographic order, as a programmer might expect:
"bambam" < "barney" < "betty" < "fred".

Trouble arises, however, when numeric and non-numeric strings are compared.
The rule for comparison is that mixed-type comparisons like this are treated
as string comparisons. The result is that '''<''' does not induce an order.
There are inconsistent comparison results, rendering '''<''' and friends
worthless for sorting. 0x10 < 0y < 1 < 0x10.

The problems with this inconsistency prompted changes in May of 2000,
introducing '''eq''' and '''ne''' operators that always perform string
comparison. For whatever reason, the four inequality operations never
followed. This leads to pitfalls for the unwary. It's fairly well entrenched
in the Tcl folklore that comparisons other than '''eq''' and '''ne''' should
be reserved for numeric arguments only, and experienced Tcl programmers know
to write:

| if {[string compare $x $y] < 0} { ... }

in place of 

| if {$x < $y} { ... }

~ Proposal

Four new bareword operators, '''ge''', '''gt''', '''le''' and
'''lt''' shall be added to the expression parser and to the
'''::tcl::mathop''' command set. They will have precedence identical to
the existing operators '''>=''', '''>''', '''<=''' and '''<'''. They
will accept string values, and return 0 or 1 according to lexicographic
string comparison of their operators. This change is entirely backward
compatible (it uses syntax that would previously have been erroneous),
and should go in as soon as possible - no later than the next point
release, but ideally even in a patchlevel - so that programmers can
begin conversion as soon as possible. Use of the '''==''', '''>=''',
'''>''', '''<=''', '''<''', and '''!=''' for comparing non-numeric
values shall immediately be deprecated.

The six string compare operators shall be declared to function so that
their results are the same as the results of [[string compare]]:

|    {$a lt $b}  <=> {[string compare $a $b] <  0}
|    {$a le $b}  <=> {[string compare $a $b] <= 0}
|    {$a eq $b}  <=> {[string compare $a $b] == 0}
|    {$a ne $b}  <=> {[string compare $a $b] != 0}
|    {$a gt $b}  <=> {[string compare $a $b] >  0}
|    {$a ge $b}  <=> {[string compare $a $b] >= 0}

It is also intended that any future changes to [[string compare]]
(for example, a hypothetical change to make it follow Unicode collation
semantics) will have the corresponding effect on these six operators.

Unlike what was specified in an earlier version of this TIP, no
changes are to  be made to the semantics of the comparison operators
 '''==''', '''>=''', '''>''', '''<=''', '''<''', and '''!='''.

~ Discussion

~~ Forcing typed comparisons in Tcl

Programmers who wish to insure string semantics should restrict their
comparisons to the '''lt''', '''le''', '''eq''', '''ne''', '''gt'''
and '''ge''' operators.

Use of the '''<''', '''<=''', '''==''', '''!=''', '''>''' and '''>='''
operators with operands that might be non-numeric shall be regarded
as poor programming style. Unless operands are constant, unary '''+'''
should be used to force them to be numeric. Thus,

| if {$x < $y} { ... }

should be relaced with

| if {+$x < +$y} { ... }

The second comparison will have the effect of forcing both operands to be
numeric.

~~ Rejected alternatives

Earlier, the radical suggestion of ''requiring'' the '''<''',
'''<=''', '''==''', '''!=''', '''>''' and '''>=''' operators to have
numeric arguments had been read into this TIP. It appears that there
is far too much outstanding code that is written like:

    if {$x == "somestring"} { ... }

to have the more radical option be viable.

One possible alternative to excluding non-numeric arguments from the
comparison operators is to change their semantics so that all non-numeric
strings are greater than all numbers. This change would at least yield a
consistent ordering. The ordering that it yields would, however, be somewhat
surprising, and not terribly useful. (It would at least be compatible with
today's scheme for numeric comparisons.)

~~ Objections (and rebuttals)

In out-of-band discussions, several objections were raised. This section
attempts to address them.

   1. ''Tcl's expression parser has a hard limit of 64 different binary
      operators. This proposal consumes four of them, leaving only 28. There
      is a concern that this is a less-than-effective use of a limited
      resource.''

    > The limit is self-imposed, in an effort to make the nodes of an
      expression parse tree fit in exactly 16 bytes (or four int's). It is far
      from obvious that this pretty size is actually useful. Few expressions
      are more than a few dozen parse nodes, and typical expressions are not
      parsed multiple times. It appears that neither the speed of the parse
      nor the size of the tree will be critical issues in most applications.
      In any case, we still have nearly half the operators left.

   2. ''There is some concern that using barewords for operators was a bad
      idea in the first place.'' The fact that

| expr {"foo"}

    > and

| set x foo; expr {$x}

     > both work, while

| expr {foo}

     > is an invalid bareword is arguably surprising.

    > Nevertheless, we have committed to the approach with the '''eq''',
      '''ne''', '''in''' and '''ni''' operators. These are unlikely to go
      away. Adding '''lt''', '''le''', '''gt''' and '''ge''' will make this
      problem no better nor worse.

    > Moreover, the language of [[expr]] is not the same as Tcl. It does not
      strip comments, parse into words, and apply Tcl's precise substitution
      rules - and it would be surprising if it did!  There are other "little
      languages" throughout Tcl - regular expressions, glob patterns, assembly
      code, and so on. [[expr]] is one among many.

   3. ''There is concern that [[expr]], which was originally intended almost
      exclusively for numeric calculations, is being abused with string
      arguments and possibly string results.''

    > The author of this TIP contends that we introduced string values to
      [[expr]] a long time ago, certainly by the time that the '''eq''',
      '''ne''', '''in''' and '''ni''' operations were introduced.  It is true
      that the use of numeric conversions in [[expr]] is incoherent, as seen
      in:

|   % proc tcl::mathfunc::cat {args} { join $args {} }
|   % expr {cat(0x1,0x2,"a")}
|   0x10x2a
|   % expr {cat(0x1)}
|   1


    > (Bug [[e7c21ed678]] is another manifestation of this general
      problem.) Once again, adding additional string operations
      that behave, with respect to data types, exactly the same
      as ones that are already there will neither fix nor exacerbate
      the general problem.

   4. ''Because [[expr]] has no interpreted form, the operations must have
      bytecode representations. The space of available bytecodes is under even
      more pressure than the space of available operators, and must not be
      squandered on operations that are duplicative of already-available
      functionality such as [[string compare]].''

    > The obvious rebuttal is that [[string compare]] is already bytecoded.
      There are no new operations required, merely a compiler that is smart
      enough to emit a short codeburst rather than a single bytecode. As an
      example, the code for the expression

|   {$x lt $y}

    > could
      be:

|   (0) loadScalar1 %v0        # var "x"
|   (2) loadScalar1 %v1        # var "y"
|   (4) strcmp 
|   (5) push1 0        # "0"
|   (7) lt 

    > For the other string operators, only the last bytecode in the burst
      would change.  No new bytecode operations are needed. In fact, this
      codeburst is identical code to that generated for the expression

|   {[string compare $x $y] < 0}

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|


|
|
|
|


|










|
|



|


|



|



|

|

|
|
|
|


|


|
|



|

|
|
|
|
|
|

|
|
|



|

|

|


|
|

|

|


|



|




|

|
|



|







|
|

|




|


|

|
|






|
|

|

|

|

|

|

|

|
|
|


|



|

|

|

|
|
|
|


|
|
|
|
<
|
>
|
|




|



|

|




|

|


|
|
|
|
|

|



|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182

183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222

# TIP 461: Separate Numeric and String Comparison Operators

	Author:         Kevin B Kenny <[email protected]>
	Author:         Kevin B Kenny <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        24-Jan-2017
	Post-History:   
	Keywords:       Tcl,expression
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to complete the separation between string and numeric
comparison operations in [expr] and related commands \([for], [if],
[while], etc.\). It introduces new comparison operators **ge**, **gt**,
**le**, and **lt**, \(along with the corresponding commands in the
**::tcl::mathop** namespace\), and encourages programmers to restrict the six operators **==**, **>=**, **>**, **<=**, **<** and **!=** to comparisons of numeric
values.

# Rationale

Tcl throughout its history has had comparison operators that freely compare
numeric and string values. These operators behave as expected if both their
arguments are numeric: they compare values on the real number line. Hence, 15
< 0x10 < 0b10001. Similarly, if presented with non-numeric strings, they
compare the strings in lexicographic order, as a programmer might expect:
"bambam" < "barney" < "betty" < "fred".

Trouble arises, however, when numeric and non-numeric strings are compared.
The rule for comparison is that mixed-type comparisons like this are treated
as string comparisons. The result is that **<** does not induce an order.
There are inconsistent comparison results, rendering **<** and friends
worthless for sorting. 0x10 < 0y < 1 < 0x10.

The problems with this inconsistency prompted changes in May of 2000,
introducing **eq** and **ne** operators that always perform string
comparison. For whatever reason, the four inequality operations never
followed. This leads to pitfalls for the unwary. It's fairly well entrenched
in the Tcl folklore that comparisons other than **eq** and **ne** should
be reserved for numeric arguments only, and experienced Tcl programmers know
to write:

	 if {[string compare $x $y] < 0} { ... }

in place of 

	 if {$x < $y} { ... }

# Proposal

Four new bareword operators, **ge**, **gt**, **le** and
**lt** shall be added to the expression parser and to the
**::tcl::mathop** command set. They will have precedence identical to
the existing operators **>=**, **>**, **<=** and **<**. They
will accept string values, and return 0 or 1 according to lexicographic
string comparison of their operators. This change is entirely backward
compatible \(it uses syntax that would previously have been erroneous\),
and should go in as soon as possible - no later than the next point
release, but ideally even in a patchlevel - so that programmers can
begin conversion as soon as possible. Use of the **==**, **>=**,
**>**, **<=**, **<**, and **!=** for comparing non-numeric
values shall immediately be deprecated.

The six string compare operators shall be declared to function so that
their results are the same as the results of [string compare]:

	    {$a lt $b}  <=> {[string compare $a $b] <  0}
	    {$a le $b}  <=> {[string compare $a $b] <= 0}
	    {$a eq $b}  <=> {[string compare $a $b] == 0}
	    {$a ne $b}  <=> {[string compare $a $b] != 0}
	    {$a gt $b}  <=> {[string compare $a $b] >  0}
	    {$a ge $b}  <=> {[string compare $a $b] >= 0}

It is also intended that any future changes to [string compare]
\(for example, a hypothetical change to make it follow Unicode collation
semantics\) will have the corresponding effect on these six operators.

Unlike what was specified in an earlier version of this TIP, no
changes are to  be made to the semantics of the comparison operators
 **==**, **>=**, **>**, **<=**, **<**, and **!=**.

# Discussion

## Forcing typed comparisons in Tcl

Programmers who wish to insure string semantics should restrict their
comparisons to the **lt**, **le**, **eq**, **ne**, **gt**
and **ge** operators.

Use of the **<**, **<=**, **==**, **!=**, **>** and **>=**
operators with operands that might be non-numeric shall be regarded
as poor programming style. Unless operands are constant, unary **\+**
should be used to force them to be numeric. Thus,

	 if {$x < $y} { ... }

should be relaced with

	 if {+$x < +$y} { ... }

The second comparison will have the effect of forcing both operands to be
numeric.

## Rejected alternatives

Earlier, the radical suggestion of _requiring_ the **<**,
**<=**, **==**, **!=**, **>** and **>=** operators to have
numeric arguments had been read into this TIP. It appears that there
is far too much outstanding code that is written like:

    if \{$x == "somestring"\} \{ ... \}

to have the more radical option be viable.

One possible alternative to excluding non-numeric arguments from the
comparison operators is to change their semantics so that all non-numeric
strings are greater than all numbers. This change would at least yield a
consistent ordering. The ordering that it yields would, however, be somewhat
surprising, and not terribly useful. \(It would at least be compatible with
today's scheme for numeric comparisons.\)

## Objections \(and rebuttals\)

In out-of-band discussions, several objections were raised. This section
attempts to address them.

   1. _Tcl's expression parser has a hard limit of 64 different binary
      operators. This proposal consumes four of them, leaving only 28. There
      is a concern that this is a less-than-effective use of a limited
      resource._

	    > The limit is self-imposed, in an effort to make the nodes of an
      expression parse tree fit in exactly 16 bytes \(or four int's\). It is far
      from obvious that this pretty size is actually useful. Few expressions
      are more than a few dozen parse nodes, and typical expressions are not
      parsed multiple times. It appears that neither the speed of the parse
      nor the size of the tree will be critical issues in most applications.
      In any case, we still have nearly half the operators left.

   2. _There is some concern that using barewords for operators was a bad
      idea in the first place._ The fact that

		 expr {"foo"}

	    > and

		 set x foo; expr {$x}

	     > both work, while

		 expr {foo}

	     > is an invalid bareword is arguably surprising.

	    > Nevertheless, we have committed to the approach with the **eq**,
      **ne**, **in** and **ni** operators. These are unlikely to go
      away. Adding **lt**, **le**, **gt** and **ge** will make this
      problem no better nor worse.

	    > Moreover, the language of [expr] is not the same as Tcl. It does not
      strip comments, parse into words, and apply Tcl's precise substitution
      rules - and it would be surprising if it did!  There are other "little
      languages" throughout Tcl - regular expressions, glob patterns, assembly
      code, and so on. [expr] is one among many.

   3. _There is concern that [expr], which was originally intended almost
      exclusively for numeric calculations, is being abused with string
      arguments and possibly string results._

	    > The author of this TIP contends that we introduced string values to
      [expr] a long time ago, certainly by the time that the **eq**,
      **ne**, **in** and **ni** operations were introduced.  It is true
      that the use of numeric conversions in [expr] is incoherent, as seen
      in:

		   % proc tcl::mathfunc::cat {args} { join $args {} }
		   % expr {cat(0x1,0x2,"a")}
		   0x10x2a
		   % expr {cat(0x1)}

		   1

	    > \(Bug [e7c21ed678] is another manifestation of this general
      problem.\) Once again, adding additional string operations
      that behave, with respect to data types, exactly the same
      as ones that are already there will neither fix nor exacerbate
      the general problem.

   4. _Because [expr] has no interpreted form, the operations must have
      bytecode representations. The space of available bytecodes is under even
      more pressure than the space of available operators, and must not be
      squandered on operations that are duplicative of already-available
      functionality such as [string compare]._

	    > The obvious rebuttal is that [string compare] is already bytecoded.
      There are no new operations required, merely a compiler that is smart
      enough to emit a short codeburst rather than a single bytecode. As an
      example, the code for the expression

		   {$x lt $y}

	    > could
      be:

		   (0) loadScalar1 %v0        # var "x"
		   (2) loadScalar1 %v1        # var "y"
		   (4) strcmp 
		   (5) push1 0        # "0"
		   (7) lt 

	    > For the other string operators, only the last bytecode in the burst
      would change.  No new bytecode operations are needed. In fact, this
      codeburst is identical code to that generated for the expression

		   {[string compare $x $y] < 0}

# Copyright

This document has been placed in the public domain.

Name change from tip/462.tip to tip/462.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
136
137
138
139
140
141
142
143
144
145

TIP:            462
Title:          Add New [info ps] Ensemble for Subprocess Management
Version:        $Revision: 1.4 $
Author:         Fr�d�ric Bonnet <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        23-Jan-2017
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes to improve Tcl's handling of subprocesses created by the 
'''exec''' and '''open''' commands by adding a new '''::tcl::process''' ensemble.

~ Rationale

This TIP is inspired by a https://github.com/flightaware/Tcl-bounties#stop-tcl-from-eating-child-process-exit-status-gratuitously%|%request from FlightAware%|% to fix the way Tcl currently
handles child process exit status. 

Subprocess creation can be either synchronous or asynchronous. In either case, 
a children with a non-zero return value indicates an error condition that is
bubbled up to the Tcl error handling mechanism. 

~~ Synchronous subprocesses

Synchronous subprocesses are created using the '''exec''' command with no '''&'''
terminal argument. Errors are raised synchronously as well.

~~ Asynchronous subprocesses

Asynchronous subprocesses can be created using two distinct methods:

   * '''exec''' command with a '''&''' terminal argument. In this case the command returns immediately with a list of the PIDs for all the subprocesses in the pipeline.

   * '''open "| command"'''. In this case the command returns immediately with the channel id of the pipe (hereafter '''$ch'''). The subprocess IDs are given by the '''[pid $ch]''' command. The subprocess status code and error conditions are processed upon channel closure with the '''[close $ch]'''.

~~ Error handling and status code

Errors are caught with the '''catch''' and '''try'''  commands, with status 
codes given in the '''-errorcode''' options dictionary entry and the 
'''errorCode''' global variable in the form '''{CHILDKILLED pid sigName msg}''' / '''{CHILDSTATUS pid code}''' / '''{CHILDSUSP pid sigName msg}'''. 

~~ C-level access

The Tcl library provides the following procedures for managing subprocesses (excerpts from the Tcl documentation):

   * '''Tcl_DetachPids''' may be called to ask Tcl to take responsibility for one or more processes whose process ids are contained in the pidPtr array passed as argument. The caller presumably has started these processes running in background and does not want to have to deal with them again.

   * '''Tcl_ReapDetachedProcs''' invokes the '''waitpid''' kernel call on each of the background processes so that its state can be cleaned up if it has exited. If the process has not exited yet, '''Tcl_ReapDetachedProcs''' does not wait for it to exit; it will check again the next time it is invoked. Tcl automatically calls '''Tcl_ReapDetachedProcs''' each time the exec command is executed, so in most cases it is not necessary for any code outside of Tcl to invoke Tcl_ReapDetachedProcs. However, if you call '''Tcl_DetachPids''' in situations where the exec command may never get executed, you may wish to call '''Tcl_ReapDetachedProcs''' from time to time so that background processes can be cleaned up.

   * '''Tcl_WaitPid''' is a thin wrapper around the facilities provided by the operating system to wait on the end of a spawned process and to check a whether spawned process is still running. It is used by '''Tcl_ReapDetachedProcs''' and the channel system to portably access the operating system.

Moreover, '''Tcl_WaitPid''' is blocking unless called with the '''WNOHANG''' option.

~~ Limitations

The current implementation is lacking several key features:

   * There is no way to get subprocess status other than through the error handling mechanism.

   * Consequently, there is no way to collect the status code of a asychronous subprocess created with the '''exec &''' method because such commands don't raise errors once the subprocesses are launched.

   * There is no non-blocking way to query asynchronous subprocess status codes; '''catch'''/'''try''' upon '''open |''' pipe closure is blocking.

   * Moreover, '''exec''' and '''open''' call '''Tcl_ReapDetachedProcs''', thereby cleaning up all pending information on terminated subprocesses. This prevents any advanced subprocess monitoring at the script level.

   * While reasonable in the general case, a non-zero return value does not always indicates an error condition for all kinds of programs, so it is desirable to provide a subprocess-specific mechanism that does not rely on Tcl's standard error handling facility.

~ Specifications

A new '''::tcl::process''' will be created:

   '''::tcl::process''' ''subcommand ?arg ...'': Subprocess management.

The following ''subcommand'' values are supported by '''::tcl::process''': 

   * '''::tcl::process list''': Returns the list of subprocess PIDs.

   * '''::tcl::process status''' ''?switches? ?pids?'': Returns a dictionary mapping subprocess PIDs to their respective statuses. If ''pids'' is specified as a list of PIDs then the command only returns the status of the matching subprocesses if they exist, and raises an error otherwise. The status value uses the same format as the '''errorCode''' global variable for terminated processes; for active processes an empty value is returned. Under the hood this command calls '''Tcl_WaitPid''' with the '''WNOHANG''' flag set for non-blocking behavior. 

   * '''::tcl::process purge''' ''?pids?'': Cleans up all data associated with terminated subprocesses. If ''pids'' is specified as a list of PIDs then the command only cleanup data for the matching subprocesses if they exist, and raises an error otherwise. If the process is still active then it does nothing.

   * '''::tcl::process autopurge''' ''?flag?'': Automatic purge facility. If ''flag'' is specified as a boolean value then it activates or deactivate autopurge. In all cases it returns the current status as a boolean value. When autopurge is active, '''Tcl_ReapDetachedProcs''' is called each time the '''exec''' command is executed or a pipe channel created by '''open''' is closed. When autopurge is inactive, '''::tcl::process purge''' must be called explicitly. By default autopurge is active and replicates the current Tcl behavior.

Additionally, '''::tcl::process status''' accepts the following switches:

   * '''-wait''': By default the command returns immediately (the underlying '''Tcl_WaitPid''' is called with the '''WNOHANG''' flag set) unless this switch is set. If ''pids'' is specified as a list of PIDs then the command waits until the matching subprocess statuses are available. If ''pids'' is not specified then it waits for all known subprocesses.

   * '''--''': Marks the end of switches. The argument following this one will be treated as the first arg even if it starts with a -. 

~ Examples

|% ::tcl::process autopurge
|true
|% ::tcl::process autopurge false
|false
|
|% set pid1 [exec command1 a b c | command2 d e f &]
|123 456
|% set chan [open "|command1 a b c | command2 d e f"]
|file123
|% set pid2 [pid $chan]
|789 1011
|
|% ::tcl::process list
|123 456 789 1011
|
|% ::tcl::process status
|123 {CHILDSTATUS 123 0} 456 {CHILDKILLED 456 SIGPIPE "write on pipe with no readers"} 789 {CHILDSUSP 789 SIGTTIN "background tty read"} 1011 {}
|
|% ::tcl::process status 123
|123 {CHILDSTATUS 123 0}
|
|% ::tcl::process status 1011
|1011 {}
|
|% ::tcl::process status -wait
|123 {CHILDSTATUS 123 0} 456 {CHILDKILLED 456 SIGPIPE "write on pipe with no readers"} 789 {CHILDSUSP 789 SIGTTIN "background tty read"} 1011 {CHILDSTATUS 1011 -1}
|
|% ::tcl::process status 1011
|1011 {CHILDSTATUS 1011 -1}
|
|% ::tcl::process purge
|% exec command1 1 2 3 &
|1213
|% ::tcl::process list
|1213

~ Rejected Alternatives

The first version proposed to implement the feature as a new '''ps''' option to
the existing '''info''' command. However, almost all operations in '''[info]'''
are things that just examine state, not change it, and that's a 
principle-of-least-astonishment that should be upheld for the sake of less 
experienced users.

~ Reference implementation

TBD

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|

|

|






|

|


|



|

|

|

|
|
|

|

|

|

|

|

|

|





|

|

|



|

|

|

|

|

|

|

|

|

|

|

|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|

|
|




|



|


>

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
136
137
138
139
140
141
142
143
144
145

# TIP 462: Add New [info ps] Ensemble for Subprocess Management

	Author:         Frédéric Bonnet <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        23-Jan-2017
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to improve Tcl's handling of subprocesses created by the 
**exec** and **open** commands by adding a new **::tcl::process** ensemble.

# Rationale

This TIP is inspired by a <https://github.com/flightaware/Tcl-bounties\#stop-tcl-from-eating-child-process-exit-status-gratuitously%\|%request> from FlightAware%\|% to fix the way Tcl currently
handles child process exit status. 

Subprocess creation can be either synchronous or asynchronous. In either case, 
a children with a non-zero return value indicates an error condition that is
bubbled up to the Tcl error handling mechanism. 

## Synchronous subprocesses

Synchronous subprocesses are created using the **exec** command with no **&**
terminal argument. Errors are raised synchronously as well.

## Asynchronous subprocesses

Asynchronous subprocesses can be created using two distinct methods:

   * **exec** command with a **&** terminal argument. In this case the command returns immediately with a list of the PIDs for all the subprocesses in the pipeline.

   * **open "\| command"**. In this case the command returns immediately with the channel id of the pipe \(hereafter **$ch**\). The subprocess IDs are given by the **[pid $ch]** command. The subprocess status code and error conditions are processed upon channel closure with the **[close $ch]**.

## Error handling and status code

Errors are caught with the **catch** and **try**  commands, with status 
codes given in the **-errorcode** options dictionary entry and the 
**errorCode** global variable in the form **\{CHILDKILLED pid sigName msg\}** / **\{CHILDSTATUS pid code\}** / **\{CHILDSUSP pid sigName msg\}**. 

## C-level access

The Tcl library provides the following procedures for managing subprocesses \(excerpts from the Tcl documentation\):

   * **Tcl\_DetachPids** may be called to ask Tcl to take responsibility for one or more processes whose process ids are contained in the pidPtr array passed as argument. The caller presumably has started these processes running in background and does not want to have to deal with them again.

   * **Tcl\_ReapDetachedProcs** invokes the **waitpid** kernel call on each of the background processes so that its state can be cleaned up if it has exited. If the process has not exited yet, **Tcl\_ReapDetachedProcs** does not wait for it to exit; it will check again the next time it is invoked. Tcl automatically calls **Tcl\_ReapDetachedProcs** each time the exec command is executed, so in most cases it is not necessary for any code outside of Tcl to invoke Tcl\_ReapDetachedProcs. However, if you call **Tcl\_DetachPids** in situations where the exec command may never get executed, you may wish to call **Tcl\_ReapDetachedProcs** from time to time so that background processes can be cleaned up.

   * **Tcl\_WaitPid** is a thin wrapper around the facilities provided by the operating system to wait on the end of a spawned process and to check a whether spawned process is still running. It is used by **Tcl\_ReapDetachedProcs** and the channel system to portably access the operating system.

Moreover, **Tcl\_WaitPid** is blocking unless called with the **WNOHANG** option.

## Limitations

The current implementation is lacking several key features:

   * There is no way to get subprocess status other than through the error handling mechanism.

   * Consequently, there is no way to collect the status code of a asychronous subprocess created with the **exec &** method because such commands don't raise errors once the subprocesses are launched.

   * There is no non-blocking way to query asynchronous subprocess status codes; **catch**/**try** upon **open \|** pipe closure is blocking.

   * Moreover, **exec** and **open** call **Tcl\_ReapDetachedProcs**, thereby cleaning up all pending information on terminated subprocesses. This prevents any advanced subprocess monitoring at the script level.

   * While reasonable in the general case, a non-zero return value does not always indicates an error condition for all kinds of programs, so it is desirable to provide a subprocess-specific mechanism that does not rely on Tcl's standard error handling facility.

# Specifications

A new **::tcl::process** will be created:

   **::tcl::process** _subcommand ?arg ..._: Subprocess management.

The following _subcommand_ values are supported by **::tcl::process**: 

   * **::tcl::process list**: Returns the list of subprocess PIDs.

   * **::tcl::process status** _?switches? ?pids?_: Returns a dictionary mapping subprocess PIDs to their respective statuses. If _pids_ is specified as a list of PIDs then the command only returns the status of the matching subprocesses if they exist, and raises an error otherwise. The status value uses the same format as the **errorCode** global variable for terminated processes; for active processes an empty value is returned. Under the hood this command calls **Tcl\_WaitPid** with the **WNOHANG** flag set for non-blocking behavior. 

   * **::tcl::process purge** _?pids?_: Cleans up all data associated with terminated subprocesses. If _pids_ is specified as a list of PIDs then the command only cleanup data for the matching subprocesses if they exist, and raises an error otherwise. If the process is still active then it does nothing.

   * **::tcl::process autopurge** _?flag?_: Automatic purge facility. If _flag_ is specified as a boolean value then it activates or deactivate autopurge. In all cases it returns the current status as a boolean value. When autopurge is active, **Tcl\_ReapDetachedProcs** is called each time the **exec** command is executed or a pipe channel created by **open** is closed. When autopurge is inactive, **::tcl::process purge** must be called explicitly. By default autopurge is active and replicates the current Tcl behavior.

Additionally, **::tcl::process status** accepts the following switches:

   * **-wait**: By default the command returns immediately \(the underlying **Tcl\_WaitPid** is called with the **WNOHANG** flag set\) unless this switch is set. If _pids_ is specified as a list of PIDs then the command waits until the matching subprocess statuses are available. If _pids_ is not specified then it waits for all known subprocesses.

   * **--**: Marks the end of switches. The argument following this one will be treated as the first arg even if it starts with a -. 

# Examples

	% ::tcl::process autopurge
	true
	% ::tcl::process autopurge false
	false
	
	% set pid1 [exec command1 a b c | command2 d e f &]
	123 456
	% set chan [open "|command1 a b c | command2 d e f"]
	file123
	% set pid2 [pid $chan]
	789 1011
	
	% ::tcl::process list
	123 456 789 1011
	
	% ::tcl::process status
	123 {CHILDSTATUS 123 0} 456 {CHILDKILLED 456 SIGPIPE "write on pipe with no readers"} 789 {CHILDSUSP 789 SIGTTIN "background tty read"} 1011 {}
	
	% ::tcl::process status 123
	123 {CHILDSTATUS 123 0}
	
	% ::tcl::process status 1011
	1011 {}
	
	% ::tcl::process status -wait
	123 {CHILDSTATUS 123 0} 456 {CHILDKILLED 456 SIGPIPE "write on pipe with no readers"} 789 {CHILDSUSP 789 SIGTTIN "background tty read"} 1011 {CHILDSTATUS 1011 -1}
	
	% ::tcl::process status 1011
	1011 {CHILDSTATUS 1011 -1}
	
	% ::tcl::process purge
	% exec command1 1 2 3 &
	1213
	% ::tcl::process list
	1213

# Rejected Alternatives

The first version proposed to implement the feature as a new **ps** option to
the existing **info** command. However, almost all operations in **[info]**
are things that just examine state, not change it, and that's a 
principle-of-least-astonishment that should be upheld for the sake of less 
experienced users.

# Reference implementation

TBD

# Copyright

This document has been placed in the public domain.

Name change from tip/463.tip to tip/463.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

TIP:		463
Title:		Command-Driven Substitutions for regsub
State:		Final
Type:		Project
Tcl-Version:	8.7
Vote:		Done
Post-History:	
Version:	$Revision: 1.6 $
Author:		Donal Fellows <[email protected]>
Created:	11-Feb-2017
Keywords:	Tcl, regular expression


~ Abstract

The '''regsub''' command can only do substitutions of a limited complexity.
This TIP adds an option to generate substitution text using another Tcl
command, allowing a more complex range of substitutions to be performed easily
and safely.

~ Rationale and Outline Proposal

Many scripts wish to perform subsitutions on a string where the text to be
substituted can be described by a regular expression, but where the text to be
substituted in cannot easily be generated by the '''regsub''' command. There
are workarounds for this, as seen in this example (from the Wiki):

| set text [subst [regsub -all {[a-zA-Z]} [\
|     regsub -all "\[\[$\\\\\]" $text {\\&}] {[
|         set c [scan & %c]
|         format %c [expr {$c\&96|(($c\&31)+12)%26+1}]
|     ]}]]

But it is not at all trivial to write such things! Instead, we should be able
to do this:

| set text [regsub -all -command {[a-zA-Z]} $text {apply {c {
|     scan $c %c c
|     format %c [expr {$c&96|(($c&31)+12)%26+1}]
| }}}]

It's going to be both safer (as there's no required non-obvious metadata
defanging preprocessing step) and faster (as we can do this as a command call
rather than a '''subst''' that needs separate bytecode compilation).

The parallels with Perl's "e" flag to its regular expression substitution
operator should be obvious.

~ Proposed Change

My proposal is that we add a flag to the '''regsub''' command, '''-command''',
that changes the interpretation and processing of the substitution argument.
When the flag is passed, instead of that argument being a string that is
processed for '''&''' and backslash-number sequences, it is instead
interpreted as a command prefix; the various captured substrings (minimally
the entire string passed in, but also any captured substrings specified in the
RE) will become extra arguments added, and the result will be evaluated and
the result of that evaluation will be used as the string to substitute in. If
the '''-all''' option is not given, the substitution command will be called at
most once, whereas if '''-all''' is given, the substitution command will be
called for as many times as the regular expression matches. The indices in the
original script that matched will not be available.

Non-OK results will be passed through to the surrounding script.

Substitutions too complex to be described by a simple command can be done by
using a procedure or '''apply'''/lambda-term (as in the example above). The
arguments received by the command invoked by '''regsub -command''' will be
exactly the substrings that were matched, with no other substitutions
performed on them.

~~ Examples

The command:

| regsub -all -command {\w} "ab-cd-ef-gh" {  puts  }

will give '''---''' as its result and print the letters '''a''' to '''h''',
one per line in that order.

The command:

| regsub -command {\W(\W)} "ab cd,{ef gh,} ij" {apply {{x y} {
|     scan $y %c c
|     format %%%02x $c
| }}}

will produce this result:

| ab cd%7bef gh,} ij

~ Implementation

http://core.tcl.tk/tcl/timeline?r=tip-463

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|

|




|



|
|

|
|
|
|
|




|
|
|
|

|
|
|




|

|


|
|

|

|
|






|
|



|



|

|




|
|
|
|



|

|

|

|


>

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

# TIP 463: Command-Driven Substitutions for regsub
	State:		Final
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Done
	Post-History:	

	Author:		Donal Fellows <[email protected]>
	Created:	11-Feb-2017
	Keywords:	Tcl, regular expression
-----

# Abstract

The **regsub** command can only do substitutions of a limited complexity.
This TIP adds an option to generate substitution text using another Tcl
command, allowing a more complex range of substitutions to be performed easily
and safely.

# Rationale and Outline Proposal

Many scripts wish to perform subsitutions on a string where the text to be
substituted can be described by a regular expression, but where the text to be
substituted in cannot easily be generated by the **regsub** command. There
are workarounds for this, as seen in this example \(from the Wiki\):

	 set text [subst [regsub -all {[a-zA-Z]} [\
	     regsub -all "\[\[$\\\\\]" $text {\\&}] {[
	         set c [scan & %c]
	         format %c [expr {$c\&96|(($c\&31)+12)%26+1}]
	     ]}]]

But it is not at all trivial to write such things! Instead, we should be able
to do this:

	 set text [regsub -all -command {[a-zA-Z]} $text {apply {c {
	     scan $c %c c
	     format %c [expr {$c&96|(($c&31)+12)%26+1}]
	 }}}]

It's going to be both safer \(as there's no required non-obvious metadata
defanging preprocessing step\) and faster \(as we can do this as a command call
rather than a **subst** that needs separate bytecode compilation\).

The parallels with Perl's "e" flag to its regular expression substitution
operator should be obvious.

# Proposed Change

My proposal is that we add a flag to the **regsub** command, **-command**,
that changes the interpretation and processing of the substitution argument.
When the flag is passed, instead of that argument being a string that is
processed for **&** and backslash-number sequences, it is instead
interpreted as a command prefix; the various captured substrings \(minimally
the entire string passed in, but also any captured substrings specified in the
RE\) will become extra arguments added, and the result will be evaluated and
the result of that evaluation will be used as the string to substitute in. If
the **-all** option is not given, the substitution command will be called at
most once, whereas if **-all** is given, the substitution command will be
called for as many times as the regular expression matches. The indices in the
original script that matched will not be available.

Non-OK results will be passed through to the surrounding script.

Substitutions too complex to be described by a simple command can be done by
using a procedure or **apply**/lambda-term \(as in the example above\). The
arguments received by the command invoked by **regsub -command** will be
exactly the substrings that were matched, with no other substitutions
performed on them.

## Examples

The command:

	 regsub -all -command {\w} "ab-cd-ef-gh" {  puts  }

will give **---** as its result and print the letters **a** to **h**,
one per line in that order.

The command:

	 regsub -command {\W(\W)} "ab cd,{ef gh,} ij" {apply {{x y} {
	     scan $y %c c
	     format %%%02x $c
	 }}}

will produce this result:

	 ab cd%7bef gh,} ij

# Implementation

<http://core.tcl.tk/tcl/timeline?r=tip-463>

# Copyright

This document has been placed in the public domain.

Name change from tip/464.tip to tip/464.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

TIP:            464
Title:          Support for Multimedia Keys on Windows
Version:        $Revision: 1.6 $
Author:         Ralf Fassel <[email protected]>
Author:         Andreas Leitgeb <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        28-Jan-2017
Post-History:   
Keywords:       Tk,keyboard,keycode
Tcl-Version:    8.5


~ Abstract

This TIP proposes adding support for the multimedia keys present on many
modern keyboards.

~ Rationale

Tk is lacking support for the multimedia keys as described on
https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx

|VK_VOLUME_DOWN        0xAE   Volume Down key
|VK_VOLUME_UP          0xAF   Volume Up key
|VK_MEDIA_NEXT_TRACK   0xB0   Next Track key
|VK_MEDIA_PREV_TRACK   0xB1   Previous Track key
|VK_MEDIA_STOP         0xB2   Stop Media key
|VK_MEDIA_PLAY_PAUSE   0xB3   Play/Pause Media key

Linux supports these as, e.g., XF86AudioPlay, XF86AudioPrev, XF86AudioNext.
Tk should support them as well so that application programmers can make use of
the keys as appropriate.

Because this is driven by changing external circumstances, it is propsed that
this TIP be backported to all future-releaseable versions of Tk (i.e., 8.5
onwards).

~ Proposal

The table of supported keys should be extended to include the following named
keys:

 * '''XF86AudioLowerVolume''' - the volume-down key

 * '''XF86AudioMute''' - the volume-mute key

 * '''XF86AudioNext''' - the next-track key

 * '''XF86AudioPlay''' - the start-playback key

 * '''XF86AudioPrev''' - the previous-track key

 * '''XF86AudioRaiseVolume''' - the volume-up key

 * '''XF86AudioStop''' - the stop-playback key

The above list does not imply any ordering in the implementation.

~ Implementation

The support can be added by extending some keymapping lookup tables in Tk.

A Ticket already exists with a proposed patch
[http://core.tcl.tk/tk/tktview/499526180d6cd5ca7c02eed96c10e9d3630a807c] and
fvogel has also created a branch
[http://core.tcl.tk/tk/timeline?r=tip-464].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|




|


|

|
|
|
|
|
|






|
|

|




|

|

|

|

|

|

|



|




|

|

|


>

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

# TIP 464: Support for Multimedia Keys on Windows

	Author:         Ralf Fassel <[email protected]>
	Author:         Andreas Leitgeb <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        28-Jan-2017
	Post-History:   
	Keywords:       Tk,keyboard,keycode
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes adding support for the multimedia keys present on many
modern keyboards.

# Rationale

Tk is lacking support for the multimedia keys as described on
<https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx>

	VK_VOLUME_DOWN        0xAE   Volume Down key
	VK_VOLUME_UP          0xAF   Volume Up key
	VK_MEDIA_NEXT_TRACK   0xB0   Next Track key
	VK_MEDIA_PREV_TRACK   0xB1   Previous Track key
	VK_MEDIA_STOP         0xB2   Stop Media key
	VK_MEDIA_PLAY_PAUSE   0xB3   Play/Pause Media key

Linux supports these as, e.g., XF86AudioPlay, XF86AudioPrev, XF86AudioNext.
Tk should support them as well so that application programmers can make use of
the keys as appropriate.

Because this is driven by changing external circumstances, it is propsed that
this TIP be backported to all future-releaseable versions of Tk \(i.e., 8.5
onwards\).

# Proposal

The table of supported keys should be extended to include the following named
keys:

 * **XF86AudioLowerVolume** - the volume-down key

 * **XF86AudioMute** - the volume-mute key

 * **XF86AudioNext** - the next-track key

 * **XF86AudioPlay** - the start-playback key

 * **XF86AudioPrev** - the previous-track key

 * **XF86AudioRaiseVolume** - the volume-up key

 * **XF86AudioStop** - the stop-playback key

The above list does not imply any ordering in the implementation.

# Implementation

The support can be added by extending some keymapping lookup tables in Tk.

A Ticket already exists with a proposed patch
<http://core.tcl.tk/tk/tktview/499526180d6cd5ca7c02eed96c10e9d3630a807c>  and
fvogel has also created a branch
<http://core.tcl.tk/tk/timeline?r=tip-464> .

# Copyright

This document has been placed in the public domain.

Name change from tip/465.tip to tip/465.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

TIP:            465
Title:          Change Rule 8 of the Dodekalogue to Cut Some Corner Cases
Version:        $Revision: 1.2 $
Author:         Andreas Leitgeb <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        03-Mar-2017
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes to make '''$'''-substitution more conforming to naive
expectations and just rule out certain odd-ball uses that can safely be
assumed to not appear in serious use, but only in crafted examples "serving"
for confusion, or as accidentally legal interpretation of mistyped Tcl code.

~ Rationale

Back in the days where '''$'''-substitution was added to Tcl, it was designed
to be as syntactically simple as possible. Back then, Tcl was still an
interpreted language, so optimising parse time was top priority.  For this, it
was designed that a sequence starting with '''${''' would end at the '''next
close brace''' no matter how many open braces or backslashes are passed by,
and '''$arr(''' would end at the '''next close paren''' no matter how many
open parens are found before.  This enables odd-ball corner cases that work in
an interactive shell at top level, as tried by newbies:

|   set "{{{" 42; puts ${{{{}

but fail within a braced block, unless a comment like:

|   # }}} }}}

follows within the same block. These are just strange parts of Tcl, that
nobody can seriously claim to use for good.

Another surprising part is with arrays, where parens are treated
asymmetrically, in that any number of bare open parens, but also quote chars
or braces may be part of the index in a '''$arr(...)''' substitution, but
first bare close paren terminates the token.  Quote characters or braces have
no significance, apart from that bare close braces might pre-maturely finish
the enclosing braced block, which may only be evident to seasoned Tclers - and
not even always to them.

The final motivation for writing up this TIP came while discussing one part of
[282]: assignment to array elements.

An informal poll showed a clear preference towards bare '''array(...)'''
naming on left hand side of proposed assignment, without sympathy for any need
of explicit disambiguation by quoting or tagging.

Generally disallowing bare open parens, quotes and braces within array indices
would mean that array indices on left hand side of an assignment could follow
same rules as on right hand side, and parsing an array by these new rules
would make sure, that where parsing as a function call and parsing as an array
are both successful, then both parses would end up consuming the same portion
of the expression body - a prerequisite for making a sound decision about
following assignment operator.

Without having array parses and function parses agreeing on close paren, then
it is possible that parsing as an array will see a trailing assignment
operator that would otherwise have been nested in a subexpression, or even
part of a quoted literal value.

Because of the low expected impact on real code, a target of 8.7 is considered
feasible.

~ Implementation

A full implementation of this TIP is now checked in on branch ''tip-465''.

~ Alternatives

The following points show alternatives that would make sense, but would make
the currently rather simple implementation of this TIP ways more complicated:

 * Allow bare parens in array indices if properly paired. Quotes and braces
   are still disallowed (even if paired), to avoid cases of bad nesting:
   '''{(})'''.  This might save users two backslashes in some rare cases where
   a close paren in the index is already backslash-escaped.

 * Specifically add backslash-quoting to the "body" of '''${...}'''.  After
   all, the "body" is a variable name, and not a nested structure like most
   braced words in Tcl. This would make some odd variable names once again
   possible, but now in a consistent syntax that doesn't affect enclosing
   blocks.

 * '''${...}''' syntax could also be further restricted by disallowing open
   braces and final backslashes, just to enforce "well-behaving" tokens.

 * A much stricter alternative would disallow unbalanced braces even within
   "-quoted and unquoted literals. This would disallow common but dangerous
   idioms like ''append var "{"'', which may be followed by an ''append var
   "}"'' in the same block and work, until one of these two commands gets
   moved into a nested block. The correct and safe way is, of course,
   backslash-escaping bare braces within string literals.  Good Code(tm)
   wouldn't be affected by this alternative change.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|




|

|


|
|
|



|



|






|






|

|



















|

|

|





|
|


|





|




|
|

|


|


>

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

# TIP 465: Change Rule 8 of the Dodekalogue to Cut Some Corner Cases

	Author:         Andreas Leitgeb <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        03-Mar-2017
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to make **$**-substitution more conforming to naive
expectations and just rule out certain odd-ball uses that can safely be
assumed to not appear in serious use, but only in crafted examples "serving"
for confusion, or as accidentally legal interpretation of mistyped Tcl code.

# Rationale

Back in the days where **$**-substitution was added to Tcl, it was designed
to be as syntactically simple as possible. Back then, Tcl was still an
interpreted language, so optimising parse time was top priority.  For this, it
was designed that a sequence starting with **$\{** would end at the **next
close brace** no matter how many open braces or backslashes are passed by,
and **$arr\(** would end at the **next close paren** no matter how many
open parens are found before.  This enables odd-ball corner cases that work in
an interactive shell at top level, as tried by newbies:

	   set "{{{" 42; puts ${{{{}

but fail within a braced block, unless a comment like:

	   # }}} }}}

follows within the same block. These are just strange parts of Tcl, that
nobody can seriously claim to use for good.

Another surprising part is with arrays, where parens are treated
asymmetrically, in that any number of bare open parens, but also quote chars
or braces may be part of the index in a **$arr\(...\)** substitution, but
first bare close paren terminates the token.  Quote characters or braces have
no significance, apart from that bare close braces might pre-maturely finish
the enclosing braced block, which may only be evident to seasoned Tclers - and
not even always to them.

The final motivation for writing up this TIP came while discussing one part of
[[282]](282.md): assignment to array elements.

An informal poll showed a clear preference towards bare **array\(...\)**
naming on left hand side of proposed assignment, without sympathy for any need
of explicit disambiguation by quoting or tagging.

Generally disallowing bare open parens, quotes and braces within array indices
would mean that array indices on left hand side of an assignment could follow
same rules as on right hand side, and parsing an array by these new rules
would make sure, that where parsing as a function call and parsing as an array
are both successful, then both parses would end up consuming the same portion
of the expression body - a prerequisite for making a sound decision about
following assignment operator.

Without having array parses and function parses agreeing on close paren, then
it is possible that parsing as an array will see a trailing assignment
operator that would otherwise have been nested in a subexpression, or even
part of a quoted literal value.

Because of the low expected impact on real code, a target of 8.7 is considered
feasible.

# Implementation

A full implementation of this TIP is now checked in on branch _tip-465_.

# Alternatives

The following points show alternatives that would make sense, but would make
the currently rather simple implementation of this TIP ways more complicated:

 * Allow bare parens in array indices if properly paired. Quotes and braces
   are still disallowed \(even if paired\), to avoid cases of bad nesting:
   **\{\(\}\)**.  This might save users two backslashes in some rare cases where
   a close paren in the index is already backslash-escaped.

 * Specifically add backslash-quoting to the "body" of **$\{...\}**.  After
   all, the "body" is a variable name, and not a nested structure like most
   braced words in Tcl. This would make some odd variable names once again
   possible, but now in a consistent syntax that doesn't affect enclosing
   blocks.

 * **$\{...\}** syntax could also be further restricted by disallowing open
   braces and final backslashes, just to enforce "well-behaving" tokens.

 * A much stricter alternative would disallow unbalanced braces even within
   "-quoted and unquoted literals. This would disallow common but dangerous
   idioms like _append var "\{"_, which may be followed by an _append var
   "\}"_ in the same block and work, until one of these two commands gets
   moved into a nested block. The correct and safe way is, of course,
   backslash-escaping bare braces within string literals.  Good Code\(tm\)
   wouldn't be affected by this alternative change.

# Copyright

This document has been placed in the public domain.

Name change from tip/466.tip to tip/466.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
TIP:            466
Title:          Revised Implementation of the Text Widget
Version:        $Revision: 1.11 $
Author:         Fran�ois Vogel <[email protected]>
Author:         Gregor Cramer <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        10-Mar-2017
Post-History:   
Keywords:       Tk,text widget
Tcl-Version:    8.7


~ Abstract

This TIP proposes the replacement of the current implementation of the text
widget (the "legacy" text widget) by a revised implementation offering a large
number of advantages.

~ Rationale

The Tk text widget has become increasingly complex as long as incremental
improvements and features have been added from time to time. In that process,
some known long-standing issues have become very difficult to tackle, for
instance the long line problem regarding lack of performance.

Gregor Cramer, in the process of using the text widget in one of his
<
|
<
|
|
|
|
|
|
|
|
|
>

|


|


|








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

# TIP 466: Revised Implementation of the Text Widget

	Author:         François Vogel <[email protected]>
	Author:         Gregor Cramer <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        10-Mar-2017
	Post-History:   
	Keywords:       Tk,text widget
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes the replacement of the current implementation of the text
widget \(the "legacy" text widget\) by a revised implementation offering a large
number of advantages.

# Rationale

The Tk text widget has become increasingly complex as long as incremental
improvements and features have been added from time to time. In that process,
some known long-standing issues have become very difficult to tackle, for
instance the long line problem regarding lack of performance.

Gregor Cramer, in the process of using the text widget in one of his
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478


 * A large number of new features

 * Numerous bug fixes

 * Very few incompatibilities with the legacy text widget

~ Proposal

The proposal is to replace the legacy code with the new implementation.

The author of the revised implementation has written a well documented website
[http://scidb.sourceforge.net/tk/revised-text-widget.html]
describing in details the issues with the legacy code, how he fixed these
issues, and what features he has changed or improved.

It was not deemed feasible nor necessary to copy/paste/reformat all the
information of the above website into the present TIP. Only the new features
and incompatibilities are highlighted here, as opposed to detailed rationales
about each change.

A version of the '''text''' man page, consistent with the changes and improvements proposed by the present TIP, can be seen at 
http://scidb.sourceforge.net/tk/text.html
This version of the man page is colorized, with blue meaning "changed", and green meaning "new", so that it is easier to spot what's different from the legacy text widget.

~~ Performance Improvements

Detailed performance comparison between legacy code and revised code can be
found at [http://scidb.sourceforge.net/tk/comparison.html] but these are the
key points:

 * Long line problem, especially with many tags, is eliminated: in general
   only O(N log N) in revised version, was a higher order polynomial time in
   legacy code.

 * Display is faster: smoother scrolling, faster response time.
   [http://scidb.sourceforge.net/tk/display.html]

 * Undo/redo is much faster: a completely new implementation has been worked
   out, directly working on the text segments.
   [http://scidb.sourceforge.net/tk/undo.html]

~~ New Features

Detailed explanations and rationales for each of the items below can be found
at [http://scidb.sourceforge.net/tk/revised-text-widget.html]

 * Undo/redo is handling tags (this was requesteed in Issue #1561991 and
   Issue #1027741, embedded images, embedded windows, and also marks if option
   ''-steadymarks'' is enabled

 * Additional widget state '''readonly'''

 * Hyphenation and full-justification support

 > * Support of hyphenation (Issue #1096580 is fixed), with new helper
      functions '''tk_textinsert''' and '''tk_textReplace''', and with new
      switches to ''pathName'' '''count''', ''pathName'' '''get''', and
      ''pathName'' '''search'''

 > * Additional justification mode '''full'''

 > * Additional wrap mode '''codepoint''', and new widget option
   '''-useunibreak'''. New subcommand ''pathName'' '''brks'''

 > * Additional option '''-lang''' used to guide hyphenation engines.

 * Additional subcommands:

 > * ''pathName'' '''checksum'''

 > * ''pathName'' '''clear'''

 > * ''pathName'' '''edit altered'''

 > * ''pathName'' '''edit info'''

 > * ''pathName'' '''edit inspect'''

 > * ''pathName'' '''edit irreversible'''

 > * ''pathName'' '''edit recover'''

 > * ''pathName'' '''inspect'''

 > * ''pathName'' '''isclean'''

 > * ''pathName'' '''isdead'''

 > * ''pathName'' '''isempty'''

 > * ''pathName'' '''lineno'''

 > * ''pathName'' '''load'''

 > * ''pathName'' '''mark compare'''

 > * ''pathName'' '''mark exists'''

 > * ''pathName'' '''mark generate'''

 > * ''pathName'' '''tag clear'''

 > * ''pathName'' '''tag findnext'''

 > * ''pathName'' '''tag findprev'''

 > * ''pathName'' '''tag getrange'''

 > * ''pathName'' '''tag priority'''

 > * ''pathName'' '''watch'''

 * Additional tag attributes:

 > * '''-eolcolor'''

 > * '''-hyphencolor'''

 > * '''-hyphenrules'''

 > * '''-inactivebackground'''

 > * '''-inactiveforeground'''

 > * '''-inactiveselectbackground'''

 > * '''-inactiveselectforeground'''

 > * '''-indentbackground'''

 > * '''-undo'''

 * Additional widget options:

 > * '''-endindex'''

 > * '''-eolchar'''

 > * '''-eolcolor'''

 > * '''-eotchar'''

 > * '''-eotcolor'''

 > * '''-hyphencolor'''

 > * '''-hyphenrules'''

 > * '''-hyphens'''

 > * '''-inactiveselectforeground'''

 > * '''-insertforeground'''

 > * '''-maxredo'''

 > * '''-maxundosize'''

 > * '''-responsiveness'''

 > * '''-showendofline'''

 > * '''-showendoftext'''

 > * '''-showinsertforeground'''

 > * '''-spacemode'''

 > * '''-startindex'''

 > * '''-steadymarks'''

 > * '''-synctime'''

 > * '''-tagging'''

 * Extensions to the syntax for indices:

 > * new specifier '''begin'''

 > * new syntax ''tag''.'''current.first''', ''tag''.'''current.last'''

 > * new syntax '''@first,last'''

 * Additional features of existing subcommands:

 > * Additional option '''-marks''' for ''pathName'' '''delete''' command

 > * Additional optional parameter ''direction'' for ''pathName'' '''mark set''' sub-command

 > * New virtual event '''<<Altered>>''' to support new sub-command
     ''pathName'' '''edit altered'''

 > * Extensions to commands ''pathName'' '''edit reset''' and ''pathName''
     '''edit separator'''

 * Extended command ''pathName'' '''tag names'''

 * Additional switch for ''pathName'' '''dump'''

 * Additional option '''-extents''' for ''pathName'' '''bbox'''
     and ''pathName'' '''dlineinfo'''

 * Additional option '''-discardspecial''' for ''pathName'' '''mark names''', ''pathName'' '''mark next''', and ''pathName'' '''mark previous'''.

 * Additional optional parameter ''pattern'' for ''pathName'' '''mark names''', ''pathName'' '''mark next''', and ''pathName'' '''mark previous'''.

 * New helper commands:

 > * '''tk_mergeRange'''

 > * '''tk_textInsert'''

 > * '''tk_textReplace'''

 > * '''tk_textRebindMouseWheel'''

 * Additional option '''-owner''' for embedded window

 * Additional option '''-tags''' for embedded images and embedded windows

~~ Bug Fixes

 * Bug fixed in TkTextGetIndex

 * Bug fixed in TkTextGetIndexFromObj

 * Bug fixed in DeleteIndexRange (note that this bugfix implies that deletion at the end of the text handles the last newline now differently - slight incompatibility with the legacy text widget)

 * Bug fixed in TkTextDeleteTag/TagBindEvent

 * Problems fixed with '''-startline'''/'''-endline'''

 * Problems fixed with tag event handling

 * Several bug fixes with '''undo''

 * '''Edit modified''' confusing results fixed with new command
   '''edit altered'''

 * Severe problems with command '''sync''' fixed

 * Invalid changes in disabled widget are marked as deprecated

 * Inaccurate wrapping algorithm fixed

 * Bugs in display logic fixed

 * Insert cursor is now fully visible in all conditions

 * Trimming spaces: Issue #1082213 is invalid, the fix put in trunk (8.7) has
   been reverted (but there is now the new option '''-spacemode''' that can be
   set to '''trim''')

 * Issues with display of selections fixed

 * '''Update''' is no longer wasting the processor time since superfluous
   update computations are not done anymore

 * Bugs in context drawing support (OS X) fixed

 * Bugs fixed in tkUnixRFont.c

 * Several bug fixes related to handling/positioning of the insertion cursor

Details on each of these bugs can be found in the "Bugs/Issues in Original
Implementation" section at
http://scidb.sourceforge.net/tk/revised-text-widget.html

~~ Incompatibilities with Legacy Version

Based on the author's website, the following incompatibilities are currently
known:

 * [449] (undo/redo to Return Range of Characters) was not adapted into the
   revised implementation, because Issue #1217222 - the basis for [449] -
   is now featured by:

 > 1. The new undo implementation, because also the tag associations will be
      restored, and

 > 2. The powerful '''watch''' command, which also provides the affected
      ranges (with constant runtime behavior).

 > Moreover, the '''tk_mergeRange''' function convenience function has been
   implemented in the revised version.

 * The special selection tag '''sel''' can no longer be elided (would be
   useless anyway).

 * Tag options (introduced in 8.6.6) -overstrikefg and -underlinefg were
   renamed to '''-overstrikecolor''' and '''-underlinecolor'''

 * The new index syntax '''@first,last''' is incompatible with the legacy
   version but it is not expected that any existing application will break,
   certainly nobody is using such a form for the name of a mark or image

 * The default value of 50 ms for the new '''-responsiveness''' option is
   incompatible to prior releases, but it shouldn't matter here, because
   nobody wants flickering, and nobody is using special tricks with a short
   mouse hovering while the widget is scrolling. Setting the responsiveness to zero restores the old
   behavior of the text widget.

 * <<UndoStack>> is generated with any change on the undo stack, not only when
   the undo stack or the redo stack becomes empty or non-empty

 * '''-startline'''/'''-endline''' behavior was subtly changed in some corner cases

 * In revised implementation "+N chars" and "-N chars" refer to characters,
   and no longer to indices (which was the case in legacy code for backwards
   compatibility reasons).

~~ Deprecated Commands and Options

 * Tag options (introduced in 8.6.6) '''-overstrikefg''' and
   '''-underlinefg''' were renamed to -overstrikecolor and -underlinecolor

 * edit '''undodepth'''|'''redodepth'''|'''canundo'''|'''canredo''' are
   replaced by more general '''edit info'''

 * Widget options '''-startline'''/'''-endline'''' are replaced by
   -startindex/-endindex

~~ Drawbacks

 * The increase in memory usage is not very high (but a bit high), and despite
   this, in many cases, especially if many tags are used, and/or undo is
   enabled, the revised version is even decreasing the memory usage.

Detailed memory comparison between legacy code and revised code can be found
at http://scidb.sourceforge.net/tk/comparison.html

~~ Known Issues in the Revised Implementation

Based on the author's website, currently only these issues are known: 

 * The code for the implementation has increased by more than 100%, and about
   70% of the old code has been changed. The revised implementation needs more
   testing, the text widget is very complex, and bugs are expected. And a few
   additions are not yet well tested.

 * Function '''tk_textCopy''' is copying hidden (elided) text. This seems to
   be unexpected, but it's the behavior of the original implementation.
   Probably this is a bug and should be corrected.

 * Adding/deleting tags covering a large range of text is still quite time
   consuming.

 * The display line with the insert cursor is redrawn each time the cursor
   blinks, which causes a steady stream of graphics traffic. It would be
   desirable if the cursor update will be performed with a specialized and
   efficient redraw function.

 * If option '''-spacemode''' is set to trim, then '''get -displaychars'''
   should probably return trimmed spaces. Currently this command is not
   trimming spaces, so the result may not coincide with the visible text.

 * The '''search -regexp''' sub-command is still not yet fully implemented,
   see Tk documentation.

 * The revised widget still ignores modifying commands if state is
   not normal; this behavior is unreasonable, but conforms to the original
   version.

 * Currently the special index specifier '''begin''' has the lowest
   precedence, although it should have the same precedence as the special
   index special '''end''' (see section INDICES). In a future release this
   should be corrected.  The current behavior is a workaround, avoiding that
   existing applications will break with the introduction of '''begin'''.

 * The implementation still contains some TODO's of minor issues. 

Also, the following should be noted:

 * With the revised version there are failing tests on all platforms, they
   need to be fixed (by fixing the expected result in the test, or by fixing
   the text widget code).

 * More tests should be written to exercise the new or changed features.

 * The OS X case should be more tested on a real Mac, because it's the only
   platform using context drawing.

~~ Miscellaneous

 * No function signature pertaining to a public interface was changed. Also
   public data structures haven't been touched.

 * All recent new features brought in trunk in the legacy version have their
   counterpart in the revised version, have been improved in performance and
   have no known drawbacks. Minor incompatibilities are however identified
   here and there.

~ Target Release

Given the amount of changes, also because of our usual precautions regarding
backwards compatibility, and despite the very high quality of the code and the
fact it passes (almost all) the previously existing test suite, it is deemed
reasonable to target Tcl/Tk 8.7 (or 9.0), but neither the 8.6 nor the 8.5
streams of releases, which will continue to implement the legacy text widget
code.

Support of versions back to 8.5 is currently included in the revised code, but
will be removed (because it's useless for use in trunk only) at the time the
new code will get merged into trunk.

~ Implementation

Implementation of the revised text widget code has been placed in branch
[http://core.tcl.tk/tk/timeline?r=revised_text] of the fossil repository.

This implementation compiles on Linux, Windows, and OS X. It respects the
standards of Tk (C99 standard, and also the Tcl source code formatting
described in [247]).

The man page for the text widget has been contributed by jima and is included
in the revised_text branch.

The expected results of many tests were adjusted to take into account that the
revised implementation is better optimizing, so some trace results of display
line computation are different. Other adjustments were required because of bug
fixes.

~ Open Questions

 * tkTextUndo.c implements a specialized undo/redo, not using the legacy
   tkUndo.c. Reasons for this are stated at the top of tkTextUndo.c. It is
   interesting to note that, in the revised_text branch, tkUndo.c is not even
   compiled anymore, except on Linux (for no apparent reason). This is dead
   code waiting for use case by a widget. At least, compilation on Linux
   should be removed, but couldn't we even rename tkTextUndo.c to tkUndo.c and
   forget about the old implementation? tkTextUndo.c is also a shareable
   implementation (in the spirit of [104]).

 * Actual removal of deprecated features or keep them (some are marked as
   deprecated, but actually still supported)?

~ Copyright

This document has been placed in the public domain.

The author of the revised text widget code has explicitly placed his code of
the text widget under the same license as Tcl.








|




|








|
|


|


|



|



|



|

|


|

|
|
|

|



|
|
|
|

|

|
|

|



|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|



|

|

|

|

|

|

|

|

|



|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|



|

|

|



|

|

|
|

|
|

|

|

|
|

|

|



|

|

|

|

|

|

|





|



|



|

|
|

|









|
|
|



|


|







|

|




|
|


|


|
|

|


|
|

|
|

|



|








|

|
|
|

|

|
|

|
|

|


|

|




|

|








|











|



|






|

|

|






|
|






|









|



|
|




|


|


|


|
|


|






|



|
|



|

|
|

|





>
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478

 * A large number of new features

 * Numerous bug fixes

 * Very few incompatibilities with the legacy text widget

# Proposal

The proposal is to replace the legacy code with the new implementation.

The author of the revised implementation has written a well documented website
<http://scidb.sourceforge.net/tk/revised-text-widget.html> 
describing in details the issues with the legacy code, how he fixed these
issues, and what features he has changed or improved.

It was not deemed feasible nor necessary to copy/paste/reformat all the
information of the above website into the present TIP. Only the new features
and incompatibilities are highlighted here, as opposed to detailed rationales
about each change.

A version of the **text** man page, consistent with the changes and improvements proposed by the present TIP, can be seen at 
<http://scidb.sourceforge.net/tk/text.html>
This version of the man page is colorized, with blue meaning "changed", and green meaning "new", so that it is easier to spot what's different from the legacy text widget.

## Performance Improvements

Detailed performance comparison between legacy code and revised code can be
found at <http://scidb.sourceforge.net/tk/comparison.html>  but these are the
key points:

 * Long line problem, especially with many tags, is eliminated: in general
   only O\(N log N\) in revised version, was a higher order polynomial time in
   legacy code.

 * Display is faster: smoother scrolling, faster response time.
   <http://scidb.sourceforge.net/tk/display.html> 

 * Undo/redo is much faster: a completely new implementation has been worked
   out, directly working on the text segments.
   <http://scidb.sourceforge.net/tk/undo.html> 

## New Features

Detailed explanations and rationales for each of the items below can be found
at <http://scidb.sourceforge.net/tk/revised-text-widget.html> 

 * Undo/redo is handling tags \(this was requesteed in Issue \#1561991 and
   Issue \#1027741, embedded images, embedded windows, and also marks if option
   _-steadymarks_ is enabled

 * Additional widget state **readonly**

 * Hyphenation and full-justification support

	 > \* Support of hyphenation \(Issue \#1096580 is fixed\), with new helper
      functions **tk\_textinsert** and **tk\_textReplace**, and with new
      switches to _pathName_ **count**, _pathName_ **get**, and
      _pathName_ **search**

	 > \* Additional justification mode **full**

	 > \* Additional wrap mode **codepoint**, and new widget option
   **-useunibreak**. New subcommand _pathName_ **brks**

	 > \* Additional option **-lang** used to guide hyphenation engines.

 * Additional subcommands:

	 > \* _pathName_ **checksum**

	 > \* _pathName_ **clear**

	 > \* _pathName_ **edit altered**

	 > \* _pathName_ **edit info**

	 > \* _pathName_ **edit inspect**

	 > \* _pathName_ **edit irreversible**

	 > \* _pathName_ **edit recover**

	 > \* _pathName_ **inspect**

	 > \* _pathName_ **isclean**

	 > \* _pathName_ **isdead**

	 > \* _pathName_ **isempty**

	 > \* _pathName_ **lineno**

	 > \* _pathName_ **load**

	 > \* _pathName_ **mark compare**

	 > \* _pathName_ **mark exists**

	 > \* _pathName_ **mark generate**

	 > \* _pathName_ **tag clear**

	 > \* _pathName_ **tag findnext**

	 > \* _pathName_ **tag findprev**

	 > \* _pathName_ **tag getrange**

	 > \* _pathName_ **tag priority**

	 > \* _pathName_ **watch**

 * Additional tag attributes:

	 > \* **-eolcolor**

	 > \* **-hyphencolor**

	 > \* **-hyphenrules**

	 > \* **-inactivebackground**

	 > \* **-inactiveforeground**

	 > \* **-inactiveselectbackground**

	 > \* **-inactiveselectforeground**

	 > \* **-indentbackground**

	 > \* **-undo**

 * Additional widget options:

	 > \* **-endindex**

	 > \* **-eolchar**

	 > \* **-eolcolor**

	 > \* **-eotchar**

	 > \* **-eotcolor**

	 > \* **-hyphencolor**

	 > \* **-hyphenrules**

	 > \* **-hyphens**

	 > \* **-inactiveselectforeground**

	 > \* **-insertforeground**

	 > \* **-maxredo**

	 > \* **-maxundosize**

	 > \* **-responsiveness**

	 > \* **-showendofline**

	 > \* **-showendoftext**

	 > \* **-showinsertforeground**

	 > \* **-spacemode**

	 > \* **-startindex**

	 > \* **-steadymarks**

	 > \* **-synctime**

	 > \* **-tagging**

 * Extensions to the syntax for indices:

	 > \* new specifier **begin**

	 > \* new syntax _tag_.**current.first**, _tag_.**current.last**

	 > \* new syntax **@first,last**

 * Additional features of existing subcommands:

	 > \* Additional option **-marks** for _pathName_ **delete** command

	 > \* Additional optional parameter _direction_ for _pathName_ **mark set** sub-command

	 > \* New virtual event **<<Altered>>** to support new sub-command
     _pathName_ **edit altered**

	 > \* Extensions to commands _pathName_ **edit reset** and _pathName_
     **edit separator**

 * Extended command _pathName_ **tag names**

 * Additional switch for _pathName_ **dump**

 * Additional option **-extents** for _pathName_ **bbox**
     and _pathName_ **dlineinfo**

 * Additional option **-discardspecial** for _pathName_ **mark names**, _pathName_ **mark next**, and _pathName_ **mark previous**.

 * Additional optional parameter _pattern_ for _pathName_ **mark names**, _pathName_ **mark next**, and _pathName_ **mark previous**.

 * New helper commands:

	 > \* **tk\_mergeRange**

	 > \* **tk\_textInsert**

	 > \* **tk\_textReplace**

	 > \* **tk\_textRebindMouseWheel**

 * Additional option **-owner** for embedded window

 * Additional option **-tags** for embedded images and embedded windows

## Bug Fixes

 * Bug fixed in TkTextGetIndex

 * Bug fixed in TkTextGetIndexFromObj

 * Bug fixed in DeleteIndexRange \(note that this bugfix implies that deletion at the end of the text handles the last newline now differently - slight incompatibility with the legacy text widget\)

 * Bug fixed in TkTextDeleteTag/TagBindEvent

 * Problems fixed with **-startline**/**-endline**

 * Problems fixed with tag event handling

 * Several bug fixes with **undo_

 * **Edit modified** confusing results fixed with new command
   **edit altered**

 * Severe problems with command **sync** fixed

 * Invalid changes in disabled widget are marked as deprecated

 * Inaccurate wrapping algorithm fixed

 * Bugs in display logic fixed

 * Insert cursor is now fully visible in all conditions

 * Trimming spaces: Issue \#1082213 is invalid, the fix put in trunk \(8.7\) has
   been reverted \(but there is now the new option **-spacemode** that can be
   set to **trim**\)

 * Issues with display of selections fixed

 * **Update** is no longer wasting the processor time since superfluous
   update computations are not done anymore

 * Bugs in context drawing support \(OS X\) fixed

 * Bugs fixed in tkUnixRFont.c

 * Several bug fixes related to handling/positioning of the insertion cursor

Details on each of these bugs can be found in the "Bugs/Issues in Original
Implementation" section at
<http://scidb.sourceforge.net/tk/revised-text-widget.html>

## Incompatibilities with Legacy Version

Based on the author's website, the following incompatibilities are currently
known:

 * [[449]](449.md) \(undo/redo to Return Range of Characters\) was not adapted into the
   revised implementation, because Issue \#1217222 - the basis for [[449]](449.md) -
   is now featured by:

	 > 1. The new undo implementation, because also the tag associations will be
      restored, and

	 > 2. The powerful **watch** command, which also provides the affected
      ranges \(with constant runtime behavior\).

	 > Moreover, the **tk\_mergeRange** function convenience function has been
   implemented in the revised version.

 * The special selection tag **sel** can no longer be elided \(would be
   useless anyway\).

 * Tag options \(introduced in 8.6.6\) -overstrikefg and -underlinefg were
   renamed to **-overstrikecolor** and **-underlinecolor**

 * The new index syntax **@first,last** is incompatible with the legacy
   version but it is not expected that any existing application will break,
   certainly nobody is using such a form for the name of a mark or image

 * The default value of 50 ms for the new **-responsiveness** option is
   incompatible to prior releases, but it shouldn't matter here, because
   nobody wants flickering, and nobody is using special tricks with a short
   mouse hovering while the widget is scrolling. Setting the responsiveness to zero restores the old
   behavior of the text widget.

 * <<UndoStack>> is generated with any change on the undo stack, not only when
   the undo stack or the redo stack becomes empty or non-empty

 * **-startline**/**-endline** behavior was subtly changed in some corner cases

 * In revised implementation "\+N chars" and "-N chars" refer to characters,
   and no longer to indices \(which was the case in legacy code for backwards
   compatibility reasons\).

## Deprecated Commands and Options

 * Tag options \(introduced in 8.6.6\) **-overstrikefg** and
   **-underlinefg** were renamed to -overstrikecolor and -underlinecolor

 * edit **undodepth**\|**redodepth**\|**canundo**\|**canredo** are
   replaced by more general **edit info**

 * Widget options **-startline**/**-endline**' are replaced by
   -startindex/-endindex

## Drawbacks

 * The increase in memory usage is not very high \(but a bit high\), and despite
   this, in many cases, especially if many tags are used, and/or undo is
   enabled, the revised version is even decreasing the memory usage.

Detailed memory comparison between legacy code and revised code can be found
at <http://scidb.sourceforge.net/tk/comparison.html>

## Known Issues in the Revised Implementation

Based on the author's website, currently only these issues are known: 

 * The code for the implementation has increased by more than 100%, and about
   70% of the old code has been changed. The revised implementation needs more
   testing, the text widget is very complex, and bugs are expected. And a few
   additions are not yet well tested.

 * Function **tk\_textCopy** is copying hidden \(elided\) text. This seems to
   be unexpected, but it's the behavior of the original implementation.
   Probably this is a bug and should be corrected.

 * Adding/deleting tags covering a large range of text is still quite time
   consuming.

 * The display line with the insert cursor is redrawn each time the cursor
   blinks, which causes a steady stream of graphics traffic. It would be
   desirable if the cursor update will be performed with a specialized and
   efficient redraw function.

 * If option **-spacemode** is set to trim, then **get -displaychars**
   should probably return trimmed spaces. Currently this command is not
   trimming spaces, so the result may not coincide with the visible text.

 * The **search -regexp** sub-command is still not yet fully implemented,
   see Tk documentation.

 * The revised widget still ignores modifying commands if state is
   not normal; this behavior is unreasonable, but conforms to the original
   version.

 * Currently the special index specifier **begin** has the lowest
   precedence, although it should have the same precedence as the special
   index special **end** \(see section INDICES\). In a future release this
   should be corrected.  The current behavior is a workaround, avoiding that
   existing applications will break with the introduction of **begin**.

 * The implementation still contains some TODO's of minor issues. 

Also, the following should be noted:

 * With the revised version there are failing tests on all platforms, they
   need to be fixed \(by fixing the expected result in the test, or by fixing
   the text widget code\).

 * More tests should be written to exercise the new or changed features.

 * The OS X case should be more tested on a real Mac, because it's the only
   platform using context drawing.

## Miscellaneous

 * No function signature pertaining to a public interface was changed. Also
   public data structures haven't been touched.

 * All recent new features brought in trunk in the legacy version have their
   counterpart in the revised version, have been improved in performance and
   have no known drawbacks. Minor incompatibilities are however identified
   here and there.

# Target Release

Given the amount of changes, also because of our usual precautions regarding
backwards compatibility, and despite the very high quality of the code and the
fact it passes \(almost all\) the previously existing test suite, it is deemed
reasonable to target Tcl/Tk 8.7 \(or 9.0\), but neither the 8.6 nor the 8.5
streams of releases, which will continue to implement the legacy text widget
code.

Support of versions back to 8.5 is currently included in the revised code, but
will be removed \(because it's useless for use in trunk only\) at the time the
new code will get merged into trunk.

# Implementation

Implementation of the revised text widget code has been placed in branch
<http://core.tcl.tk/tk/timeline?r=revised_text>  of the fossil repository.

This implementation compiles on Linux, Windows, and OS X. It respects the
standards of Tk \(C99 standard, and also the Tcl source code formatting
described in [[247]](247.md)\).

The man page for the text widget has been contributed by jima and is included
in the revised\_text branch.

The expected results of many tests were adjusted to take into account that the
revised implementation is better optimizing, so some trace results of display
line computation are different. Other adjustments were required because of bug
fixes.

# Open Questions

 * tkTextUndo.c implements a specialized undo/redo, not using the legacy
   tkUndo.c. Reasons for this are stated at the top of tkTextUndo.c. It is
   interesting to note that, in the revised\_text branch, tkUndo.c is not even
   compiled anymore, except on Linux \(for no apparent reason\). This is dead
   code waiting for use case by a widget. At least, compilation on Linux
   should be removed, but couldn't we even rename tkTextUndo.c to tkUndo.c and
   forget about the old implementation? tkTextUndo.c is also a shareable
   implementation \(in the spirit of [[104]](104.md)\).

 * Actual removal of deprecated features or keep them \(some are marked as
   deprecated, but actually still supported\)?

# Copyright

This document has been placed in the public domain.

The author of the revised text widget code has explicitly placed his code of
the text widget under the same license as Tcl.

Name change from tip/467.tip to tip/467.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

TIP:            467
Title:          Move TIP Collection to Fossil
Version:        $Revision: 1.5 $
Author:         Mark Janssen <[email protected]>
State:          Draft
Type:           Process
Vote:           Pending
Created:        14-Mar-2017
Post-History:   
Keywords:       migration


~ Abstract

The Tcl TIP collection shall be moved to Fossil and the process of managing
TIPs shall use Fossil as much as possible. The TIP format will be changed from
a TIP-specific form to Markdown.

~ Rationale

Triggered by some people having issues with changing content on current TIP
website and discussion on the #tcl chat, I have experimented with fossil as a
medium to host the Tcl TIP collection.

The current TIP storage and handling requires a lot of scripts that need to be
maintained by the TCT and it is less open than it could be.
There are also advantages to switching to Fossil in place of CVS.

 * Fossil has embedded Markdown rendering.

 * Fossil is already used to manage the Tcl and Tk sources.

 * TIP discussion and CFVs can be done and tracked using fossil tickets.

 * Fossil events could also track CFV's and Vote results

 * CVS is extremely vulnerable to problems with system administration on a
   single host. With a fossil-based system, it is much simpler to have
   multiple repositories.

Besides Fossil supporting Markdown out of the box, markdown is also better
option for the future than the current format. The value of making up
your own plain text format in this age is debatable (especially for the TIP
requirements). Markdown has widely available options to convert to other
formats without any need for the community to maintain the converters, and
supports key extra features such as embedded images (which are important for
some Tk TIPs, and never worked particularly well with the old TIP format).

~ Specification

Proposed URL for the new repository will be http://core.tcl.tk/tips

~~ Backwards compatibility

 * ''tip.tcl.tk/<NUM>.html'' should still show a rendered result. This could be redirected to ''core.tcl.tk/tips/doc/trunk/tip/<NUM>.md''

 * ''tip.tcl.tk'' offers several converted formats (XML, *roff, ...). The fossil option will be to use the ''core.tcl.tk/tips/file/tip/<NUM>.md?download'' URL to get the raw Markdown downloads. For getting the other options one could convert the markdown source file using something like pandoc.

 * E-mail address are not hidden in the source and in the rendered result.  If e-mail addresses need to be hidden there are two options

    1. Remove mails from source.

    2. Hide e-mails in fossil.

    3. Hide e-mails in the webhost.

  Option 2. doesn't help much as the mails are still online in the raw markdown files. Option 1. loses information. Suggested is to leave the addresses untouched. 

~~ Process

TBD

~~ TIP Format

The Markdown tip format has one extension to standard Markdown:

Any TIP.md file will have a mandatory preamble starting with the title (for
fossil rendering) and ending with a `------` on a single line. Between these
parts there is tab indented meta information about the tip. (Tab indented so
it renders nicer in fossil, 4 spaces would also work)

Example from [0]:

|# TIP 0: Tcl Core Team Basic Rules
|    State:          Final
|    Type:           Process
|    Vote:           Done
|    Post-History:
|------

~ Implementation

 * There is a proof of concept conversion (with CVS history) at
   https://fossil.mpcjanssen.nl/tips

 * The scripts for the automatic conversion are at
   https://fossil.mpcjanssen.nl/tip-migration

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|





|


|




















|
|

|
|

|

|

|

|

|











|



|



|
|
|
|

|

|
|
|
|
|
|

|

|
|


|

|


>

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

# TIP 467: Move TIP Collection to Fossil

	Author:         Mark Janssen <[email protected]>
	State:          Draft
	Type:           Process
	Vote:           Pending
	Created:        14-Mar-2017
	Post-History:   
	Keywords:       migration
-----

# Abstract

The Tcl TIP collection shall be moved to Fossil and the process of managing
TIPs shall use Fossil as much as possible. The TIP format will be changed from
a TIP-specific form to Markdown.

# Rationale

Triggered by some people having issues with changing content on current TIP
website and discussion on the \#tcl chat, I have experimented with fossil as a
medium to host the Tcl TIP collection.

The current TIP storage and handling requires a lot of scripts that need to be
maintained by the TCT and it is less open than it could be.
There are also advantages to switching to Fossil in place of CVS.

 * Fossil has embedded Markdown rendering.

 * Fossil is already used to manage the Tcl and Tk sources.

 * TIP discussion and CFVs can be done and tracked using fossil tickets.

 * Fossil events could also track CFV's and Vote results

 * CVS is extremely vulnerable to problems with system administration on a
   single host. With a fossil-based system, it is much simpler to have
   multiple repositories.

Besides Fossil supporting Markdown out of the box, markdown is also better
option for the future than the current format. The value of making up
your own plain text format in this age is debatable \(especially for the TIP
requirements\). Markdown has widely available options to convert to other
formats without any need for the community to maintain the converters, and
supports key extra features such as embedded images \(which are important for
some Tk TIPs, and never worked particularly well with the old TIP format\).

# Specification

Proposed URL for the new repository will be <http://core.tcl.tk/tips>

## Backwards compatibility

 * _tip.tcl.tk/<NUM>.html_ should still show a rendered result. This could be redirected to _core.tcl.tk/tips/doc/trunk/tip/<NUM>.md_

 * _tip.tcl.tk_ offers several converted formats \(XML, \*roff, ...\). The fossil option will be to use the _core.tcl.tk/tips/file/tip/<NUM>.md?download_ URL to get the raw Markdown downloads. For getting the other options one could convert the markdown source file using something like pandoc.

 * E-mail address are not hidden in the source and in the rendered result.  If e-mail addresses need to be hidden there are two options

    1. Remove mails from source.

    2. Hide e-mails in fossil.

    3. Hide e-mails in the webhost.

  Option 2. doesn't help much as the mails are still online in the raw markdown files. Option 1. loses information. Suggested is to leave the addresses untouched. 

## Process

TBD

## TIP Format

The Markdown tip format has one extension to standard Markdown:

Any TIP.md file will have a mandatory preamble starting with the title \(for
fossil rendering\) and ending with a \`------\` on a single line. Between these
parts there is tab indented meta information about the tip. \(Tab indented so
it renders nicer in fossil, 4 spaces would also work\)

Example from [[0]](0.md):

	# TIP 0: Tcl Core Team Basic Rules
	    State:          Final
	    Type:           Process
	    Vote:           Done
	    Post-History:
	------

# Implementation

 * There is a proof of concept conversion \(with CVS history\) at
   <https://fossil.mpcjanssen.nl/tips>

 * The scripts for the automatic conversion are at
   <https://fossil.mpcjanssen.nl/tip-migration>

# Copyright

This document has been placed in the public domain.

Name change from tip/468.tip to tip/468.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

TIP:		468
Title:		Support Passing TCP listen Backlog Size Option to TCP Socket Creation
Version:	$Revision: 1.1 $
Author:		Shannon Noe <[email protected]>
State:		Draft
Type:		Project
Vote:		Pending
Created:	03-Apr-2017
Post-History:  
Keywords:	Tcl, socket, SOMAXCONN
Tcl-Version:	8.7


~ Abstract

This TIP adds the ability to control the TCP backlog depth used by the
''listen'' system call within the '''socket''' Command. The API function,
'''Tcl_OpenTcpServerEx''', will be extended to allow the passing of the
backlog value. Currently, the SOMAXCONN macro is used as the default. Backlog
values are hard coded to a minimum of 100. The backlog values of 1 and 0 are
useful on the Linux platform.

~ Rationale

Modern Linux TCP supports the kernel managing the listen queue for TCP
sockets. Multiple processes open the same socket address and ports with
SOREUSEADDR and SOREUSEPORT. Each process then uses a backlog value of 1 to
process a single connection at a time. This is explained in detail on this
website
http://veithen.github.io/2014/01/01/how-tcp-backlog-works-in-linux.html

Tighter control over this would allow Tcl scripts to have tighter control over
whether to support a large backlog of sockets waiting to be opened. (Exceeding
the limit would cause the OS to automatically reject the socket connection,
which might be preferable in some high-availability situations to being
blocked for an unknown amount of time.)

~ Specification

A '''Tcl_OpenTcpServerEx''' function will be changed to add a ''backlog''
parameter with this signature:

 > Tcl_Channel '''Tcl_OpenTcpServerEx'''(Tcl_Interp *''interp'', const char *
    ''service'', const char *''myHost'', unsigned int ''flags'',  int ''backlog'',
    Tcl_TcpAcceptProc *''acceptProc'', ClientData ''acceptProcData'')

As for the Tcl side, the '''socket''' command gains a new optional switch that
are only valid for server sockets: ?'''-backlog''' ''int''?. Omitting the
parameter will cause the default value to be used.

Tcl code includes local macro’s for SOMAXCONN which override all platforms
values for SOMAXCONN. This makes backwards compatibility easier. We only need
to preserve the macro value in the default code path.

~ Reference Implementation

Please refer to the ''tip-???'' branch of the core Tcl repository.

~ Backwards Compatibility

The '''Tcl_OpenTcpServerEx''' will retain the old behavior by default as
SOMAXCONN. The SOMAXCONN is defined by macros in the Tcl source. All Tcl code
paths with a listen() system call pass a backlog value. No new code paths are
introduced, only new values for the listen backlog parameter.

The '''socket''' command will be backwards compatible. The default
'''-backlog''' parameter is set to ''SOMAXCONN''. Omission of the new
parameter provides the current behavior.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|
|




|






|


|


|

|

|


|
|
|

|
|






|

|

|

|

|


|
|


|


>

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

# TIP 468: Support Passing TCP listen Backlog Size Option to TCP Socket Creation

	Author:		Shannon Noe <[email protected]>
	State:		Draft
	Type:		Project
	Vote:		Pending
	Created:	03-Apr-2017
	Post-History:  
	Keywords:	Tcl, socket, SOMAXCONN
	Tcl-Version:	8.7
-----

# Abstract

This TIP adds the ability to control the TCP backlog depth used by the
_listen_ system call within the **socket** Command. The API function,
**Tcl\_OpenTcpServerEx**, will be extended to allow the passing of the
backlog value. Currently, the SOMAXCONN macro is used as the default. Backlog
values are hard coded to a minimum of 100. The backlog values of 1 and 0 are
useful on the Linux platform.

# Rationale

Modern Linux TCP supports the kernel managing the listen queue for TCP
sockets. Multiple processes open the same socket address and ports with
SOREUSEADDR and SOREUSEPORT. Each process then uses a backlog value of 1 to
process a single connection at a time. This is explained in detail on this
website
<http://veithen.github.io/2014/01/01/how-tcp-backlog-works-in-linux.html>

Tighter control over this would allow Tcl scripts to have tighter control over
whether to support a large backlog of sockets waiting to be opened. \(Exceeding
the limit would cause the OS to automatically reject the socket connection,
which might be preferable in some high-availability situations to being
blocked for an unknown amount of time.\)

# Specification

A **Tcl\_OpenTcpServerEx** function will be changed to add a _backlog_
parameter with this signature:

 > Tcl\_Channel **Tcl\_OpenTcpServerEx**\(Tcl\_Interp \*_interp_, const char \*
    _service_, const char \*_myHost_, unsigned int _flags_,  int _backlog_,
    Tcl\_TcpAcceptProc \*_acceptProc_, ClientData _acceptProcData_\)

As for the Tcl side, the **socket** command gains a new optional switch that
are only valid for server sockets: ?**-backlog** _int_?. Omitting the
parameter will cause the default value to be used.

Tcl code includes local macro’s for SOMAXCONN which override all platforms
values for SOMAXCONN. This makes backwards compatibility easier. We only need
to preserve the macro value in the default code path.

# Reference Implementation

Please refer to the _tip-???_ branch of the core Tcl repository.

# Backwards Compatibility

The **Tcl\_OpenTcpServerEx** will retain the old behavior by default as
SOMAXCONN. The SOMAXCONN is defined by macros in the Tcl source. All Tcl code
paths with a listen\(\) system call pass a backlog value. No new code paths are
introduced, only new values for the listen backlog parameter.

The **socket** command will be backwards compatible. The default
**-backlog** parameter is set to _SOMAXCONN_. Omission of the new
parameter provides the current behavior.

# Copyright

This document has been placed in the public domain.

Name change from tip/469.tip to tip/469.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

TIP:            469
Title:          A Callback for Channel-Exception Conditions
Version:        $Revision: 1.3 $
Author:         Andreas Leitgeb <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        16-Apr-2017
Post-History:   
Keywords:       Tcl,event handling
Tcl-Version:    8.7


~ Abstract

This TIP proposes to extend the '''fileevent''' Tcl command to also accept the
keyword '''exception''' for its second argument. This will allow to register a
callback for the specific event that the OS reports an exception on the
channel, while ignoring read- or writability.

~ Rationale

Tcl already allows registering for exceptions in its C-API function
Tcl_CreateChannelHandler(). This TIP merely enables the command
'''fileevent''' to pass TCL_EXCEPTION for the mask in the call to
Tcl_CreateChannelHandler().

On Linux, there exist special "files" that are always readable or writable
without blocking, but certain (hardware-related) events are reported as
exceptions on the channel.  The example at hand is the "sysfs"-API for GPIO
(general purpose input output) where level-changes on GPIO pins are reported
as exceptions on the channel. For details see
[https://www.kernel.org/doc/Documentation/gpio/sysfs.txt] and the paragraphs
about "value".

Listening for readable plus exceptions (as Tcl automatically does when asking
for readable event) doesn't help here, because then the event would
continuously fire, as reading the current level on a pin never blocks.

The only way to react to level-changes (short of busy-looping) is to have the
internal select/poll call specify exclusively the exception notification for
that channel.

~ Specification

This document proposes to add the keyword '''exception''' to the
'''fileevent''' command, where so far only '''readable''' and '''writable'''
are allowed.

If '''exception''' is given as event specifier, then a handler script is
registered, cleared or queried just like with '''readable''' or
'''writable'''.

Since '''readable''' or '''writable''' already check for exception as well,
registering an exception event for a channel that already has readable and/or
writable handlers registered makes little sense, but allowing it does not
raise any issues that having both readable and writable handlers wouldn't
already have, so being fussy about it would confuse more than it could help to
avoid confusion.

~ Alternatives

The ''piio'' extension provides event registration on its own, but its support
for certain IO-chipsets lags behind the sysfs-API.

With '''exception''' becoming its own event type, then '''readable''' and
'''writable''' would no longer need to also fire on exceptions, but
compatibility forbids this particular follow-up change.

~ Compatibility

No incompatibilities are introduced.

~ Reference Implementation

A really bare-bones reference implementation is available as a patch
[http://paste.tclers.tk/4231]. Also, a branch named tip-469 in fossil has been created: [https://core.tcl.tk/tcl/timeline?r=tip-469].

A thus-patched tclsh can successfully wait for input-level changes
on TIP-author's "nano-pi" raspberryPI-like platform with a chipset
not yet supported by piio.

Documentation and test updates yet to be done.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|



|


|
|
|


|

|

|


|
|


|



|

|
|


|
|
|

|






|

|


|
|


|



|


|







|


>

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

# TIP 469: A Callback for Channel-Exception Conditions

	Author:         Andreas Leitgeb <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        16-Apr-2017
	Post-History:   
	Keywords:       Tcl,event handling
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes to extend the **fileevent** Tcl command to also accept the
keyword **exception** for its second argument. This will allow to register a
callback for the specific event that the OS reports an exception on the
channel, while ignoring read- or writability.

# Rationale

Tcl already allows registering for exceptions in its C-API function
Tcl\_CreateChannelHandler\(\). This TIP merely enables the command
**fileevent** to pass TCL\_EXCEPTION for the mask in the call to
Tcl\_CreateChannelHandler\(\).

On Linux, there exist special "files" that are always readable or writable
without blocking, but certain \(hardware-related\) events are reported as
exceptions on the channel.  The example at hand is the "sysfs"-API for GPIO
\(general purpose input output\) where level-changes on GPIO pins are reported
as exceptions on the channel. For details see
<https://www.kernel.org/doc/Documentation/gpio/sysfs.txt>  and the paragraphs
about "value".

Listening for readable plus exceptions \(as Tcl automatically does when asking
for readable event\) doesn't help here, because then the event would
continuously fire, as reading the current level on a pin never blocks.

The only way to react to level-changes \(short of busy-looping\) is to have the
internal select/poll call specify exclusively the exception notification for
that channel.

# Specification

This document proposes to add the keyword **exception** to the
**fileevent** command, where so far only **readable** and **writable**
are allowed.

If **exception** is given as event specifier, then a handler script is
registered, cleared or queried just like with **readable** or
**writable**.

Since **readable** or **writable** already check for exception as well,
registering an exception event for a channel that already has readable and/or
writable handlers registered makes little sense, but allowing it does not
raise any issues that having both readable and writable handlers wouldn't
already have, so being fussy about it would confuse more than it could help to
avoid confusion.

# Alternatives

The _piio_ extension provides event registration on its own, but its support
for certain IO-chipsets lags behind the sysfs-API.

With **exception** becoming its own event type, then **readable** and
**writable** would no longer need to also fire on exceptions, but
compatibility forbids this particular follow-up change.

# Compatibility

No incompatibilities are introduced.

# Reference Implementation

A really bare-bones reference implementation is available as a patch
<http://paste.tclers.tk/4231> . Also, a branch named tip-469 in fossil has been created: <https://core.tcl.tk/tcl/timeline?r=tip-469> .

A thus-patched tclsh can successfully wait for input-level changes
on TIP-author's "nano-pi" raspberryPI-like platform with a chipset
not yet supported by piio.

Documentation and test updates yet to be done.

# Copyright

This document has been placed in the public domain.

Name change from tip/47.tip to tip/47.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
136
137
138
139
140
141
142
143
144
145
146
147
148

149
150

151
152
153
154
155
156
157
158
159
160
161
162

163
164
165
166
167
168

169
170
171

172
173
174

175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191

TIP:            47
Title:          Modifying Tk to Allow Writing X Window managers
Version:        $Revision: 1.9 $
Author:         Neil McKay <[email protected]>
Author:         Andreas Kupries <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        19-Jul-2001
Post-History:   
Tcl-Version:    8.4


~ Abstract

With a few modifications to the Tk core, extensions could be
written that would allow X window managers to be implemented
as Tcl/Tk scripts.

~ Requirements

Writing X window managers in Tk requires some facilities that
the current Tk core doesn't provide. A window manager
must be able to:

 * draw to, and handle events on, the display's
	root window (including ''<Create>'',
	''<MapRequest>'', ''<ResizeRequest>'', ''<CirculateRequest>'',
	and ''<ConfigureRequest>'' events, which are currently
	ignored)

 * embed arbitrary windows inside Tk windows

 * receive ''<PropertyNotify>'' events from embedded windows

 * perform a variety of other X-specific operations

Window embedding can be handled by an extension, if it is not
incorporated into the Tk frame widget at some later time.
Likewise, the X-specific operations can be handled by
an extension. However, Tk as it currently stands cannot
access the display's root window, nor can ''<PropertyNotify>''
events be received from embedded windows; doing these
things requires core modifications.

~ Root Window Access

The root window is special in many ways:

 * It does not need to be created

 * It cannot be destroyed, moved, or resized

 * Only one process can receive ''<ButtonPress>'' and ''<ButtonRelease>''
	events from it, and only one process can have the
	''SubstructureRedirect'' and ''ResizeRedirect'' masks set

 * It has no physical parent window

Because of these properties, access to the root window via a Tk
widget presents some difficulties. First, the widget's window cannot
be created in the standard way; however, this problem may be solved by
providing a non-standard creation routine via the
''Tk_SetClassProcs'' procedure described in [5].
Likewise, the event handling required by the root window
can be enabled in an extension, although some care is required
when enabling ''<ButtonPress>'' and certain other events.
What really causes problems is the lack of a physical parent.
There are many places in Tk where it is assumed that only
toplevel widgets have no physical parent within the application;
this is reflected in the Tk source by the use of the ''TK_TOP_LEVEL'' flag.
This flag is used to mean different things in different places.
In particular, the ''TK_TOP_LEVEL'' flag may mean:

 * This window is a toplevel widget

 * This widget has a wrapper window

 * This widget's window is controlled by the window manager

 * This window is at the top of a physical window hierarchy
	within the current application

In the current version of Tk, toplevel widgets have all of these
properties, and no other widgets have any of these properties;
hence a single flag suffices.
If we create a widget whose window is the display's root, then this
is no longer the case; a root window has the last property, but not
the first three. For this reason, it is necessary to replace
the ''TK_TOP_LEVEL'' flag with at least two distinct flags. A better
idea is to replace the ''TK_TOP_LEVEL'' flag with four flags, one for each
of the properties listed above. (Even in a standard Tk distribution,
this replacement is desirable for documentation reasons, since it will
indicate what property of a toplevel widget is important in the current
circumstances.) We must also replace the ''Tk_IsTopLevel'' macro with
several macros, or just eliminate it entirely.

One possible set of flag names is:

 TK_TOP_LEVEL: this is a toplevel widget

 TK_HAS_WRAPPER: this window has a wrapper window

 TK_WIN_MANAGED: this window is controlled by the window manager

 TK_TOP_HIERARCHY: this window is at the top of a physical window hierarchy

~ New Event Bindings and Substitutions

A window manager must be able to intercept certain events on the root
window that the standard Tk distribution doesn't recognize, and
it must be able to obtain information about those events. In particular,
it needs to respond to ''<CirculateRequest>'', ''<ConfigureRequest>'',
''<CreateNotify>'', ''<MapRequest>'', and ''<ResizeRequest>'' events.
These events are ignored by standard Tk, and need not be enabled by
default; however, they need to be included in the list of events recognized
by the Tk ''[bind]'' command. Adding this facility is very simple.

Obtaining information about these events is also necessary.
This is usually done via %-substitutions in the ''[bind]'' command;
however, there are two pieces of information that are necessary
for implementing a window manager that cannot be obtained via
the current %-substitution mechanism: the numerical X window ID,
required to handle ''<CreateNotify>'' events, and the property name,
for handling ''<PropertyNotify>'' events. This information could be
obtained by adding two new %-substitutions:

 %i: substitute the numerical window ID for the event

 %P: substitute the atom name for the property being changed

~ Propagating <PropertyNotify> Events

In order to receive ''<PropertyNotify>'' events from embedded windows,
the Tk event loop must handle events not just for windows that
are represented by ''Tk_Window'' structures, but also for their children.
One way to accomplish this is to add another flag for the
''Tk_Window'' struct, and alter the event loop so that
it will also look at a window's parent, if the event is a
''<PropertyNotify>'' event. The relevant part of the Tk event loop
currently looks like this:

|
|winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow);
|if (winPtr == NULL) {
|    if (eventPtr->type == PropertyNotify) {
|	TkSelPropProc(eventPtr);
|    }

|    return;
|}

|

If the flag for propagating ''<PropertyNotify>'' events is
''TK_PROP_PROPCHANGE'', then the code above must be modified to look
approximately like this:

|
|winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow);
|if (winPtr == NULL) {
|    if (eventPtr->type != PropertyNotify) {
|	return;
|    }

|    TkSelPropProc(eventPtr);
|    parentXId = (parent of handlerWindow);
|    winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, parentXId);
|    if (winPtr == NULL) {
|	return;
|    }

|    if (!(winPtr->flags & TK_PROP_PROPCHANGE)) {
|	return;
|    }

|    handlerWindow = parentXId;
|    return;
|}

|

~ Patches

A patch (against tk8.4a2) that implements the changes described above
is available
[http://www.eecs.umich.edu/~mckay/computer/wmenablers.84a3.patch.gz].

~ Notes

''Andreas Kupries.'' There was a ''tkwm' patch once.
[http://www.neosoft.com/tcl/ftparchive/sorted/x11/tkwm/]
[http://www.ensta.fr/internet/unix/window_managers/tkwm.html]

~ Copyright

This document is in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|





|






|
|
|
|



|







|



|







|

|







|


|



|

|
















|
|
|


|




|

|

|

|

|




|
|


|


|



|
|






|

|

|

|

|


|
|
|
|
|
<
>
|
<
>
|

|
|


|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
<
>
|
|
<
>
|

|

|

|

|

|
|
|

|


>

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
136
137
138
139
140
141
142
143
144
145
146

147
148

149
150
151
152
153
154
155
156
157
158
159
160

161
162
163
164
165
166

167
168
169

170
171
172

173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191

# TIP 47: Modifying Tk to Allow Writing X Window managers

	Author:         Neil McKay <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        19-Jul-2001
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

With a few modifications to the Tk core, extensions could be
written that would allow X window managers to be implemented
as Tcl/Tk scripts.

# Requirements

Writing X window managers in Tk requires some facilities that
the current Tk core doesn't provide. A window manager
must be able to:

 * draw to, and handle events on, the display's
	root window \(including _<Create>_,
	_<MapRequest>_, _<ResizeRequest>_, _<CirculateRequest>_,
	and _<ConfigureRequest>_ events, which are currently
	ignored\)

 * embed arbitrary windows inside Tk windows

 * receive _<PropertyNotify>_ events from embedded windows

 * perform a variety of other X-specific operations

Window embedding can be handled by an extension, if it is not
incorporated into the Tk frame widget at some later time.
Likewise, the X-specific operations can be handled by
an extension. However, Tk as it currently stands cannot
access the display's root window, nor can _<PropertyNotify>_
events be received from embedded windows; doing these
things requires core modifications.

# Root Window Access

The root window is special in many ways:

 * It does not need to be created

 * It cannot be destroyed, moved, or resized

 * Only one process can receive _<ButtonPress>_ and _<ButtonRelease>_
	events from it, and only one process can have the
	_SubstructureRedirect_ and _ResizeRedirect_ masks set

 * It has no physical parent window

Because of these properties, access to the root window via a Tk
widget presents some difficulties. First, the widget's window cannot
be created in the standard way; however, this problem may be solved by
providing a non-standard creation routine via the
_Tk\_SetClassProcs_ procedure described in [[5]](5.md).
Likewise, the event handling required by the root window
can be enabled in an extension, although some care is required
when enabling _<ButtonPress>_ and certain other events.
What really causes problems is the lack of a physical parent.
There are many places in Tk where it is assumed that only
toplevel widgets have no physical parent within the application;
this is reflected in the Tk source by the use of the _TK\_TOP\_LEVEL_ flag.
This flag is used to mean different things in different places.
In particular, the _TK\_TOP\_LEVEL_ flag may mean:

 * This window is a toplevel widget

 * This widget has a wrapper window

 * This widget's window is controlled by the window manager

 * This window is at the top of a physical window hierarchy
	within the current application

In the current version of Tk, toplevel widgets have all of these
properties, and no other widgets have any of these properties;
hence a single flag suffices.
If we create a widget whose window is the display's root, then this
is no longer the case; a root window has the last property, but not
the first three. For this reason, it is necessary to replace
the _TK\_TOP\_LEVEL_ flag with at least two distinct flags. A better
idea is to replace the _TK\_TOP\_LEVEL_ flag with four flags, one for each
of the properties listed above. \(Even in a standard Tk distribution,
this replacement is desirable for documentation reasons, since it will
indicate what property of a toplevel widget is important in the current
circumstances.\) We must also replace the _Tk\_IsTopLevel_ macro with
several macros, or just eliminate it entirely.

One possible set of flag names is:

 TK\_TOP\_LEVEL: this is a toplevel widget

 TK\_HAS\_WRAPPER: this window has a wrapper window

 TK\_WIN\_MANAGED: this window is controlled by the window manager

 TK\_TOP\_HIERARCHY: this window is at the top of a physical window hierarchy

# New Event Bindings and Substitutions

A window manager must be able to intercept certain events on the root
window that the standard Tk distribution doesn't recognize, and
it must be able to obtain information about those events. In particular,
it needs to respond to _<CirculateRequest>_, _<ConfigureRequest>_,
_<CreateNotify>_, _<MapRequest>_, and _<ResizeRequest>_ events.
These events are ignored by standard Tk, and need not be enabled by
default; however, they need to be included in the list of events recognized
by the Tk _[bind]_ command. Adding this facility is very simple.

Obtaining information about these events is also necessary.
This is usually done via %-substitutions in the _[bind]_ command;
however, there are two pieces of information that are necessary
for implementing a window manager that cannot be obtained via
the current %-substitution mechanism: the numerical X window ID,
required to handle _<CreateNotify>_ events, and the property name,
for handling _<PropertyNotify>_ events. This information could be
obtained by adding two new %-substitutions:

 %i: substitute the numerical window ID for the event

 %P: substitute the atom name for the property being changed

# Propagating <PropertyNotify> Events

In order to receive _<PropertyNotify>_ events from embedded windows,
the Tk event loop must handle events not just for windows that
are represented by _Tk\_Window_ structures, but also for their children.
One way to accomplish this is to add another flag for the
_Tk\_Window_ struct, and alter the event loop so that
it will also look at a window's parent, if the event is a
_<PropertyNotify>_ event. The relevant part of the Tk event loop
currently looks like this:

	
	winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow);
	if (winPtr == NULL) {
	    if (eventPtr->type == PropertyNotify) {
		TkSelPropProc(eventPtr);

	    }
	    return;

	}
	

If the flag for propagating _<PropertyNotify>_ events is
_TK\_PROP\_PROPCHANGE_, then the code above must be modified to look
approximately like this:

	
	winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow);
	if (winPtr == NULL) {
	    if (eventPtr->type != PropertyNotify) {
		return;

	    }
	    TkSelPropProc(eventPtr);
	    parentXId = (parent of handlerWindow);
	    winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, parentXId);
	    if (winPtr == NULL) {
		return;

	    }
	    if (!(winPtr->flags & TK_PROP_PROPCHANGE)) {
		return;

	    }
	    handlerWindow = parentXId;
	    return;

	}
	

# Patches

A patch \(against tk8.4a2\) that implements the changes described above
is available
<http://www.eecs.umich.edu/~mckay/computer/wmenablers.84a3.patch.gz> .

# Notes

_Andreas Kupries._ There was a _tkwm' patch once.
<http://www.neosoft.com/tcl/ftparchive/sorted/x11/tkwm/> 
<http://www.ensta.fr/internet/unix/window_managers/tkwm.html> 

# Copyright

This document is in the public domain.

Name change from tip/470.tip to tip/470.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

TIP:		470
Title:		Reliable Access to OO Definition Context Object
State:		Final
Type:		Project
Tcl-Version:	8.7
Vote:		Done
Post-History:	
Version:	$Revision: 1.4 $
Author:		Donal Fellows <[email protected]>
Created:	23-Apr-2017
Keywords:	TclOO, metaprogramming


~ Abstract

This TIP makes it easier for people to write procedures to extend TclOO's
definition sublanguage.

~ Rationale

One of the fundamental features of Tcl is that you can extend it with more
capabilities by writing your own procedures (and other commands, if you prefer
the C API). However, it is somewhat awkward to do so when using TclOO, as the
'''oo::define''' and '''oo::objdefine''' commands don't make it easy to find
out what the context class or object is.

For example, in the ''oo::util'' package of Tcllib, the code for discovering
what the context class is includes this
[http://core.tcl-lang.org/tcllib/artifact/51d71f560ceb7d63?ln=77]:

|    # Get the name of the current class or class delegate 
|    set cls [namespace which [lindex [info level -1] 1]]

That is ugly, and won't even work reliably for getting the context object in
'''oo::objdefine''' as that can be entered into by multiple paths (i.e.,
there's a shortcut from '''oo::define''').

~ Proposed Change

I propose to make the existing '''self''' command in '''oo::define''', when
invoked without arguments, return the context class (provided it is evaluated
in the correct stack frame, as usual with definition commands).  Similarly, I
also propose to add a '''self''' command to the '''oo::objdefine''' system
that takes no arguments and returns the context object.

This will enable to code listed above in the ''Rationale'' to become:

|    # Get the name of the current class or class delegate 
|    set cls [uplevel 1 self]

In the C API, I propose adding a function:

 > Tcl_Object '''Tcl_GetDefineContextObject'''(Tcl_Interp *''interp'')

which will get the context object, or return NULL and put an error in the
interpreter if there is no context object in the frame or the context object
has been deleted. The functionality is that of '''TclOOGetDefineCmdContext'''
in ''tclOODefineCmds.c''
[http://core.tcl-lang.org/tcl/artifact/7d58f1a701168168?ln=682], but the text
of the error messages might be changed.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|




|


|
|
|


|

|

|
|


|
|

|

|
|
|
|


|

|
|



|



|
|
|


|


>

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

# TIP 470: Reliable Access to OO Definition Context Object
	State:		Final
	Type:		Project
	Tcl-Version:	8.7
	Vote:		Done
	Post-History:	

	Author:		Donal Fellows <[email protected]>
	Created:	23-Apr-2017
	Keywords:	TclOO, metaprogramming
-----

# Abstract

This TIP makes it easier for people to write procedures to extend TclOO's
definition sublanguage.

# Rationale

One of the fundamental features of Tcl is that you can extend it with more
capabilities by writing your own procedures \(and other commands, if you prefer
the C API\). However, it is somewhat awkward to do so when using TclOO, as the
**oo::define** and **oo::objdefine** commands don't make it easy to find
out what the context class or object is.

For example, in the _oo::util_ package of Tcllib, the code for discovering
what the context class is includes this
<http://core.tcl-lang.org/tcllib/artifact/51d71f560ceb7d63?ln=77> :

	    # Get the name of the current class or class delegate 
	    set cls [namespace which [lindex [info level -1] 1]]

That is ugly, and won't even work reliably for getting the context object in
**oo::objdefine** as that can be entered into by multiple paths \(i.e.,
there's a shortcut from **oo::define**\).

# Proposed Change

I propose to make the existing **self** command in **oo::define**, when
invoked without arguments, return the context class \(provided it is evaluated
in the correct stack frame, as usual with definition commands\).  Similarly, I
also propose to add a **self** command to the **oo::objdefine** system
that takes no arguments and returns the context object.

This will enable to code listed above in the _Rationale_ to become:

	    # Get the name of the current class or class delegate 
	    set cls [uplevel 1 self]

In the C API, I propose adding a function:

 > Tcl\_Object **Tcl\_GetDefineContextObject**\(Tcl\_Interp \*_interp_\)

which will get the context object, or return NULL and put an error in the
interpreter if there is no context object in the frame or the context object
has been deleted. The functionality is that of **TclOOGetDefineCmdContext**
in _tclOODefineCmds.c_
<http://core.tcl-lang.org/tcl/artifact/7d58f1a701168168?ln=682> , but the text
of the error messages might be changed.

# Copyright

This document has been placed in the public domain.

Name change from tip/471.tip to tip/471.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

TIP:            471
Title:          Add [info linkedname] Introspection Command
Version:        $Revision: 1.1 $
Author:         Mathieu Lafon <[email protected]>
State:          Draft
Type:           Project
Created:        05-May-2017
Tcl-Version:    8.7
Vote:		Pending
Post-History:


~ Abstract

This TIP proposes to improve link variable introspection by providing a new
'''info linkedname''' command.

~ Rationale

This TIP is related to discussions about [457] and the '''-upvar''' extended
argument specifier. Adding an intropsection command to get the name of the
variable linked to is more Tcl-ish than automatically adding a local variable
with the linked name.  The proposed command is not restricted to [457] usage
as this can also be used for a link variable created by other means, using the
'''upvar''' command for example.

~ Specification of the Proposed Change

There should be a new subcommand of '''info''' created with the following syntax:

 > '''info linkedname''' ''varname''

The ''varname'' should be the name of a variable that has been linked to
another variable (e.g., with '''upvar''', '''global''', '''variable''' or
'''namespace upvar'''), and the result of the command will be the name of the
variable linked to.

~ Reference Implementation

The reference implementation is available in the info-linkedname
[http://core.tcl.tk/tcl/timeline?r=info-linkedname] branch.

The code is licensed under the BSD license.

~~ Implementation Notes

Depending on the linked variable, the name is found using different methods:

 * The name of a variable present in a hash table (globals, local variables
   created at runtime, ...) is retrieved using the hash key;

 * The name of an array element is built using the name of the array and the
   index name, retrieved using the hash key. A new field is added to the
   TclVarHashTable sructure to access the related array variable from the
   array element;

 * The name of a compiled local variable is searched in current or upper call
   frames.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|

|

|


|

|

|

|

|

|
|
|


|


|



|



|
|









|


>

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

# TIP 471: Add [info linkedname] Introspection Command

	Author:         Mathieu Lafon <[email protected]>
	State:          Draft
	Type:           Project
	Created:        05-May-2017
	Tcl-Version:    8.7
	Vote:		Pending
	Post-History:
-----

# Abstract

This TIP proposes to improve link variable introspection by providing a new
**info linkedname** command.

# Rationale

This TIP is related to discussions about [[457]](457.md) and the **-upvar** extended
argument specifier. Adding an intropsection command to get the name of the
variable linked to is more Tcl-ish than automatically adding a local variable
with the linked name.  The proposed command is not restricted to [[457]](457.md) usage
as this can also be used for a link variable created by other means, using the
**upvar** command for example.

# Specification of the Proposed Change

There should be a new subcommand of **info** created with the following syntax:

 > **info linkedname** _varname_

The _varname_ should be the name of a variable that has been linked to
another variable \(e.g., with **upvar**, **global**, **variable** or
**namespace upvar**\), and the result of the command will be the name of the
variable linked to.

# Reference Implementation

The reference implementation is available in the info-linkedname
<http://core.tcl.tk/tcl/timeline?r=info-linkedname>  branch.

The code is licensed under the BSD license.

## Implementation Notes

Depending on the linked variable, the name is found using different methods:

 * The name of a variable present in a hash table \(globals, local variables
   created at runtime, ...\) is retrieved using the hash key;

 * The name of an array element is built using the name of the array and the
   index name, retrieved using the hash key. A new field is added to the
   TclVarHashTable sructure to access the related array variable from the
   array element;

 * The name of a compiled local variable is searched in current or upper call
   frames.

# Copyright

This document has been placed in the public domain.

Name change from tip/472.tip to tip/472.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

TIP:            472
Title:          Add Support for 0d Radix Prefix to Integer Literals
Version:        $Revision: 1.8 $
Author:         Venkat Iyer <[email protected]>
Author:         Brian Griffin <[email protected]>
State:          Accepted
Type:           Project
Vote:           Done
Created:        25-May-2017
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes adding support for a '''0d''' decimal radix prefix to
complement the existing '''0x''' hexidecimal, '''0o''' octal and '''0b'''
binary radix prefixes.

~ Rationale

Verilog (and other Hardware Description Languages) always (or at least since
the 1995 LRM) had a way to specify a decimal number explicitly.  Verilog uses
''''d343534''' to mean decimal, VHDL actually allows any radix from 2 to 16
using syntax, so you could explicitly force a decimal interpretation using
'''10#343534#'''.

Tcl now allows '''0b''' for binary in '''expr''' and '''format''', which is
similar to ''''b''' in Verilog.  And of course the '''0x''' prefix has always
been around.  Another use case would be to prevent false parsing of leading
zeroes in '''clock format'''s as octal, without having to go through a
'''scan'''.

But a more elegant reason is that it makes the radix definition consistent, so

 1. all valid input radixes have a consistent unambiguous input literal
    format, and

 2. the '''d''' in '''format %d''' finally finds its complement in '''scan'''.

~ Specification

Extend the '''TclParseNumber''' function to recognize the prefixes '''0d'''
and '''0D''' as decimal integers.  It will have the same semantics as
'''0x''', but base 10 instead of base 16.  

Also extend format command '#' flag to produce the appropriate "0d" for 
the "%#d" conversion.  

~ Examples

It's an integer:

|   % expr {0d12 + 0d15}
|   27
|   % format "%#x" 0d1024
|   0x400
|   % format "%#d" 128
|   0d128

Errors same as other radix prefixes:

|   % expr { 0d317g }
|   invalid bareword "0d317g"
|   in expression " 0d317g ";
|   should be "$0d317g" or "{0d317g}" or "0d317g(...)" or ...
|   % expr { 0x1.53 }
|   missing operator at _@_
|   in expression " 0x1_@_.53 "
|   % expr {0d7.23}
|   missing operator at _@_
|   in expression "0d7_@_.23"

~ Compatibility

Currently, literals beginning with '''0d''' and parsed as a number will
produce an error.  Any code expecting such an error would fail to produce an
error an thus have a change in behavior.  I would expect this situation to be
uncommon.

~ Implementation

An implementation can be found the fossil on the "bsg-0d-radix-prefix" branch, including %#d conversion support.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|


|

|
|
|

|

|
|

|
|






|

|

|
|
|

|
|

|



|
|
|
|
|
|



|
|
|
|
|
|
|
|
|
|

|

|




|

|

|


>

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

# TIP 472: Add Support for 0d Radix Prefix to Integer Literals

	Author:         Venkat Iyer <[email protected]>
	Author:         Brian Griffin <[email protected]>
	State:          Accepted
	Type:           Project
	Vote:           Done
	Created:        25-May-2017
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes adding support for a **0d** decimal radix prefix to
complement the existing **0x** hexidecimal, **0o** octal and **0b**
binary radix prefixes.

# Rationale

Verilog \(and other Hardware Description Languages\) always \(or at least since
the 1995 LRM\) had a way to specify a decimal number explicitly.  Verilog uses
**'d343534** to mean decimal, VHDL actually allows any radix from 2 to 16
using syntax, so you could explicitly force a decimal interpretation using
**10\#343534\#**.

Tcl now allows **0b** for binary in **expr** and **format**, which is
similar to **'b** in Verilog.  And of course the **0x** prefix has always
been around.  Another use case would be to prevent false parsing of leading
zeroes in **clock format**s as octal, without having to go through a
**scan**.

But a more elegant reason is that it makes the radix definition consistent, so

 1. all valid input radixes have a consistent unambiguous input literal
    format, and

 2. the **d** in **format %d** finally finds its complement in **scan**.

# Specification

Extend the **TclParseNumber** function to recognize the prefixes **0d**
and **0D** as decimal integers.  It will have the same semantics as
**0x**, but base 10 instead of base 16.  

Also extend format command '\#' flag to produce the appropriate "0d" for 
the "%\#d" conversion.  

# Examples

It's an integer:

	   % expr {0d12 + 0d15}
	   27
	   % format "%#x" 0d1024
	   0x400
	   % format "%#d" 128
	   0d128

Errors same as other radix prefixes:

	   % expr { 0d317g }
	   invalid bareword "0d317g"
	   in expression " 0d317g ";
	   should be "$0d317g" or "{0d317g}" or "0d317g(...)" or ...
	   % expr { 0x1.53 }
	   missing operator at _@_
	   in expression " 0x1_@_.53 "
	   % expr {0d7.23}
	   missing operator at _@_
	   in expression "0d7_@_.23"

# Compatibility

Currently, literals beginning with **0d** and parsed as a number will
produce an error.  Any code expecting such an error would fail to produce an
error an thus have a change in behavior.  I would expect this situation to be
uncommon.

# Implementation

An implementation can be found the fossil on the "bsg-0d-radix-prefix" branch, including %\#d conversion support.

# Copyright

This document has been placed in the public domain.

Name change from tip/473.tip to tip/473.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

TIP:		473
Title:		Allow a Defined Target Namespace in oo::copy
State:		Final
Type:		Project
Tcl-Version:	8.6.7
Vote:		Done
Post-History:	
Version:	$Revision: 1.4 $
Author:		Donal Fellows <[email protected]>
Created:	06-Jun-2017
Keywords:	Tcl, missing functionality, bugfix


~ Abstract

This TIP adds functionality to '''oo::copy''' to allow the created copy to
have a defined namespace, much as '''oo::class''''s '''createWithNamespace'''
method allows such a namespace to be given on normal object creation.

~ Rationale

Due to an oversight, the '''oo::copy''' command is missing the ability to have
an explicit namespace name specified to use as the instance namespace of the
target object. It was always intended to have this (and the functionality is
there in the C API), but it was omitted from the Tcl-level interface.

Having this capability allows objects to be used as factories for namespaces,
which is in many ways an inversion of the way that TclOO was designed (with
namespaces as the basis for objects). It was requested by Nathan Coulter as a
way to enable more complex behaviour in Rivet and NaviServer. See Tcl Issue
dd3b844fda [http://core.tcl.tk/tcl/tktview/dd3b844fdabdeae5fcb0] for more
information.

~ Proposed Change

I propose to add one more optional argument to '''oo::copy''',
''targetNamespace'', that if provided and non-empty will be the name of a
namespace (resolved relative to the current namespace if not an absolute name)
that will be the name of the newly created target object's instance namespace.
The named namespace must not already exist. Note that specifying the
''targetObject'' as the empty string will cause the object's command to be
automatically chosen.

 > '''oo::copy''' ''sourceObject'' ?''targetObject''? ?''targetNamespace''?

The meaning of the result of the command is unchanged.

~ Implementation

See the oo-copy-ns branch. [http://core.tcl.tk/tcl/timeline?r=oo-copy-ns]

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|

|
|


|

|

|
|


|
|

|


|

|
|
|


|


|



|

|

|


>

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

# TIP 473: Allow a Defined Target Namespace in oo::copy
	State:		Final
	Type:		Project
	Tcl-Version:	8.6.7
	Vote:		Done
	Post-History:	

	Author:		Donal Fellows <[email protected]>
	Created:	06-Jun-2017
	Keywords:	Tcl, missing functionality, bugfix
-----

# Abstract

This TIP adds functionality to **oo::copy** to allow the created copy to
have a defined namespace, much as **oo::class**'s **createWithNamespace**
method allows such a namespace to be given on normal object creation.

# Rationale

Due to an oversight, the **oo::copy** command is missing the ability to have
an explicit namespace name specified to use as the instance namespace of the
target object. It was always intended to have this \(and the functionality is
there in the C API\), but it was omitted from the Tcl-level interface.

Having this capability allows objects to be used as factories for namespaces,
which is in many ways an inversion of the way that TclOO was designed \(with
namespaces as the basis for objects\). It was requested by Nathan Coulter as a
way to enable more complex behaviour in Rivet and NaviServer. See Tcl Issue
dd3b844fda <http://core.tcl.tk/tcl/tktview/dd3b844fdabdeae5fcb0>  for more
information.

# Proposed Change

I propose to add one more optional argument to **oo::copy**,
_targetNamespace_, that if provided and non-empty will be the name of a
namespace \(resolved relative to the current namespace if not an absolute name\)
that will be the name of the newly created target object's instance namespace.
The named namespace must not already exist. Note that specifying the
_targetObject_ as the empty string will cause the object's command to be
automatically chosen.

 > **oo::copy** _sourceObject_ ?_targetObject_? ?_targetNamespace_?

The meaning of the result of the command is unchanged.

# Implementation

See the oo-copy-ns branch. <http://core.tcl.tk/tcl/timeline?r=oo-copy-ns> 

# Copyright

This document has been placed in the public domain.

Name change from tip/48.tip to tip/48.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
TIP:            48
Title:          Tk Widget Styling Support
Version:        $Revision: 1.20 $
Author:         Fr�d�ric Bonnet <[email protected]>
Author:         Fr�d�ric Bonnet <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        23-Jul-2001
Post-History:   
Discussions-To: news:comp.lang.tcl
Tcl-Version:    8.4


~ Abstract

The Tk Toolkit is one of the last major GUI toolkits lacking themes
support.  This TIP proposes several changes to widget design that
allows custom code to be provided for widget element handling in a
transparent and extensible fashion.  User-provided code may then be
used to alter the widgets' look without the need to alter the Tk core.
The proposed changes induce no loss of compatibility, and only slight
core changes are needed with no side effect on existing functionality.

~ Background

The Tk Toolkit appeared on X-Window systems at a time where Motif was
the ''de facto'' standard for GUI development.  It thus naturally
adopted Motif's look&feel and its famous 3D border style.  First ports
to non-X platforms such as Windows and MacOS kept the Motif style,
which disappointed many users who felt Tk applications look "foreign".
Version 8.0 released around 1996 added native look&feel on these
platforms.

Recently, other Open Source toolkits such as Qt (used by the KDE
project) and GTK (used by the GIMP graphics editing software and the
Gnome project) emerged as powerful and free alternatives to Motif for
X-Window GUI development.  The rapidly growing success of Open Source
systems such as GNU/Linux helped both toolkits attract a vast
community of developers, and the firm (and sometimes friendly)
competition between both communities led to an explosion of new
features.  Thirst for freedom and customizability created the need for
themeability.

The current implementation of Tk only provides native look&feel on
supported platforms (Windows, X-Window, MacOS).  This lack partly
explains Tk's loss of mind-share, especially amongst Linux developers,
where theme support is considered a "cool" or must-have feature.

While yesterday's goal of many GUIs was cross-platform visual
uniformity (Qt and GTK borrowed much of their visual appearance from
Windows, which borrowed earlier from NeXTStep), it is now quite common
to find huge visual differences on today's desktops, even on similar
systems.  Screenshot contests are quite common nowadays.

~ Rationale

Tk first kept away from the toolkit war.  Tk's and its competitors'
philosophies are radically opposite.  Tk favors high level
abstractions and scripting languages such as Tcl, whereas Qt and GTK
developments are primarily done using C or C++ (which Tcl/Tk advocates
believe to be The Wrong Way).  But despite Tk's power, flexibility and
ease of use, it has lost serious mind-share, especially amongst
newcomers and Linux users who don't care about its cross-platform
capabilities.

Many Tk users may see themes support as cosmetic or of lower
importance than much needed features such as megawidgets or
objectification.  Nevertheless, this is a critical feature to be
implemented for the long-term viability of Tk.  Many courses are now
promoting Qt, GTK or (aarggg!) Swing in place of Motif, leaving no
room for Tk.  Whatever its qualities (cross-platform, performance,
ease of use, internationalization and Unicode support), the lack of
themeability will always be seen as one of the main reasons for not
using Tk.  Applications using Tk instead of GTK will look as "foreign"
on pixmap-themed Linux desktop, or even on newer MacOS and Windows
versions, as pre-8.0 applications were on non-X desktops.

The lack of themeability is neither a fatality nor difficult to solve.
Tk already allows colors, fonts and border width and relief to be
specified for all widgets.  What is currently missing is pixmap
themeing and border styles.  The current proposal describes the
required building blocks for theme support that are both easy to
implement and backward compatible.

A straightforward solution would be the one introduced by the
Dash-patch in the form of new widget options such as ''-tile''.  This
approach suffers from several major drawbacks:

  * A lot of new options are needed to handle the many ways of drawing
    pixmap tiles, such as anchoring, repeating, or scaling.

  * With the introduction of new options such as
    ''-activebackground'', tile-related options must be duplicated for
    each widget state (normal, active, disabled...), thus cluttering
    the options namespace more and thus raising the learning curve.

  * Applying a theme to a whole widget hierarchy implies traversing
    the whole tree and applying a lot of options to each widget.

  * Memory consumption is increased for all widgets, even in the case
    when these options are not used.

Moreover, one of the main goals of a theme being to enforce overall
visual consistency, multiplying new options should be avoided.  A
theme is designed to gather these options into one place so that they
can be shared by numerous widgets while avoiding performance or memory
hit.  A carefully designed theme engine should then only add one new
option per widget to set its ''style'' (an essential part of a theme).

How far should themeabitily go? A previous version of this document
proposed to extend the current 3D border mechanism to allow custom
drawing code.  Although this proposal was simple, backward compatible
and covered most of the needs for themeability (border style often
represents the largest part of the visual appearance), it failed to
address other significant parts of the user interface.  These include
radio and check marks, scrollbar arrows, sliders, and other widget
''elements''.  From this point of view, the border is only an
''element'' of a widget.  A complete theme engine should then allow
each UI element to be customized, while maximizing code reuse and
preserving compatibility.  To suit this model, widgets should then be
thought of as assembly of elements, and no more as monolithic
constructs.  This implies a paradigm shift in the way widgets are
''designed'' (but not necessarily in the way they are ''used'').
Actually, the notion of ''element'' is not foreign to Tk, since some
widgets (scrollbars) use the same term to identify their subparts.

~ A quick look at existing implementations

The two major toolkits supporting widget styles are Qt and GTK+.  Both
seem to follow the same path, but in slightly distinct manners: they
define a fixed set of common elements (arrows, checkmarks...) and
associate each with one or several API calls.  While Qt follows the
OO-path, GTK+ uses a more traditional procedural API model.

Qt defines a generic ''QStyle'' class which is the base class for all
styles (Windows, Motif...).  QStyle-derived classes implement a number
of virtual member methods, each being used to draw or compute the
geometry of the many elements.  Thanks to polymorphism, widgets can
then use any style derived from this base class.

Contrary to the C++ -based Qt that defines a class gathering all
style-related methods, GTK+ is C-based and defines individual
procedures (e.g. ''gtk_draw_slider'').

But overall, both use the same model: a predefined (albeit potentially
extensible) set of elements, and associated overloadable
methods/procs.  Adding new elements implies recompilation and/or code
changes.  While it is hardly seen as a problem with Qt and GTK+, since
both target C/C++ programming, it doesn't fit the Tcl/Tk model at all.

~ Proposal (or There Must Be A Better Way)

This document describes a generic and extensible element handling
mechanism.  This mechanism allows elements to be created and/or
overloaded at run-time in a modular fashion.

Widgets are composed of elements.  For instance, a scrollbar is made
out of arrows, a trough, and a slider.  Each element must be declared
<
|
<
|
|
|
|
|
|
|
|
|
>

|









|


|






|
|
|


|





|




|
|



|




|
|








|
|
|













|






|
|













|




|
|


|
|




|
|
|

|

|

|

|

|
|




|
|
|

|
|

|
|

|








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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

# TIP 48: Tk Widget Styling Support

	Author:         Frédéric Bonnet <[email protected]>
	Author:         Frédéric Bonnet <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        23-Jul-2001
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Tcl-Version:    8.4
-----

# Abstract

The Tk Toolkit is one of the last major GUI toolkits lacking themes
support.  This TIP proposes several changes to widget design that
allows custom code to be provided for widget element handling in a
transparent and extensible fashion.  User-provided code may then be
used to alter the widgets' look without the need to alter the Tk core.
The proposed changes induce no loss of compatibility, and only slight
core changes are needed with no side effect on existing functionality.

# Background

The Tk Toolkit appeared on X-Window systems at a time where Motif was
the _de facto_ standard for GUI development.  It thus naturally
adopted Motif's look&feel and its famous 3D border style.  First ports
to non-X platforms such as Windows and MacOS kept the Motif style,
which disappointed many users who felt Tk applications look "foreign".
Version 8.0 released around 1996 added native look&feel on these
platforms.

Recently, other Open Source toolkits such as Qt \(used by the KDE
project\) and GTK \(used by the GIMP graphics editing software and the
Gnome project\) emerged as powerful and free alternatives to Motif for
X-Window GUI development.  The rapidly growing success of Open Source
systems such as GNU/Linux helped both toolkits attract a vast
community of developers, and the firm \(and sometimes friendly\)
competition between both communities led to an explosion of new
features.  Thirst for freedom and customizability created the need for
themeability.

The current implementation of Tk only provides native look&feel on
supported platforms \(Windows, X-Window, MacOS\).  This lack partly
explains Tk's loss of mind-share, especially amongst Linux developers,
where theme support is considered a "cool" or must-have feature.

While yesterday's goal of many GUIs was cross-platform visual
uniformity \(Qt and GTK borrowed much of their visual appearance from
Windows, which borrowed earlier from NeXTStep\), it is now quite common
to find huge visual differences on today's desktops, even on similar
systems.  Screenshot contests are quite common nowadays.

# Rationale

Tk first kept away from the toolkit war.  Tk's and its competitors'
philosophies are radically opposite.  Tk favors high level
abstractions and scripting languages such as Tcl, whereas Qt and GTK
developments are primarily done using C or C\+\+ \(which Tcl/Tk advocates
believe to be The Wrong Way\).  But despite Tk's power, flexibility and
ease of use, it has lost serious mind-share, especially amongst
newcomers and Linux users who don't care about its cross-platform
capabilities.

Many Tk users may see themes support as cosmetic or of lower
importance than much needed features such as megawidgets or
objectification.  Nevertheless, this is a critical feature to be
implemented for the long-term viability of Tk.  Many courses are now
promoting Qt, GTK or \(aarggg!\) Swing in place of Motif, leaving no
room for Tk.  Whatever its qualities \(cross-platform, performance,
ease of use, internationalization and Unicode support\), the lack of
themeability will always be seen as one of the main reasons for not
using Tk.  Applications using Tk instead of GTK will look as "foreign"
on pixmap-themed Linux desktop, or even on newer MacOS and Windows
versions, as pre-8.0 applications were on non-X desktops.

The lack of themeability is neither a fatality nor difficult to solve.
Tk already allows colors, fonts and border width and relief to be
specified for all widgets.  What is currently missing is pixmap
themeing and border styles.  The current proposal describes the
required building blocks for theme support that are both easy to
implement and backward compatible.

A straightforward solution would be the one introduced by the
Dash-patch in the form of new widget options such as _-tile_.  This
approach suffers from several major drawbacks:

  * A lot of new options are needed to handle the many ways of drawing
    pixmap tiles, such as anchoring, repeating, or scaling.

  * With the introduction of new options such as
    _-activebackground_, tile-related options must be duplicated for
    each widget state \(normal, active, disabled...\), thus cluttering
    the options namespace more and thus raising the learning curve.

  * Applying a theme to a whole widget hierarchy implies traversing
    the whole tree and applying a lot of options to each widget.

  * Memory consumption is increased for all widgets, even in the case
    when these options are not used.

Moreover, one of the main goals of a theme being to enforce overall
visual consistency, multiplying new options should be avoided.  A
theme is designed to gather these options into one place so that they
can be shared by numerous widgets while avoiding performance or memory
hit.  A carefully designed theme engine should then only add one new
option per widget to set its _style_ \(an essential part of a theme\).

How far should themeabitily go? A previous version of this document
proposed to extend the current 3D border mechanism to allow custom
drawing code.  Although this proposal was simple, backward compatible
and covered most of the needs for themeability \(border style often
represents the largest part of the visual appearance\), it failed to
address other significant parts of the user interface.  These include
radio and check marks, scrollbar arrows, sliders, and other widget
_elements_.  From this point of view, the border is only an
_element_ of a widget.  A complete theme engine should then allow
each UI element to be customized, while maximizing code reuse and
preserving compatibility.  To suit this model, widgets should then be
thought of as assembly of elements, and no more as monolithic
constructs.  This implies a paradigm shift in the way widgets are
_designed_ \(but not necessarily in the way they are _used_\).
Actually, the notion of _element_ is not foreign to Tk, since some
widgets \(scrollbars\) use the same term to identify their subparts.

# A quick look at existing implementations

The two major toolkits supporting widget styles are Qt and GTK\+.  Both
seem to follow the same path, but in slightly distinct manners: they
define a fixed set of common elements \(arrows, checkmarks...\) and
associate each with one or several API calls.  While Qt follows the
OO-path, GTK\+ uses a more traditional procedural API model.

Qt defines a generic _QStyle_ class which is the base class for all
styles \(Windows, Motif...\).  QStyle-derived classes implement a number
of virtual member methods, each being used to draw or compute the
geometry of the many elements.  Thanks to polymorphism, widgets can
then use any style derived from this base class.

Contrary to the C\+\+ -based Qt that defines a class gathering all
style-related methods, GTK\+ is C-based and defines individual
procedures \(e.g. _gtk\_draw\_slider_\).

But overall, both use the same model: a predefined \(albeit potentially
extensible\) set of elements, and associated overloadable
methods/procs.  Adding new elements implies recompilation and/or code
changes.  While it is hardly seen as a problem with Qt and GTK\+, since
both target C/C\+\+ programming, it doesn't fit the Tcl/Tk model at all.

# Proposal \(or There Must Be A Better Way\)

This document describes a generic and extensible element handling
mechanism.  This mechanism allows elements to be created and/or
overloaded at run-time in a modular fashion.

Widgets are composed of elements.  For instance, a scrollbar is made
out of arrows, a trough, and a slider.  Each element must be declared
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
Elements are declared along with an implementation.  This declaration
can be made by the system or by widgets themselves, and at run-time,
thus allowing extensions to create new and use or derive existing
elements.

Implementations are registered in a given style engine.  A style
engine is thus a collection of element implementations.  Style engines
can be declared at run-time as well, but are static (since they
provide compiled code).  Style engines can be layered in order to
reuse and redefine existing elements implementations, falling back to
the default, core-defined engine.

A style is an instance of a style engine.  Styles can be given client
data information that would carry style engine-specific data.  For
example, a style engine implementing pixmapped elements could be given
the pixmaps to use.  Styles can be created and deleted at run-time.

Using this scheme, a widget can register elements and their default
implementation, but actually use a custom implementation code in a
transparent manner depending on its currently applied style.
Moreover, elements can be shared across widgets, new elements can be
registered dynamically and used transparently.  New widgets could also
be built in a modular fashion and easily reuse other widget's
elements.  The proposed mechanism could then be used in a
megawidget-like fashion (we could speak about megaelement widgets).
Last, it provides a dynamic hook mechanism for overriding the core
widget code from loadable extensions, avoiding the need for
maintaining core patches.

~ Functional Specification

 Style engines: Style engines gather code for handling a set of
	elements.  For this reason, they are inherently static, alike
	''Tcl_ObjType''s.  They can be registered at run-time,
	queried, but never unregistered, since external style engines
	will usually be provided by loadable packages, and that Tcl
	does not support library unloading.

 Styles: Styles are instances of style engines.  While engines are
	static, styles can be dynamic.  All styles of the same engine
	use the same code for handling elements, but using different
	data provided at creation-time.  For example, a generic pixmap
	engine may be instantiated by several styles providing a
	different set of pixmaps.  Styles can be created at run-time,
	queried, and freed.  Since they are user-visible entities, a
	''Tcl_Obj''-based interface is also provided.

 Elements: Elements are virtual entities.  An element only exists if
	an implementation has been provided.  Thus, elements are
	created implicitly.  They can be queried, but not destroyed.
	Upon creation, elements are given a unique ID that remains
	valid for the entire application life time and is used
	subsequently for all related calls.  It serves as a numerical







|
|















|




|



|











|







165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
Elements are declared along with an implementation.  This declaration
can be made by the system or by widgets themselves, and at run-time,
thus allowing extensions to create new and use or derive existing
elements.

Implementations are registered in a given style engine.  A style
engine is thus a collection of element implementations.  Style engines
can be declared at run-time as well, but are static \(since they
provide compiled code\).  Style engines can be layered in order to
reuse and redefine existing elements implementations, falling back to
the default, core-defined engine.

A style is an instance of a style engine.  Styles can be given client
data information that would carry style engine-specific data.  For
example, a style engine implementing pixmapped elements could be given
the pixmaps to use.  Styles can be created and deleted at run-time.

Using this scheme, a widget can register elements and their default
implementation, but actually use a custom implementation code in a
transparent manner depending on its currently applied style.
Moreover, elements can be shared across widgets, new elements can be
registered dynamically and used transparently.  New widgets could also
be built in a modular fashion and easily reuse other widget's
elements.  The proposed mechanism could then be used in a
megawidget-like fashion \(we could speak about megaelement widgets\).
Last, it provides a dynamic hook mechanism for overriding the core
widget code from loadable extensions, avoiding the need for
maintaining core patches.

# Functional Specification

 Style engines: Style engines gather code for handling a set of
	elements.  For this reason, they are inherently static, alike
	_Tcl\_ObjType_s.  They can be registered at run-time,
	queried, but never unregistered, since external style engines
	will usually be provided by loadable packages, and that Tcl
	does not support library unloading.

 Styles: Styles are instances of style engines.  While engines are
	static, styles can be dynamic.  All styles of the same engine
	use the same code for handling elements, but using different
	data provided at creation-time.  For example, a generic pixmap
	engine may be instantiated by several styles providing a
	different set of pixmaps.  Styles can be created at run-time,
	queried, and freed.  Since they are user-visible entities, a
	_Tcl\_Obj_-based interface is also provided.

 Elements: Elements are virtual entities.  An element only exists if
	an implementation has been provided.  Thus, elements are
	created implicitly.  They can be queried, but not destroyed.
	Upon creation, elements are given a unique ID that remains
	valid for the entire application life time and is used
	subsequently for all related calls.  It serves as a numerical
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596

	also provide a list of required widget options.  Elements
	would then pick the option values from the widget record
	according to the widget's option table.  In the case when the
	desired option is missing from the option table, the element
	would have to either try other options of fail gracefully and
	use sensible default values.

~ Detailed Specification

The proposal introduces a set of new public types and APIs, exported
from ''generic/tk.h'' and the stubs table.  The implementation induces
very slight and limited changes to the existing code, with only one
new private API added (''TkGetOptionSpec'' in ''generic/tkConfig.c'').
Most of the new code is concentrated into one file.  There is no side
effect on existing functionality.

''Types and constants''.

 TK_OPTION_STYLE:
	New ''Tk_OptionType'' usually associated with the ''-style''
	widget option.

 TK_STYLE_VERSION_1, TK_STYLE_VERSION:
	Version numbers of Tk style support. The former matches the 
	implementation described in this proposal. The latter is a shortcut to
	the current version. Future extensions may introduce new version numbers.

 Tk_StyleEngine:
	Opaque token for handling style engines.  May be NULL, meaning
	the default system engine.

 Tk_StyledElement:
	Opaque token holding a style-specific implementation of a
	given element.  Subsequently used for performing element ops.

 Tk_Style:
	Opaque token for handling styles.  May be NULL, meaning the
	default system style.

 Tk_GetElementSizeProc, Tk_GetElementBoxProc, Tk_GetElementBorderWidthProc, Tk_DrawElementProc:
	Implementations of various element operations.

| typedef void (Tk_GetElementSizeProc) _ANSI_ARGS_((ClientData clientData, 
| 	char *recordPtr, CONST Tk_OptionSpec **optionsPtr, Tk_Window tkwin,
| 	int width, int height, int inner, int *widthPtr, int *heightPtr));
|
| typedef void (Tk_GetElementBoxProc) _ANSI_ARGS_((ClientData clientData, 
| 	char *recordPtr, CONST Tk_OptionSpec **optionsPtr, Tk_Window tkwin,
| 	int x, int y, int width, int height, int inner, int *xPtr, int *yPtr, 
| 	int *widthPtr, int *heightPtr));
|
| typedef int (Tk_GetElementBorderWidthProc) _ANSI_ARGS_((ClientData clientData, 
| 	char *recordPtr, CONST Tk_OptionSpec **optionsPtr, Tk_Window tkwin));
|
| typedef void (Tk_DrawElementProc) _ANSI_ARGS_((ClientData clientData, 
| 	char *recordPtr, CONST Tk_OptionSpec **optionsPtr, Tk_Window tkwin,
| 	Drawable d, int x, int y, int width, int height, int state));

 Tk_ElementOptionSpec:
	Used to specify a list of required widget options, along with
	their type.  This info will be subsequently used to get option
	values from the widget record using its option table.

| typedef struct Tk_ElementOptionSpec {
|     char *name;
|     Tk_OptionType type;
| } Tk_ElementOptionSpec;

 Tk_ElementSpec:
	Static styled element definition. The version field must be set to 
	TK_STYLE_VERSION_1 in order to match the following structure.

| typedef struct Tk_ElementSpec {
|     int version;
|     char *name;
|     Tk_ElementOptionSpec *options;
|     Tk_GetElementSizeProc *getSize;
|     Tk_GetElementBoxProc *getBox;
|     Tk_GetElementBorderWidthProc *getBorderWidth;
|     Tk_DrawElementProc *draw;
| } Tk_ElementSpec;

 TK_ELEMENT_STATE_*:
	Flags used when drawing elements.  Elements may have a
	different visual appearance depending on their state.
	However, it should be noted that the element size is not
	affected by state changes.

| #define TK_ELEMENT_STATE_ACTIVE       (1<<0)
| #define TK_ELEMENT_STATE_DISABLED     (1<<1)
| #define TK_ELEMENT_STATE_FOCUS        (1<<2)
| #define TK_ELEMENT_STATE_PRESSED      (1<<3)

''Functions''.

 TkStylePkgInit, TkStylePkgFree:
	Internal procedures used to initialize the style subpackage on
	a per-application basis.

| void TkStylePkgInit (TkMainInfo *mainPtr)
| void TkStylePkgFree (TkMainInfo *mainPtr)

 TkGetOptionSpec:
	Internal function used to retrieve an option specifier from a
	compiled option table.

| CONST Tk_OptionSpec * TkGetOptionSpec (CONST char *name, 
| 	Tk_OptionTable optionTable);

 Tk_RegisterStyleEngine:
	Registers a new style engine.

| Tk_StyleEngine Tk_RegisterStyleEngine (char *name, Tk_StyleEngine parent)

 >	Name may be NULL, in which case it registers the default
	engine.  Returns a NULL token if an error occurred (e.g.
	registering an existing engine).

 Tk_GetStyleEngine:
	Returns a token to an existing style engine, or NULL.

| Tk_StyleEngine Tk_GetStyleEngine (char *name)

 Tk_RegisterStyledElement:
	Registers the implementation of an element for a given style
	engine.

| int Tk_RegisterStyledElement (Tk_StyleEngine engine, 
| 	Tk_ElementSpec *templatePtr)

 >	Element names use a dotted notation that gives a hierarchical
	search order.  For example, a widget requiring an element
	named "Scrollbar.vslider" can actually use the "vslider"
	generic element.  Apart from this dotted notation, element
	names are free-form.  However, conventions should be defined,
	such as capitalized widget classes, and lower case elements.
	Since whole widgets can act as elements, one can therefore
	register an element named "Scrollbar".

 >	The given pointer is not stored into internal structures, but
	is instead used to fill them.  Styled element specs can thus
	be allocated on the stack or dynamically, but in most cases
	they will be statically defined.

 Tk_GetElementId:
	Returns the unique numerical ID for an already registered
	element.

| int Tk_GetElementId (char *name)

 Tk_CreateStyle:
	Creates a new style as an instance of an existing style
	engine.

| Tk_Style Tk_CreateStyle (CONST char *name, Tk_StyleEngine engine, 
| 	ClientData clientData)

 >	Client data may be provided, that will be passed as is to
	element operations.

 Tk_GetStyle:
	Retrieves an existing style by its name.

| Tk_Style Tk_GetStyle (Tcl_Interp *interp, CONST char *name)

 >	Retrieves either an existing style by its name, or NULL if
	none was found.  In the latter case, leaves an error message
	in ''interp'' if it is not NULL.

 Tk_FreeStyle:
	Frees a style returned by ''Tk_CreateStyle'' or
	''Tk_GetStyle''.

| void Tk_FreeStyle (Tk_Style style)

 >	It actually decrements an internal reference count so that
	styles can be shared and deleted safely.

 Tk_NameOfStyle:
	Gets a style's name.

| CONST char * Tk_NameOfStyle (Tk_Style style)

 Tk_AllocStyleFromObj, Tk_GetStyleFromObj, Tk_FreeStyleFromObj:
	''Tcl_Obj'' based interface to styles.

| Tk_Style  Tk_AllocStyleFromObj (Tcl_Interp *interp, Tcl_Obj *objPtr)
| Tk_Style Tk_GetStyleFromObj (Tcl_Obj *objPtr)
| void  Tk_FreeStyleFromObj (Tcl_Obj *objPtr)

 >	''Tk_AllocStyleFromObj'' gets (doesn't create) an existing
	style from an object.  ''Tk_GetStyleFromObj'' returns the
	style already stored in the object's internal representation.
	The object must have been returned by
	''Tk_AllocStyleFromObj''.  ''Tk_FreeStyleFromObj'' frees the
	style held by the object. 

 Tk_GetStyledElement:
	Returns a token for the styled element for use with widgets
	having the given ''optionTable''.

| Tk_StyledElement Tk_GetStyledElement (Tk_Style style, int elementId, 
| 	Tk_OptionTable optionTable)

 >	Returns a token for the styled element (or NULL if not found),
	for use with widgets having the given optionTable.  The token
	is persistent and doesn't need to be freed, so it can be
	safely stored if needed (although using element IDs is the
	preferred method).  It is used in subsequent element
	operations and avoids repeated lookups.  The lookup algorithm
	works as follows:

 > 1.	Look for an implementation of the given element in the current
	style engine.

 > 2.	If none was found, traverse the chain of engines (each but the
	default engine has a parent) until the default engine is
	reached.

 > 3.	Restart at step 1 with the base element name instead.  For
	example, if we are looking for "foo.bar.baz", then look for
	"bar.baz" then "baz", until we find an implementation.  

 >	If no implementation was found, then a panic is generated,
	meaning that some dependency has not been resolved.  In the
	general case, this won't happen for core widgets (because they
	only use core elements), and new widgets either have to rely
	on core or package-provided elements, or define their own.

 Tk_GetElementSize, Tk_GetElementBox, Tk_GetElementBorderWidth, Tk_DrawElement:
	Various element operations.

| void Tk_GetElementSize (Tk_Style style, Tk_StyledElement element, 
| 	char *recordPtr, Tk_Window tkwin, int width, int height, 
| 	int inner, int *widthPtr, int *heightPtr)
| void Tk_GetElementBox (Tk_Style style, Tk_StyledElement element, 
| 	char *recordPtr, Tk_Window tkwin, int x, int y, int width, 
| 	int height, int inner, int *xPtr, int *yPtr, int *widthPtr, 
| 	int *heightPtr)
| int Tk_GetElementBorderWidth (Tk_Style style, Tk_StyledElement element, 
| 	char *recordPtr, Tk_Window tkwin)
| void Tk_DrawElement (Tk_Style style, Tk_StyledElement element, 
| 	char *recordPtr, Tk_Window tkwin, Drawable d, int x, int y, 
| 	int width, int height, int state)

 >	The first two are used for geometry management.  First one
	only computes the size, while second one computes the box
	coordinates.  The ''inner'' parameter is a boolean that
	controls whether the inner (FALSE) or outer (TRUE) geometry is
	requested from the maximum outer/minimum inner geometry.
	Third one returns the uniform internal border width of the
	element and is mostly intended for whole widgets.  Last one
	draws the element using the given geometry and state.

~ Implementation

An implementation has been written and completed with respect to the
present specification.  A patch for Tk 8.4a3 is available at:

 > http://www.purl.org/NET/bonnet/pub/style.patch

The ''square'' widget implemented in the test file
''generic/tkSquare.c'' has also been rewritten to use the new API for
its square element.  It demonstrates basic features.  Patch file:

 > http://www.purl.org/NET/bonnet/pub/squarestyle.patch

The sample code registers an element "Square.square" in the default
style engine.  This element is used by the square widget in its
drawing code.  A new style engine "fixedborder" is registered, and
code is provided for the "Square.square" element.  This style engine
draws the element's border using a fixed border width given as client
data by instantiated styles.  Four styles are created as instances of
the "fixedborder" element: "flat", "border2", "border4" and "border8"
(0, 2, 4 and 8 pixel-wide borders).

Sample test session:

| pack [square .s]
| .s config -style
| .s config -style flat
| .s config -style border2
| .s config -style border4
| .s config -style border8
| .s config -style ""
| pack [square .s2]
| .s2 config -style border2
| .s2 config -style border8

~ Performance and memory usage

The provided design and implementation is geared towards the best
compromise between performance and memory consumption.

Critical performance bottleneck is element querying.  In order to
minimize element access times, elements are identified by unique IDs
that act as indexes within internal tables, allowing direct
addressing.  Hash tables are used internally by all name pools
(engines, styles, elements).  Static structures are used whenever
possible (for styled element registration, indirectly through
widgets' option tables...).  Widget processing times are increased by
the extra procedure calls and indirections, but that is the price to
pay for better modularity anyway.  Additional calls are kept minimal.

Per-widget memory consumption is minimal.  A widget usually only needs
to store its current style.  Element IDs can (should?) be shared
globally across widgets of the same class and don't need to be stored
in the widget record.  Moreover, most information is shared internally
across widgets of the same class (identified by their option table).
Many caching & fast lookup techniques are used throughout the code.

~ Compatibility

Existing widgets will need to be rewritten in order to become
style-aware.  The required code changes may be significant (implying
code modularization).  However, no incompatibility is introduced.
Thus, migrating widgets from the old to the new model can follow a
smooth path, similar to that needed for the transition to ''Tcl_Obj''
interfaces.  Besides, widgets as a whole can act as elements, which
may shift the amount of work from the core to the style engines at the
expense of a lesser modularity and code reuse.

~ Future improvements or changes

 * Additional APIs for querying the list of engines, styles,
   elements...

 * Additional operations for elements, e.g. hit tests.

 * Script-level interfaces.

 * Optional translation tables between real widget options and needed
   element options, e.g. ''-elementborderwidth'' => ''-borderwidth''.

 * How to handle native widgets? They will certainly have to be
   provided as whole elements.

 * Current implementation uses thread-local storage for holding
   dynamic data.  Since most data is not thread-specific, this could
   be changed to a more memory-efficient scheme.

 * Provide man pages and tests.

 * Additional hidden/private option flag for accessing some widgets'
   non-configurable data (e.g. scrollbar position) through option
   tables.

~ Glossary

 Element: Part of a widget (e.g. a checkbox mark or a scrollbar
	arrow), usually active.

 Style: The visual appearance of a widget.  May include colors, skins,
        tiles, border drawing style (Windows, Motif...), element
        pictures.

 Styled element: A style-specific implementation of a widget element.

 Style engine: A visually consistent collection of styled elements.

 Theme: A collection of graphical elements giving a consistent
        appearance to a whole widget hierarchy, application, or
        desktop.  A theme is usually made up out of icons, colors,
        fonts, widget styles, or even desktop background and sounds.

~ Copyright

This document has been placed in the public domain.








|


|

|



|

|
|


|




|



|



|



|


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|




|
|
|
|

|

|

|
|
|
|
|
|
|
|
|

|





|
|
|
|

|





|
|





|
|

|


|


|
|

|


|

|



|
|















|



|

|



|
|




|


|



|

|
|
|

|




|


|

|
|

|
|
|

|
|


|


|

|

|
|

|


|
|






|
|








|
|


|


|
|
|
|
|
|
|
|
|
|
|
|



|
|





|




|

|
|


|








|



|
|
|
|
|
|
|
|
|
|

|








|
|
|




|


|


|


|
|

|




|









|











|


|

|
|


|











|


>
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
	also provide a list of required widget options.  Elements
	would then pick the option values from the widget record
	according to the widget's option table.  In the case when the
	desired option is missing from the option table, the element
	would have to either try other options of fail gracefully and
	use sensible default values.

# Detailed Specification

The proposal introduces a set of new public types and APIs, exported
from _generic/tk.h_ and the stubs table.  The implementation induces
very slight and limited changes to the existing code, with only one
new private API added \(_TkGetOptionSpec_ in _generic/tkConfig.c_\).
Most of the new code is concentrated into one file.  There is no side
effect on existing functionality.

_Types and constants_.

 TK\_OPTION\_STYLE:
	New _Tk\_OptionType_ usually associated with the _-style_
	widget option.

 TK\_STYLE\_VERSION\_1, TK\_STYLE\_VERSION:
	Version numbers of Tk style support. The former matches the 
	implementation described in this proposal. The latter is a shortcut to
	the current version. Future extensions may introduce new version numbers.

 Tk\_StyleEngine:
	Opaque token for handling style engines.  May be NULL, meaning
	the default system engine.

 Tk\_StyledElement:
	Opaque token holding a style-specific implementation of a
	given element.  Subsequently used for performing element ops.

 Tk\_Style:
	Opaque token for handling styles.  May be NULL, meaning the
	default system style.

 Tk\_GetElementSizeProc, Tk\_GetElementBoxProc, Tk\_GetElementBorderWidthProc, Tk\_DrawElementProc:
	Implementations of various element operations.

	 typedef void (Tk_GetElementSizeProc) _ANSI_ARGS_((ClientData clientData, 
	 	char *recordPtr, CONST Tk_OptionSpec **optionsPtr, Tk_Window tkwin,
	 	int width, int height, int inner, int *widthPtr, int *heightPtr));
	
	 typedef void (Tk_GetElementBoxProc) _ANSI_ARGS_((ClientData clientData, 
	 	char *recordPtr, CONST Tk_OptionSpec **optionsPtr, Tk_Window tkwin,
	 	int x, int y, int width, int height, int inner, int *xPtr, int *yPtr, 
	 	int *widthPtr, int *heightPtr));
	
	 typedef int (Tk_GetElementBorderWidthProc) _ANSI_ARGS_((ClientData clientData, 
	 	char *recordPtr, CONST Tk_OptionSpec **optionsPtr, Tk_Window tkwin));
	
	 typedef void (Tk_DrawElementProc) _ANSI_ARGS_((ClientData clientData, 
	 	char *recordPtr, CONST Tk_OptionSpec **optionsPtr, Tk_Window tkwin,
	 	Drawable d, int x, int y, int width, int height, int state));

 Tk\_ElementOptionSpec:
	Used to specify a list of required widget options, along with
	their type.  This info will be subsequently used to get option
	values from the widget record using its option table.

	 typedef struct Tk_ElementOptionSpec {
	     char *name;
	     Tk_OptionType type;
	 } Tk_ElementOptionSpec;

 Tk\_ElementSpec:
	Static styled element definition. The version field must be set to 
	TK\_STYLE\_VERSION\_1 in order to match the following structure.

	 typedef struct Tk_ElementSpec {
	     int version;
	     char *name;
	     Tk_ElementOptionSpec *options;
	     Tk_GetElementSizeProc *getSize;
	     Tk_GetElementBoxProc *getBox;
	     Tk_GetElementBorderWidthProc *getBorderWidth;
	     Tk_DrawElementProc *draw;
	 } Tk_ElementSpec;

 TK\_ELEMENT\_STATE\_\*:
	Flags used when drawing elements.  Elements may have a
	different visual appearance depending on their state.
	However, it should be noted that the element size is not
	affected by state changes.

	 #define TK_ELEMENT_STATE_ACTIVE       (1<<0)
	 #define TK_ELEMENT_STATE_DISABLED     (1<<1)
	 #define TK_ELEMENT_STATE_FOCUS        (1<<2)
	 #define TK_ELEMENT_STATE_PRESSED      (1<<3)

_Functions_.

 TkStylePkgInit, TkStylePkgFree:
	Internal procedures used to initialize the style subpackage on
	a per-application basis.

	 void TkStylePkgInit (TkMainInfo *mainPtr)
	 void TkStylePkgFree (TkMainInfo *mainPtr)

 TkGetOptionSpec:
	Internal function used to retrieve an option specifier from a
	compiled option table.

	 CONST Tk_OptionSpec * TkGetOptionSpec (CONST char *name, 
	 	Tk_OptionTable optionTable);

 Tk\_RegisterStyleEngine:
	Registers a new style engine.

	 Tk_StyleEngine Tk_RegisterStyleEngine (char *name, Tk_StyleEngine parent)

 >	Name may be NULL, in which case it registers the default
	engine.  Returns a NULL token if an error occurred \(e.g.
	registering an existing engine\).

 Tk\_GetStyleEngine:
	Returns a token to an existing style engine, or NULL.

	 Tk_StyleEngine Tk_GetStyleEngine (char *name)

 Tk\_RegisterStyledElement:
	Registers the implementation of an element for a given style
	engine.

	 int Tk_RegisterStyledElement (Tk_StyleEngine engine, 
	 	Tk_ElementSpec *templatePtr)

 >	Element names use a dotted notation that gives a hierarchical
	search order.  For example, a widget requiring an element
	named "Scrollbar.vslider" can actually use the "vslider"
	generic element.  Apart from this dotted notation, element
	names are free-form.  However, conventions should be defined,
	such as capitalized widget classes, and lower case elements.
	Since whole widgets can act as elements, one can therefore
	register an element named "Scrollbar".

 >	The given pointer is not stored into internal structures, but
	is instead used to fill them.  Styled element specs can thus
	be allocated on the stack or dynamically, but in most cases
	they will be statically defined.

 Tk\_GetElementId:
	Returns the unique numerical ID for an already registered
	element.

	 int Tk_GetElementId (char *name)

 Tk\_CreateStyle:
	Creates a new style as an instance of an existing style
	engine.

	 Tk_Style Tk_CreateStyle (CONST char *name, Tk_StyleEngine engine, 
	 	ClientData clientData)

 >	Client data may be provided, that will be passed as is to
	element operations.

 Tk\_GetStyle:
	Retrieves an existing style by its name.

	 Tk_Style Tk_GetStyle (Tcl_Interp *interp, CONST char *name)

 >	Retrieves either an existing style by its name, or NULL if
	none was found.  In the latter case, leaves an error message
	in _interp_ if it is not NULL.

 Tk\_FreeStyle:
	Frees a style returned by _Tk\_CreateStyle_ or
	_Tk\_GetStyle_.

	 void Tk_FreeStyle (Tk_Style style)

 >	It actually decrements an internal reference count so that
	styles can be shared and deleted safely.

 Tk\_NameOfStyle:
	Gets a style's name.

	 CONST char * Tk_NameOfStyle (Tk_Style style)

 Tk\_AllocStyleFromObj, Tk\_GetStyleFromObj, Tk\_FreeStyleFromObj:
	_Tcl\_Obj_ based interface to styles.

	 Tk_Style  Tk_AllocStyleFromObj (Tcl_Interp *interp, Tcl_Obj *objPtr)
	 Tk_Style Tk_GetStyleFromObj (Tcl_Obj *objPtr)
	 void  Tk_FreeStyleFromObj (Tcl_Obj *objPtr)

 >	_Tk\_AllocStyleFromObj_ gets \(doesn't create\) an existing
	style from an object.  _Tk\_GetStyleFromObj_ returns the
	style already stored in the object's internal representation.
	The object must have been returned by
	_Tk\_AllocStyleFromObj_.  _Tk\_FreeStyleFromObj_ frees the
	style held by the object. 

 Tk\_GetStyledElement:
	Returns a token for the styled element for use with widgets
	having the given _optionTable_.

	 Tk_StyledElement Tk_GetStyledElement (Tk_Style style, int elementId, 
	 	Tk_OptionTable optionTable)

 >	Returns a token for the styled element \(or NULL if not found\),
	for use with widgets having the given optionTable.  The token
	is persistent and doesn't need to be freed, so it can be
	safely stored if needed \(although using element IDs is the
	preferred method\).  It is used in subsequent element
	operations and avoids repeated lookups.  The lookup algorithm
	works as follows:

 > 1.	Look for an implementation of the given element in the current
	style engine.

 > 2.	If none was found, traverse the chain of engines \(each but the
	default engine has a parent\) until the default engine is
	reached.

 > 3.	Restart at step 1 with the base element name instead.  For
	example, if we are looking for "foo.bar.baz", then look for
	"bar.baz" then "baz", until we find an implementation.  

 >	If no implementation was found, then a panic is generated,
	meaning that some dependency has not been resolved.  In the
	general case, this won't happen for core widgets \(because they
	only use core elements\), and new widgets either have to rely
	on core or package-provided elements, or define their own.

 Tk\_GetElementSize, Tk\_GetElementBox, Tk\_GetElementBorderWidth, Tk\_DrawElement:
	Various element operations.

	 void Tk_GetElementSize (Tk_Style style, Tk_StyledElement element, 
	 	char *recordPtr, Tk_Window tkwin, int width, int height, 
	 	int inner, int *widthPtr, int *heightPtr)
	 void Tk_GetElementBox (Tk_Style style, Tk_StyledElement element, 
	 	char *recordPtr, Tk_Window tkwin, int x, int y, int width, 
	 	int height, int inner, int *xPtr, int *yPtr, int *widthPtr, 
	 	int *heightPtr)
	 int Tk_GetElementBorderWidth (Tk_Style style, Tk_StyledElement element, 
	 	char *recordPtr, Tk_Window tkwin)
	 void Tk_DrawElement (Tk_Style style, Tk_StyledElement element, 
	 	char *recordPtr, Tk_Window tkwin, Drawable d, int x, int y, 
	 	int width, int height, int state)

 >	The first two are used for geometry management.  First one
	only computes the size, while second one computes the box
	coordinates.  The _inner_ parameter is a boolean that
	controls whether the inner \(FALSE\) or outer \(TRUE\) geometry is
	requested from the maximum outer/minimum inner geometry.
	Third one returns the uniform internal border width of the
	element and is mostly intended for whole widgets.  Last one
	draws the element using the given geometry and state.

# Implementation

An implementation has been written and completed with respect to the
present specification.  A patch for Tk 8.4a3 is available at:

 > <http://www.purl.org/NET/bonnet/pub/style.patch>

The _square_ widget implemented in the test file
_generic/tkSquare.c_ has also been rewritten to use the new API for
its square element.  It demonstrates basic features.  Patch file:

 > <http://www.purl.org/NET/bonnet/pub/squarestyle.patch>

The sample code registers an element "Square.square" in the default
style engine.  This element is used by the square widget in its
drawing code.  A new style engine "fixedborder" is registered, and
code is provided for the "Square.square" element.  This style engine
draws the element's border using a fixed border width given as client
data by instantiated styles.  Four styles are created as instances of
the "fixedborder" element: "flat", "border2", "border4" and "border8"
\(0, 2, 4 and 8 pixel-wide borders\).

Sample test session:

	 pack [square .s]
	 .s config -style
	 .s config -style flat
	 .s config -style border2
	 .s config -style border4
	 .s config -style border8
	 .s config -style ""
	 pack [square .s2]
	 .s2 config -style border2
	 .s2 config -style border8

# Performance and memory usage

The provided design and implementation is geared towards the best
compromise between performance and memory consumption.

Critical performance bottleneck is element querying.  In order to
minimize element access times, elements are identified by unique IDs
that act as indexes within internal tables, allowing direct
addressing.  Hash tables are used internally by all name pools
\(engines, styles, elements\).  Static structures are used whenever
possible \(for styled element registration, indirectly through
widgets' option tables...\).  Widget processing times are increased by
the extra procedure calls and indirections, but that is the price to
pay for better modularity anyway.  Additional calls are kept minimal.

Per-widget memory consumption is minimal.  A widget usually only needs
to store its current style.  Element IDs can \(should?\) be shared
globally across widgets of the same class and don't need to be stored
in the widget record.  Moreover, most information is shared internally
across widgets of the same class \(identified by their option table\).
Many caching & fast lookup techniques are used throughout the code.

# Compatibility

Existing widgets will need to be rewritten in order to become
style-aware.  The required code changes may be significant \(implying
code modularization\).  However, no incompatibility is introduced.
Thus, migrating widgets from the old to the new model can follow a
smooth path, similar to that needed for the transition to _Tcl\_Obj_
interfaces.  Besides, widgets as a whole can act as elements, which
may shift the amount of work from the core to the style engines at the
expense of a lesser modularity and code reuse.

# Future improvements or changes

 * Additional APIs for querying the list of engines, styles,
   elements...

 * Additional operations for elements, e.g. hit tests.

 * Script-level interfaces.

 * Optional translation tables between real widget options and needed
   element options, e.g. _-elementborderwidth_ => _-borderwidth_.

 * How to handle native widgets? They will certainly have to be
   provided as whole elements.

 * Current implementation uses thread-local storage for holding
   dynamic data.  Since most data is not thread-specific, this could
   be changed to a more memory-efficient scheme.

 * Provide man pages and tests.

 * Additional hidden/private option flag for accessing some widgets'
   non-configurable data \(e.g. scrollbar position\) through option
   tables.

# Glossary

 Element: Part of a widget \(e.g. a checkbox mark or a scrollbar
	arrow\), usually active.

 Style: The visual appearance of a widget.  May include colors, skins,
        tiles, border drawing style \(Windows, Motif...\), element
        pictures.

 Styled element: A style-specific implementation of a widget element.

 Style engine: A visually consistent collection of styled elements.

 Theme: A collection of graphical elements giving a consistent
        appearance to a whole widget hierarchy, application, or
        desktop.  A theme is usually made up out of icons, colors,
        fonts, widget styles, or even desktop background and sounds.

# Copyright

This document has been placed in the public domain.

Name change from tip/49.tip to tip/49.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
TIP:          49
Title:        I/O Subsystem: Add API Tcl_OutputBuffered(chan)
Version:      $Revision: 1.4 $
Author:       Rolf Schroedter <[email protected]>
State:        Final
Type:         Project
Vote:         Done
Created:      25-Jul-2001
Post-History:
Tcl-Version:  8.4


~ Abstract

This document proposes the new public function ''Tcl_OutputBuffered()'',
analogous to the existing public function ''Tcl_InputBuffered()''.

~ Rationale

Tcl has a ''Tcl_InputBuffered()'' function but no analog
function for the output buffer. 
A ''Tcl_OutputBuffered()'' function would be useful
for non-blocking channel drivers which need to know the 
number of bytes pending in Tcl's output queue.

The implementation of [35] allows one to query the number of bytes 
in the channels input and output queues with a ''[fconfigure -queue]''
option. This is a useful feature especially for serial ports
because the input/output may be really slow or even stall.

On the driver level only the number of bytes in the system queue
can be queried. For a non-blocking channel there may also be
some pending output in Tcl buffers. 
Obviously there is not much sense to know only the byte counter
at driver level without knowing ''Tcl_OutputBuffered()''.

~ Related Ideas

It could also be useful to add general ''[fconfigure -inputbuffer
-outputbuffer]'' options for all channels returning the values from
''Tcl_InputBuffered(chan)'' and ''Tcl_OutputBuffered(chan)'' respectively.

At this opportunity the code of ''Tcl_Seek()'' and ''Tcl_Tell()''
may be shortened, because it repeats the code of 
''Tcl_InputBuffered()'' and ''Tcl_OutputBuffered()''.

~ Implementation

This function would be added to ''generic/tclIO.c'' and be 
stubs enabled. This new API should not have any impact
on existing applications.

The implementation is analog to what is done in ''Tcl_Tell()'':

|
|/*
| *----------------------------------------------------------------------
| *

| * Tcl_OutputBuffered --
| *

| *	Returns the number of bytes of output currently buffered in the
| *	common internal buffer of a channel.
| *

| * Results:
| *	The number of output bytes buffered, or zero if the channel is not
| *	open for writing.
| *

| * Side effects:
| *	None.
| *

| *----------------------------------------------------------------------
| */
|
|int
|Tcl_OutputBuffered(chan)
|    Tcl_Channel chan;			/* The channel to query. */
|{

|    ChannelState *statePtr = ((Channel *) chan)->state;
|					/* State of real channel structure. */
|    ChannelBuffer *bufPtr;
|    int bytesBuffered;
|
|    for (bytesBuffered = 0, bufPtr = statePtr->outQueueHead;
|	bufPtr != (ChannelBuffer *) NULL;
|	bufPtr = bufPtr->nextPtr) {
|	bytesBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved);
|    }

|    if ((statePtr->curOutPtr != (ChannelBuffer *) NULL) &&
|	    (statePtr->curOutPtr->nextAdded > statePtr->curOutPtr->nextRemoved)) {
|        statePtr->flags |= BUFFER_READY;
|        bytesBuffered +=
|            (statePtr->curOutPtr->nextAdded - statePtr->curOutPtr->nextRemoved);
|    }

|    return bytesBuffered;
|}

|

~ Copyright

This document has been placed in the public domain.


<
|
<
|
|
|
|
|
|
|
>

|

|
|

|

|

|



|
|







|

|

|
|
|

|

|

|

|



|

|
|
|
<
>
|
<
>
|
|
<
>
|
|
|
<
>
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
<
>
|

|


>


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

# TIP 49: I/O Subsystem: Add API Tcl_OutputBuffered(chan)

	Author:       Rolf Schroedter <[email protected]>
	State:        Final
	Type:         Project
	Vote:         Done
	Created:      25-Jul-2001
	Post-History:
	Tcl-Version:  8.4
-----

# Abstract

This document proposes the new public function _Tcl\_OutputBuffered\(\)_,
analogous to the existing public function _Tcl\_InputBuffered\(\)_.

# Rationale

Tcl has a _Tcl\_InputBuffered\(\)_ function but no analog
function for the output buffer. 
A _Tcl\_OutputBuffered\(\)_ function would be useful
for non-blocking channel drivers which need to know the 
number of bytes pending in Tcl's output queue.

The implementation of [[35]](35.md) allows one to query the number of bytes 
in the channels input and output queues with a _[fconfigure -queue]_
option. This is a useful feature especially for serial ports
because the input/output may be really slow or even stall.

On the driver level only the number of bytes in the system queue
can be queried. For a non-blocking channel there may also be
some pending output in Tcl buffers. 
Obviously there is not much sense to know only the byte counter
at driver level without knowing _Tcl\_OutputBuffered\(\)_.

# Related Ideas

It could also be useful to add general _[fconfigure -inputbuffer
-outputbuffer]_ options for all channels returning the values from
_Tcl\_InputBuffered\(chan\)_ and _Tcl\_OutputBuffered\(chan\)_ respectively.

At this opportunity the code of _Tcl\_Seek\(\)_ and _Tcl\_Tell\(\)_
may be shortened, because it repeats the code of 
_Tcl\_InputBuffered\(\)_ and _Tcl\_OutputBuffered\(\)_.

# Implementation

This function would be added to _generic/tclIO.c_ and be 
stubs enabled. This new API should not have any impact
on existing applications.

The implementation is analog to what is done in _Tcl\_Tell\(\)_:

	
	/*
	 *----------------------------------------------------------------------

	 *
	 * Tcl_OutputBuffered --

	 *
	 *	Returns the number of bytes of output currently buffered in the
	 *	common internal buffer of a channel.

	 *
	 * Results:
	 *	The number of output bytes buffered, or zero if the channel is not
	 *	open for writing.

	 *
	 * Side effects:
	 *	None.

	 *
	 *----------------------------------------------------------------------
	 */
	
	int
	Tcl_OutputBuffered(chan)
	    Tcl_Channel chan;			/* The channel to query. */

	{
	    ChannelState *statePtr = ((Channel *) chan)->state;
						/* State of real channel structure. */
	    ChannelBuffer *bufPtr;
	    int bytesBuffered;
	
	    for (bytesBuffered = 0, bufPtr = statePtr->outQueueHead;
		bufPtr != (ChannelBuffer *) NULL;
		bufPtr = bufPtr->nextPtr) {
		bytesBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved);

	    }
	    if ((statePtr->curOutPtr != (ChannelBuffer *) NULL) &&
		    (statePtr->curOutPtr->nextAdded > statePtr->curOutPtr->nextRemoved)) {
	        statePtr->flags |= BUFFER_READY;
	        bytesBuffered +=
	            (statePtr->curOutPtr->nextAdded - statePtr->curOutPtr->nextRemoved);

	    }
	    return bytesBuffered;

	}
	

# Copyright

This document has been placed in the public domain.


Name change from tip/5.tip to tip/5.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262

263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279

280
281
282
283
284
285
286
287
288

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370

TIP:            5
Title:          Make TkClassProcs and TkSetClassProcs Public and Extensible
Version:        $Revision: 1.3 $
Author:         Eric Melski <[email protected]>
State:          Final
Type:           Project
Tcl-Version:    8.4
Vote:           Done
Created:        17-Oct-2000
Post-History:


~ Abstract

At certain critical moments in the lifetime of a Tk widget, Tk will
invoke various callbacks on that widget.  These callbacks enable the
widget to do lots of interesting things, such as react to
configuration changes for named fonts, or create and manage truly
native widgets (such as the scrollbar widget on Windows platforms).
The API for setting up these callbacks for a particular window are, as
of Tk 8.3.2, private.  This prohibits extension widget authors from fully
utilizing this powerful system; those developers can either copy the
private declarations into their own source code (leading to future
maintenance hassles), or forego the system entirely, hampering their
ability to make truly native and well-integrated widgets.  This
proposal offers an extensible means for making that API public.

~ Rationale:  Why make TkClassProcs and TkSetClassProcs public?

(The following text is adapted from George Howlett
[http://dev.scriptics.com/lists/tclcore/2000/10/msg00143.html])

The Tk toolkit was originally written strictly for Xlib.  It created
wrappers for many of the Xlib calls.  A good example is creating a
window.  Tk's ''Tk_CreateWindow'' call in turn calls Xlib's
''XCreateWindow''.  This is so that the toolkit can perform
bookkeeping on the window and manage it in various ways.  The down
side was that if you needed to pass specific information/flags to the
''XCreateWindow'' call you couldn't.  But this only affected
extensions.

Now when Tk 8.0 added native widgets, Tk also had the same problem.
For example to create a Win32 button control, you have to pass
information through the X emulation layer to the eventual Win32
CreateWindow or CreateWindowEx call.

So the Sun Tk developers created this notion of class procedures.  A
widget of particular type may need to make different calls at the time
the window is created.  They added to the TkWindow structure pointers
to both the widget instance (i.e. the data the represents the specific
widget) and a structure of function pointers (such as one to call when
the window is to be created).

|TkClassProcs tkpButtonProcs =
|
|    CreateProc,             /* createProc. */
|    TkButtonWorldChanged,   /* geometryProc. */
|    NULL                    /* modalProc. */
|};

Inside of Tk, such as in ''Tk_MakeWindowExist'', code was added to
check if the ''createProc'' of the structure isn't NULL and call that
routine to create the native window.

This mechanism was also used to handle font aliasing.  I can create a
font "fred" that is really a { courier bold } font and use it with any
Tk widget.

|font create fred -family courier -weight bold
|button .b -font fred

The widget will get the real font and use it in its graphics context.
Think of GCs like a pen drawing a particular color.  A GC draws with a
particular font.

Now if I change the font, the widget's GC must be updated too.

|font create fred -family helvetica -weight medium

You can see where a ''geometryProc'' is needed to indicate when font
aliases change.  It gets called for all the widgets using the font.

Another callback is used to handle modal events.  This is currently
needed only for the Win32 native scrollbar.

So here's the private structure and ''TkSetClassProcs'' call.

|typedef Window (TkClassCreateProc) _ANSI_ARGS_((Tk_Window tkwin,
|	 Window parent, ClientData instanceData));
|typedef void (TkClassGeometryProc) _ANSI_ARGS_((ClientData instanceData));
|typedef void (TkClassModalProc) _ANSI_ARGS_((Tk_Window tkwin,
|	 XEvent *eventPtr));
|
|/*
| * Widget class procedures used to implement platform specific widget
| * behavior.
| */
|
|typedef struct TkClassProcs {
|    TkClassCreateProc *createProc;
|			 /* Procedure to invoke when the
|			    platform-dependent window needs to be
|			    created. */
|    TkClassGeometryProc *geometryProc;
|			 /* Procedure to invoke when the geometry of a
|			    window needs to be recalculated as a result
|			    of some change in the system. */
|    TkClassModalProc *modalProc;
|			 /* Procedure to invoke after all bindings on a
|			    widget have been triggered in order to
|			    handle a modal loop. */
|} TkClassProcs;
|
|void
|TkSetClassProcs(tkwin, procs, instanceData)
|    Tk_Window tkwin;        /* Token for window to modify. */
|    TkClassProcs *procs;    /* Class procs structure. */
|    ClientData instanceData;/* Data to be passed to class procedures. */
|{

|    register TkWindow *winPtr = (TkWindow *) tkwin;
|
|    winPtr->classProcsPtr = procs;
|    winPtr->instanceData = instanceData;
|}


Extension developers could not use this interface, however, because it
was private to Tk.  The original authors of the interface didn't think
that anything outside of the Tk widgets would need it.  Of course,
hindsight is 20-20, and we have since found that this is not true.
Extension developers do need to use this system:  widget writers that
use fonts obviously need to know when a font alias changes, and new
Win32 native widgets also need access to this mechanism.

Most extensions authors had/have already found a workaround: copy in
the ''TkClassProcs'' structure and ''TkSetClassProcs'' routine into
your code.  However, this workaround leads to future code maintenance
problems.  Because the structure is private, its members and usage are
not guaranteed to remain constant between versions of Tk.  If the
structure changes, the extension authors have to update all of their
code accordingly.

Making the system public locks in the format and usage of the system,
so that extension authors can rely on it existing from one version to
the next, and they will no longer have to maintain parallel redundant
copies of the structure and function definition.

~ Rationale: Why make TkClassProcs and TkSetClassProcs extensible?

Every time we've made a public structure, we've regretted it later
when we needed to extend it to handle some new feature that we didn't
originally anticipate.  In general we should avoid designing new API's
that preclude making future changes without introducing
incompatibilities.
[http://dev.scriptics.com/lists/tclcore/2000/10/msg00083.html]


This system is one that seems likely to require extension in the
future.  There are currently three callbacks: create window, geometry
change, and modal event.  Already one request to extend the mechanism
has been made, to support the notion of a "client area" related to
geometry management and labelled frame widgets
([http://dev.scriptics.com/lists/tclcore/2000/10/msg00121.html],
[http://dev.scriptics.com/lists/tclcore/2000/10/msg00170.html]).
Another possible extension is a focus management callback, to allow
for smoother focus transitions between native widgets and Tk widgets;
note that this focus management callback is a purely hypothetical
extension at this time.

If the system is one that we are likely to want to extend with
additional callbacks in the future, it behooves us to make it public
in a manner that allows us to extend it while causing the minimum
amount of disruption for extension authors.  There are two concerns
here.  First is binary compatibility: will an extension compiled
against a version of Tk which features the base (three callback)
''TkClassProcs'' system work with a version of Tk that features an
extended ''TkClassProcs'' system?  Second is source compatibility:
will an extension author have to update their sources when they want
to recompile their extension against a version of Tk that features an
extended ''TkClassProcs'' system?  Ideally, the system that we make
public will allow extension while retaining binary and source
compatibility between versions of Tk.

~ Specification

I propose that the following steps be taken to make ''TkClassProcs''
and ''TkSetClassProcs'' public:

   1.  Rename ''TkClassProcs'' to ''Tk_ClassProcs''; rename
       ''TkSetClassProcs'' to ''Tk_SetClassProcs''; rename
       ''TkClassCreateProc'', etc., to ''Tk_ClassCreateProc'', etc.
       Move the structure definition, function prototype, and callback
       typedefs from tkInt.h to tk.h.  This is in keeping with Tk
       public interface naming conventions.

   2.  Add a single size field to the ''Tk_ClassProcs'' structure.
       This field is initialized at the time that the structure is
       allocated, and always contains the size of the structure.  This
       field will be used to provide a simple versioning scheme for
       the structure.  Portions of Tk that use the class proc
       callbacks will inspect this size field to ascertain whether or
       not a particular instance of the ''Tk_ClassProcs'' structure is
       of a version that contains a given callback.  See the example
       below.

   3.  Rename the ''geometryProc'' callback to ''worldChangedProc''.
       The name ''geometryProc'' is somewhat misleading.  Currently,
       the callback is used only to support font aliasing, as
       described above.  This is sort of geometry related, but it
       doesn't necessarily mean that geometry of the widget must
       change, it just means that the widget will have to update its
       world view to reflect the current state of the world.  In
       addition, the callback will likely be used to support color
       aliasing when that is added to Tk (imagine defining a color
       "myColor" to mean "#c4d3a2" and then configuring widgets to use
       "myColor" instead of the literal value; this provides all the
       benefits for colors that font aliasing does for fonts).  When
       that is done, ''geometryProc'' will be truly misleading, since
       a color change probably does not mean a geometry change for the
       widget.

   4.  Change the order of the callback fields in the
       ''Tk_ClassProcs'' structure, making ''worldChangedProc'' the
       first of the callbacks listed in the structure.  In the
       existing private ''TkClassProcs'' structure, the first callback
       is the ''createProc''.  It is not strictly necessary to make
       ''worldChangedProc'' the first callback.  However, most widgets
       in Tk (canvas, entry, scale, text, message, listbox, menu,
       menubuttons, scrollbars on Unix and Mac, and buttons on Unix
       and Mac) use only this callback.  Making it first in the
       structure (after the size field, which must be the very first
       entry) means a little bit less work for widget authors in the
       common case, because they need not include the NULL declaration
       for the ''createProc'' slot in the structure.  Compare:

|static Tk_ClassProcs myClassProcs = {
|    sizeof(Tk_ClassProcs), NULL, myWorldChangedProc
|};

 >     with:

|static Tk_ClassProcs myClassProcs = {
|    sizeof(Tk_ClassProcs), myWorldChangedProc
|};

 >     Since the ''createProc'' is used so infrequently, why require
       that all widget authors explicitly declare it to be NULL?  This
       change just simplifies everybody's life that much more.


Usage of the public API will be very similar to usage of the existing
private API:

|static Tk_ClassProcs myClassProcs = {
|    sizeof(Tk_ClassProcs),
|    myWorldChangedProc
|};
|
|static int Tk_MyWidgetObjCmd(...) {
|    ...
|    Tk_SetClassProcs(widgetPtr->tkwin,myClassProcs,(ClientData)widgetPtr);
|    ...
|    return TCL_OK;
|}


Portions of Tk that need to use a particular callback, such as
''Tk_MakeWindowExist'', use code like the following:

|Tk_ClassProcs *thisClassProcs = tkwin->classProcs;
|createProc *procPtr;
|
|/* Make sure the structure we were given has the createProc field
| * in it by checking that the size of the structure is at least
| * big enough to have that slot.
| */
|
|if (thisClassProcs->size <= Tk_Offset(Tk_ClassProcs, createProc)) {
|    procPtr = NULL;
|} else {
|    procPtr = thisClassProcs->createProc;
|}

|
|if (procPtr != NULL) {
|    /* Invoke the createProc for this window. */
|    ...
|} else {
|    /* Use the default Tk window creation mechanism. */
|    ...
|}


~ Benefits of this implementation

Benefits of this implementation are as follows:

   1.  Usage of ''Tk_ClassProcs'' and ''Tk_SetClassProcs'' very, very
       closely parallels the usage of the existing private API.  In
       fact, the only difference is a small change in the particular
       fields of the ''Tk_ClassProcs'' structure (especially, the new
       size field, for version information, and the reordering of the
       callback fields).

   2.  All instances of "mywidget" reference the same
       ''Tk_ClassProcs'' structure.  This is memory efficient.

   3.  We do not need to explicitly initialize to NULL those fields of
       myClassProcs that we don't use.  The ANSI C specification
       states that static variables (and members of statically
       declared structures) that are not explicitly initialized are
       initialized to zero.

   4.  This retains binary compatibility.  The size field of the
       ''Tk_ClassProcs'' structure is set at compile time, so when a
       later version of Tk checks the size field to see if a new
       callback can be used, it will fail.  That is, if extension
       author A compiles the extension against version X of Tk, which
       has three fields in ''Tk_ClassProcs'', the size field of
       myClassProcs will be set to 12 (assuming 4-byte pointers).
       When using that extension with Tk version Y, which may have
       four fields in ''Tk_ClassProcs'', the size check for that
       fourth field will fail, since the size field, set to 12, will
       be less than or equal to the offset of the fourth field in the
       structure.

   5.  This retains source compatibility.  Because of #3 above, unless
       the extension author wants to use the new callbacks, they need
       not worry about their addition, because the new fields will be
       automatically set to zero.

   6.  There is minimal API bloat.  Only one public API is added,
       ''Tk_SetClassProcs''.

   7.  The system is "type safe" with respect to the function
       signatures of the callback functions.  Any type mismatches will
       be caught at compile time.

   8.  If desired, widget authors can directly reference elements of
       the ''Tk_ClassProcs'' structure:

|myClassProcs.createProc = myCreateProc;


~ Drawbacks of this implementation

The drawbacks of this implementation are as follows:

   1.  The required value of the size field will seem like a bit of
       black magic to developers new to the system.  The question
       ''"Why does this field have to be set to this value?  If it's
       always the same thing, why is it stored at all?"''  Of course,
       experienced programmers will recognize why it has to be set,
       and that in fact, it is not always the same value.  This issue
       can best be addressed by appropriate documentation.

   2.  Extensions that use the existing private ''TkClassProcs'' and
       ''TkSetClassProcs'' mechanism and which were compiled against
       versions of Tk <= 8.3 will not work with new versions of Tk,
       since the format of the ''Tk_ClassProcs'' structure will
       change.  However, this is the consequence of using private
       structures and API's in your extensions: when those private
       structures and API's change, you have to update your extension
       accordingly.  We cannot allow ourselves to be overly
       constrained by this issue.  The existing mechanism is private,
       period.  Authors that use it do so knowingly and willfully.


~ Reference Implementation

http://sourceforge.net/patch/?func=detailpatch&patch_id=102213&group_id=10894

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|





|



|
|



|

|
|



|
|


|










|
|
|

|
|
|
|
|
|

|
|



|


|
|







|

|





|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>










|











|






|







|
|










|
|
|


|



|

|
|

|
|
|




|





|



|
|






|
|

|
|




|

|
|
|
|

|
|
|

|

|
|
|

|

|
|
|

|







|
|
|
|
|
|
|
|
|
|
<
>


|

|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
|
>
|



|


|

|


|



|
|



|



|
|

|




|





|






|

|


|





|
|




|
|

|








|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277

278
279
280
281
282
283
284
285

286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370

# TIP 5: Make TkClassProcs and TkSetClassProcs Public and Extensible

	Author:         Eric Melski <[email protected]>
	State:          Final
	Type:           Project
	Tcl-Version:    8.4
	Vote:           Done
	Created:        17-Oct-2000
	Post-History:
-----

# Abstract

At certain critical moments in the lifetime of a Tk widget, Tk will
invoke various callbacks on that widget.  These callbacks enable the
widget to do lots of interesting things, such as react to
configuration changes for named fonts, or create and manage truly
native widgets \(such as the scrollbar widget on Windows platforms\).
The API for setting up these callbacks for a particular window are, as
of Tk 8.3.2, private.  This prohibits extension widget authors from fully
utilizing this powerful system; those developers can either copy the
private declarations into their own source code \(leading to future
maintenance hassles\), or forego the system entirely, hampering their
ability to make truly native and well-integrated widgets.  This
proposal offers an extensible means for making that API public.

# Rationale:  Why make TkClassProcs and TkSetClassProcs public?

\(The following text is adapted from George Howlett
<http://dev.scriptics.com/lists/tclcore/2000/10/msg00143.html> \)

The Tk toolkit was originally written strictly for Xlib.  It created
wrappers for many of the Xlib calls.  A good example is creating a
window.  Tk's _Tk\_CreateWindow_ call in turn calls Xlib's
_XCreateWindow_.  This is so that the toolkit can perform
bookkeeping on the window and manage it in various ways.  The down
side was that if you needed to pass specific information/flags to the
_XCreateWindow_ call you couldn't.  But this only affected
extensions.

Now when Tk 8.0 added native widgets, Tk also had the same problem.
For example to create a Win32 button control, you have to pass
information through the X emulation layer to the eventual Win32
CreateWindow or CreateWindowEx call.

So the Sun Tk developers created this notion of class procedures.  A
widget of particular type may need to make different calls at the time
the window is created.  They added to the TkWindow structure pointers
to both the widget instance \(i.e. the data the represents the specific
widget\) and a structure of function pointers \(such as one to call when
the window is to be created\).

	TkClassProcs tkpButtonProcs =
	
	    CreateProc,             /* createProc. */
	    TkButtonWorldChanged,   /* geometryProc. */
	    NULL                    /* modalProc. */
	};

Inside of Tk, such as in _Tk\_MakeWindowExist_, code was added to
check if the _createProc_ of the structure isn't NULL and call that
routine to create the native window.

This mechanism was also used to handle font aliasing.  I can create a
font "fred" that is really a \{ courier bold \} font and use it with any
Tk widget.

	font create fred -family courier -weight bold
	button .b -font fred

The widget will get the real font and use it in its graphics context.
Think of GCs like a pen drawing a particular color.  A GC draws with a
particular font.

Now if I change the font, the widget's GC must be updated too.

	font create fred -family helvetica -weight medium

You can see where a _geometryProc_ is needed to indicate when font
aliases change.  It gets called for all the widgets using the font.

Another callback is used to handle modal events.  This is currently
needed only for the Win32 native scrollbar.

So here's the private structure and _TkSetClassProcs_ call.

	typedef Window (TkClassCreateProc) _ANSI_ARGS_((Tk_Window tkwin,
		 Window parent, ClientData instanceData));
	typedef void (TkClassGeometryProc) _ANSI_ARGS_((ClientData instanceData));
	typedef void (TkClassModalProc) _ANSI_ARGS_((Tk_Window tkwin,
		 XEvent *eventPtr));
	
	/*
	 * Widget class procedures used to implement platform specific widget
	 * behavior.
	 */
	
	typedef struct TkClassProcs {
	    TkClassCreateProc *createProc;
				 /* Procedure to invoke when the
				    platform-dependent window needs to be
				    created. */
	    TkClassGeometryProc *geometryProc;
				 /* Procedure to invoke when the geometry of a
				    window needs to be recalculated as a result
				    of some change in the system. */
	    TkClassModalProc *modalProc;
				 /* Procedure to invoke after all bindings on a
				    widget have been triggered in order to
				    handle a modal loop. */
	} TkClassProcs;
	
	void
	TkSetClassProcs(tkwin, procs, instanceData)
	    Tk_Window tkwin;        /* Token for window to modify. */
	    TkClassProcs *procs;    /* Class procs structure. */
	    ClientData instanceData;/* Data to be passed to class procedures. */

	{
	    register TkWindow *winPtr = (TkWindow *) tkwin;
	
	    winPtr->classProcsPtr = procs;
	    winPtr->instanceData = instanceData;

	}

Extension developers could not use this interface, however, because it
was private to Tk.  The original authors of the interface didn't think
that anything outside of the Tk widgets would need it.  Of course,
hindsight is 20-20, and we have since found that this is not true.
Extension developers do need to use this system:  widget writers that
use fonts obviously need to know when a font alias changes, and new
Win32 native widgets also need access to this mechanism.

Most extensions authors had/have already found a workaround: copy in
the _TkClassProcs_ structure and _TkSetClassProcs_ routine into
your code.  However, this workaround leads to future code maintenance
problems.  Because the structure is private, its members and usage are
not guaranteed to remain constant between versions of Tk.  If the
structure changes, the extension authors have to update all of their
code accordingly.

Making the system public locks in the format and usage of the system,
so that extension authors can rely on it existing from one version to
the next, and they will no longer have to maintain parallel redundant
copies of the structure and function definition.

# Rationale: Why make TkClassProcs and TkSetClassProcs extensible?

Every time we've made a public structure, we've regretted it later
when we needed to extend it to handle some new feature that we didn't
originally anticipate.  In general we should avoid designing new API's
that preclude making future changes without introducing
incompatibilities.
<http://dev.scriptics.com/lists/tclcore/2000/10/msg00083.html> 


This system is one that seems likely to require extension in the
future.  There are currently three callbacks: create window, geometry
change, and modal event.  Already one request to extend the mechanism
has been made, to support the notion of a "client area" related to
geometry management and labelled frame widgets
\(<http://dev.scriptics.com/lists/tclcore/2000/10/msg00121.html> ,
<http://dev.scriptics.com/lists/tclcore/2000/10/msg00170.html> \).
Another possible extension is a focus management callback, to allow
for smoother focus transitions between native widgets and Tk widgets;
note that this focus management callback is a purely hypothetical
extension at this time.

If the system is one that we are likely to want to extend with
additional callbacks in the future, it behooves us to make it public
in a manner that allows us to extend it while causing the minimum
amount of disruption for extension authors.  There are two concerns
here.  First is binary compatibility: will an extension compiled
against a version of Tk which features the base \(three callback\)
_TkClassProcs_ system work with a version of Tk that features an
extended _TkClassProcs_ system?  Second is source compatibility:
will an extension author have to update their sources when they want
to recompile their extension against a version of Tk that features an
extended _TkClassProcs_ system?  Ideally, the system that we make
public will allow extension while retaining binary and source
compatibility between versions of Tk.

# Specification

I propose that the following steps be taken to make _TkClassProcs_
and _TkSetClassProcs_ public:

   1.  Rename _TkClassProcs_ to _Tk\_ClassProcs_; rename
       _TkSetClassProcs_ to _Tk\_SetClassProcs_; rename
       _TkClassCreateProc_, etc., to _Tk\_ClassCreateProc_, etc.
       Move the structure definition, function prototype, and callback
       typedefs from tkInt.h to tk.h.  This is in keeping with Tk
       public interface naming conventions.

   2.  Add a single size field to the _Tk\_ClassProcs_ structure.
       This field is initialized at the time that the structure is
       allocated, and always contains the size of the structure.  This
       field will be used to provide a simple versioning scheme for
       the structure.  Portions of Tk that use the class proc
       callbacks will inspect this size field to ascertain whether or
       not a particular instance of the _Tk\_ClassProcs_ structure is
       of a version that contains a given callback.  See the example
       below.

   3.  Rename the _geometryProc_ callback to _worldChangedProc_.
       The name _geometryProc_ is somewhat misleading.  Currently,
       the callback is used only to support font aliasing, as
       described above.  This is sort of geometry related, but it
       doesn't necessarily mean that geometry of the widget must
       change, it just means that the widget will have to update its
       world view to reflect the current state of the world.  In
       addition, the callback will likely be used to support color
       aliasing when that is added to Tk \(imagine defining a color
       "myColor" to mean "\#c4d3a2" and then configuring widgets to use
       "myColor" instead of the literal value; this provides all the
       benefits for colors that font aliasing does for fonts\).  When
       that is done, _geometryProc_ will be truly misleading, since
       a color change probably does not mean a geometry change for the
       widget.

   4.  Change the order of the callback fields in the
       _Tk\_ClassProcs_ structure, making _worldChangedProc_ the
       first of the callbacks listed in the structure.  In the
       existing private _TkClassProcs_ structure, the first callback
       is the _createProc_.  It is not strictly necessary to make
       _worldChangedProc_ the first callback.  However, most widgets
       in Tk \(canvas, entry, scale, text, message, listbox, menu,
       menubuttons, scrollbars on Unix and Mac, and buttons on Unix
       and Mac\) use only this callback.  Making it first in the
       structure \(after the size field, which must be the very first
       entry\) means a little bit less work for widget authors in the
       common case, because they need not include the NULL declaration
       for the _createProc_ slot in the structure.  Compare:

		static Tk_ClassProcs myClassProcs = {
		    sizeof(Tk_ClassProcs), NULL, myWorldChangedProc
		};

	 >     with:

		static Tk_ClassProcs myClassProcs = {
		    sizeof(Tk_ClassProcs), myWorldChangedProc
		};

	 >     Since the _createProc_ is used so infrequently, why require
       that all widget authors explicitly declare it to be NULL?  This
       change just simplifies everybody's life that much more.


Usage of the public API will be very similar to usage of the existing
private API:

	static Tk_ClassProcs myClassProcs = {
	    sizeof(Tk_ClassProcs),
	    myWorldChangedProc
	};
	
	static int Tk_MyWidgetObjCmd(...) {
	    ...
	    Tk_SetClassProcs(widgetPtr->tkwin,myClassProcs,(ClientData)widgetPtr);
	    ...
	    return TCL_OK;

	}

Portions of Tk that need to use a particular callback, such as
_Tk\_MakeWindowExist_, use code like the following:

	Tk_ClassProcs *thisClassProcs = tkwin->classProcs;
	createProc *procPtr;
	
	/* Make sure the structure we were given has the createProc field
	 * in it by checking that the size of the structure is at least
	 * big enough to have that slot.
	 */
	
	if (thisClassProcs->size <= Tk_Offset(Tk_ClassProcs, createProc)) {
	    procPtr = NULL;
	} else {
	    procPtr = thisClassProcs->createProc;

	}
	
	if (procPtr != NULL) {
	    /* Invoke the createProc for this window. */
	    ...
	} else {
	    /* Use the default Tk window creation mechanism. */
	    ...

	}

# Benefits of this implementation

Benefits of this implementation are as follows:

   1.  Usage of _Tk\_ClassProcs_ and _Tk\_SetClassProcs_ very, very
       closely parallels the usage of the existing private API.  In
       fact, the only difference is a small change in the particular
       fields of the _Tk\_ClassProcs_ structure \(especially, the new
       size field, for version information, and the reordering of the
       callback fields\).

   2.  All instances of "mywidget" reference the same
       _Tk\_ClassProcs_ structure.  This is memory efficient.

   3.  We do not need to explicitly initialize to NULL those fields of
       myClassProcs that we don't use.  The ANSI C specification
       states that static variables \(and members of statically
       declared structures\) that are not explicitly initialized are
       initialized to zero.

   4.  This retains binary compatibility.  The size field of the
       _Tk\_ClassProcs_ structure is set at compile time, so when a
       later version of Tk checks the size field to see if a new
       callback can be used, it will fail.  That is, if extension
       author A compiles the extension against version X of Tk, which
       has three fields in _Tk\_ClassProcs_, the size field of
       myClassProcs will be set to 12 \(assuming 4-byte pointers\).
       When using that extension with Tk version Y, which may have
       four fields in _Tk\_ClassProcs_, the size check for that
       fourth field will fail, since the size field, set to 12, will
       be less than or equal to the offset of the fourth field in the
       structure.

   5.  This retains source compatibility.  Because of \#3 above, unless
       the extension author wants to use the new callbacks, they need
       not worry about their addition, because the new fields will be
       automatically set to zero.

   6.  There is minimal API bloat.  Only one public API is added,
       _Tk\_SetClassProcs_.

   7.  The system is "type safe" with respect to the function
       signatures of the callback functions.  Any type mismatches will
       be caught at compile time.

   8.  If desired, widget authors can directly reference elements of
       the _Tk\_ClassProcs_ structure:

		myClassProcs.createProc = myCreateProc;


# Drawbacks of this implementation

The drawbacks of this implementation are as follows:

   1.  The required value of the size field will seem like a bit of
       black magic to developers new to the system.  The question
       _"Why does this field have to be set to this value?  If it's
       always the same thing, why is it stored at all?"_  Of course,
       experienced programmers will recognize why it has to be set,
       and that in fact, it is not always the same value.  This issue
       can best be addressed by appropriate documentation.

   2.  Extensions that use the existing private _TkClassProcs_ and
       _TkSetClassProcs_ mechanism and which were compiled against
       versions of Tk <= 8.3 will not work with new versions of Tk,
       since the format of the _Tk\_ClassProcs_ structure will
       change.  However, this is the consequence of using private
       structures and API's in your extensions: when those private
       structures and API's change, you have to update your extension
       accordingly.  We cannot allow ourselves to be overly
       constrained by this issue.  The existing mechanism is private,
       period.  Authors that use it do so knowingly and willfully.


# Reference Implementation

<http://sourceforge.net/patch/?func=detailpatch&patch\_id=102213&group\_id=10894>

# Copyright

This document has been placed in the public domain.

Name change from tip/50.tip to tip/50.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

185
TIP:            50
Title:          Bundle [incr Tcl] with the Core Tcl distribution
Version:        $Revision: 1.12 $
Author:         Kevin Kenny <[email protected]>
Author:         Mark Harrison <[email protected]>
Author:         Jeff Hobbs <[email protected]>
Author:         Andreas Kupries <[email protected]>
Author:         Karl Lehenbauer <[email protected]>
Author:         Michael McLennan <[email protected]>
Author:         Don Porter <[email protected]>
Author:         Brent Welch <[email protected]>
State:          Final
Type:           Informative
Vote:           Done
Created:        27-Jul-2001
Post-History:   


~ Abstract

A "town meeting" discussion in which users were given the opportunity
to question the Tcl Core Team at the 2001 Open Source Convention has
revealed a great popular demand for bundling an object system with the
distribution of the Tcl Core.  This TIP presents a compromise proposal
for including [[incr Tcl]] that was acceptable to all eight TCT members
present.

~ Proposal

   * [[incr Tcl]] [http://tcltk.com/itcl/] shall be bundled with the core
     Tcl distribution.

   * [[incr Tcl]] shall be "included" in the Core in only a weak
     sense.

      > The location of the [[incr Tcl]] source tree shall be left to
        the discretion of the affected maintainers.  (It appears likely
        that most [[incr Tcl]] source will appear in a separate
        ''itcl'' directory parallel to the ''generic'', ''mac'',
        ''unix'' and ''win'' directories in the source.)

      > [[incr Tcl]] shall be built as a separate loadable package, 
        similar to the ''dde'', ''http'', ''msgcat'', and ''registry'' 
        packages.  

      > The ''::itcl'' namespace shall be the only new component 
        included in the global namespace, and shall appear only when 
        a script executes

|               package require Itcl

      > There shall be no ''::class'' command in the Core.

      > The ''::info'' command shall not provide any subcommands
        specific to [[incr Tcl]].

   * [[incr Tcl]] shall not be substantially modified under the scope
     of this TIP.

      > The existing issues surrounding errors thrown from object
        destructors shall not be addressed.

      > The existing use of ''rename'' for object destruction shall
        not be amended.

      > All other limitations of [[incr Tcl]] are initially accepted
        as they are.

      > Of course, additional TIPs could be submitted to modify
        [[incr Tcl]] as desired!

   * The TCT shall assume the role of ''gatekeeper'' for changes to
     the functionality of [[incr Tcl]].

      > Changes that affect user-visible functionality of [[incr Tcl]]
        shall be made through the TIP process.

      > Informational TIPs identifying maintainer areas and assigning
        maintainers to them shall be developed.

   * Nothing in this TIP shall be construed as identifying [[incr
     Tcl]] as a single preferred object system for Tcl.  If the
     community desires other systems such as OTcl, XOTcl, or ObjecTcl
     to stand on an equal footing to [[incr Tcl]], their champions
     can introduce TIPs similar to this one.

   * [[incr Tk]] and [[incr widgets]] are outside the scope of this TIP.

~ Rationale

The lack of a standard object and data abstraction system continues to
hinder Tcl development.

  > "Lets face it, not including any sort of OO system is one of
    the major failings of Tcl. Indexing into global arrays is
    a sad hack when compared to a real OO system."
           ''- Mo DeJong <[email protected]>''

Moreover, the argument that "Tcl is not object oriented" continues to
hamper Tcl marketing.  Including at least one object system with the
Tcl core, so that it is dependably available unless the user has built
from source, would address this objection.

Since an earler proposal ([6]) to incorporate [[incr Tcl]] into the
Core failed to garner the necessary votes, at least in part because
participants were uncertain of the rationales, it seems wise to
discuss the individual points in further detail.

   * All agree that some sort of object system must be bundled with
     the core so that it is dependably available.  [[incr Tcl]]
     appears to be the most popular of the existing systems, as well
     as the most familiar to the current TCT, making it the most
     attractive of several candidates for this role.

   * The original [[incr Tcl]] developers have pointed out that
     bundling in the Core would facilitate [[incr Tcl]] development
     greatly.  While it is a separate loadable package, [[incr Tcl]]
     is intimate with the core, depending on many undocumented
     interfaces to carry out its functions.  Integrating it with the
     Core would make it easier to maintain.

   * Including a ''::class'' command in the Core is not acceptable at
     this time, because it would have the effect of disenfranchising
     the users of other object systems -- who are too numerous to
     ignore.  Moreover, the ability of Tcl to serve as a test platform
     for novel object models must not be compromised.

   * Similarly, integrating [[incr Tcl]] closely with commands such as
     ''::info'' or ''::destroy'' would accord it a privileged status
     that the users of other object systems are reluctant to accept.

   * [[incr Tcl]] is what it is.  It would be inappropriate to demand
     that all the perceived shortcomings of the [[incr Tcl]] system be
     addressed prior to inclusion in the Core.  The TIP process is
     available to make further changes; the system is certainly good
     enough that many thousands of programmers use it daily.

   * If [[incr Tcl]] is to be included in the Core, then common sense
     requires that it be under control of the TIP process.

~ Alternatives

   * Include [[incr Tcl]] in a "batteries included" (BI) distribution.

      > Many people will not opt for the BI distribution ([4]) due to its
        larger size.  It is quite likely that (for example) a Linux
        distribution my include Tcl as a standard component, but place the BI
        on a supplemental disk.

      > Moreover, as mentioned above, the [[incr Tcl]] sources are
        already intimate with the Tcl core; there are great
        maintenance savings to be achieved by combining the source
        distributions. 

   * Integrate [[incr Tcl]] tightly into the Tcl Core.

      > This alternative is unacceptable to a good many users.  A
        number of attendees at the 2001 Open Source Convention
        mentioned specifically that they use alternative object
        systems such as OTcl.  These users would be essentially
        disenfranchised if, for instance, a ''::class'' command were to
        appear in the Core.

~ Implementation

Jeff Hobbs has volunteered to lead the implementation effort with
the assistance of all volunteers who want to help.

~ Notes

Eight members of the Tcl Core Team (Harrison, Hobbs, Kenny, Kupries,
Lehenbauer, McLennan, Porter and Welch) agreed orally to this proposal
at the 2001 Open Source Convention.  Since not all have had the
opportunity to read the formal written version of the proposal, that
vote shall not be considered binding.

~ References

   * http://tcltk.com//itcl

   * [6]

~ Copyright

This document has been placed in the public domain.


<
|
<
|
|
|
|
|
|
|
|
|
|
|
|
|
>

|





|


|

|


|


|
|
|
|
|

|
|


|



|

|

|
|

|


|


|


|


|
|

|
|

|


|


|
|

|


|

|







|






|





|




|
|
|




|





|
|


|
|




|


|

|

|
|



|




|

|



|


|




|

|
|




|

|

|

|


>


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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

# TIP 50: Bundle [incr Tcl] with the Core Tcl distribution

	Author:         Kevin Kenny <[email protected]>
	Author:         Mark Harrison <[email protected]>
	Author:         Jeff Hobbs <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	Author:         Karl Lehenbauer <[email protected]>
	Author:         Michael McLennan <[email protected]>
	Author:         Don Porter <[email protected]>
	Author:         Brent Welch <[email protected]>
	State:          Final
	Type:           Informative
	Vote:           Done
	Created:        27-Jul-2001
	Post-History:   
-----

# Abstract

A "town meeting" discussion in which users were given the opportunity
to question the Tcl Core Team at the 2001 Open Source Convention has
revealed a great popular demand for bundling an object system with the
distribution of the Tcl Core.  This TIP presents a compromise proposal
for including [incr Tcl] that was acceptable to all eight TCT members
present.

# Proposal

   * [incr Tcl] <http://tcltk.com/itcl/>  shall be bundled with the core
     Tcl distribution.

   * [incr Tcl] shall be "included" in the Core in only a weak
     sense.

	      > The location of the [incr Tcl] source tree shall be left to
        the discretion of the affected maintainers.  \(It appears likely
        that most [incr Tcl] source will appear in a separate
        _itcl_ directory parallel to the _generic_, _mac_,
        _unix_ and _win_ directories in the source.\)

	      > [incr Tcl] shall be built as a separate loadable package, 
        similar to the _dde_, _http_, _msgcat_, and _registry_ 
        packages.  

	      > The _::itcl_ namespace shall be the only new component 
        included in the global namespace, and shall appear only when 
        a script executes

		               package require Itcl

	      > There shall be no _::class_ command in the Core.

	      > The _::info_ command shall not provide any subcommands
        specific to [incr Tcl].

   * [incr Tcl] shall not be substantially modified under the scope
     of this TIP.

	      > The existing issues surrounding errors thrown from object
        destructors shall not be addressed.

	      > The existing use of _rename_ for object destruction shall
        not be amended.

	      > All other limitations of [incr Tcl] are initially accepted
        as they are.

	      > Of course, additional TIPs could be submitted to modify
        [incr Tcl] as desired!

   * The TCT shall assume the role of _gatekeeper_ for changes to
     the functionality of [incr Tcl].

	      > Changes that affect user-visible functionality of [incr Tcl]
        shall be made through the TIP process.

	      > Informational TIPs identifying maintainer areas and assigning
        maintainers to them shall be developed.

   * Nothing in this TIP shall be construed as identifying [incr
     Tcl] as a single preferred object system for Tcl.  If the
     community desires other systems such as OTcl, XOTcl, or ObjecTcl
     to stand on an equal footing to [incr Tcl], their champions
     can introduce TIPs similar to this one.

   * [incr Tk] and [incr widgets] are outside the scope of this TIP.

# Rationale

The lack of a standard object and data abstraction system continues to
hinder Tcl development.

  > "Lets face it, not including any sort of OO system is one of
    the major failings of Tcl. Indexing into global arrays is
    a sad hack when compared to a real OO system."
           _- Mo DeJong <[email protected]>_

Moreover, the argument that "Tcl is not object oriented" continues to
hamper Tcl marketing.  Including at least one object system with the
Tcl core, so that it is dependably available unless the user has built
from source, would address this objection.

Since an earler proposal \([[6]](6.md)\) to incorporate [incr Tcl] into the
Core failed to garner the necessary votes, at least in part because
participants were uncertain of the rationales, it seems wise to
discuss the individual points in further detail.

   * All agree that some sort of object system must be bundled with
     the core so that it is dependably available.  [incr Tcl]
     appears to be the most popular of the existing systems, as well
     as the most familiar to the current TCT, making it the most
     attractive of several candidates for this role.

   * The original [incr Tcl] developers have pointed out that
     bundling in the Core would facilitate [incr Tcl] development
     greatly.  While it is a separate loadable package, [incr Tcl]
     is intimate with the core, depending on many undocumented
     interfaces to carry out its functions.  Integrating it with the
     Core would make it easier to maintain.

   * Including a _::class_ command in the Core is not acceptable at
     this time, because it would have the effect of disenfranchising
     the users of other object systems -- who are too numerous to
     ignore.  Moreover, the ability of Tcl to serve as a test platform
     for novel object models must not be compromised.

   * Similarly, integrating [incr Tcl] closely with commands such as
     _::info_ or _::destroy_ would accord it a privileged status
     that the users of other object systems are reluctant to accept.

   * [incr Tcl] is what it is.  It would be inappropriate to demand
     that all the perceived shortcomings of the [incr Tcl] system be
     addressed prior to inclusion in the Core.  The TIP process is
     available to make further changes; the system is certainly good
     enough that many thousands of programmers use it daily.

   * If [incr Tcl] is to be included in the Core, then common sense
     requires that it be under control of the TIP process.

# Alternatives

   * Include [incr Tcl] in a "batteries included" \(BI\) distribution.

	      > Many people will not opt for the BI distribution \([[4]](4.md)\) due to its
        larger size.  It is quite likely that \(for example\) a Linux
        distribution my include Tcl as a standard component, but place the BI
        on a supplemental disk.

	      > Moreover, as mentioned above, the [incr Tcl] sources are
        already intimate with the Tcl core; there are great
        maintenance savings to be achieved by combining the source
        distributions. 

   * Integrate [incr Tcl] tightly into the Tcl Core.

	      > This alternative is unacceptable to a good many users.  A
        number of attendees at the 2001 Open Source Convention
        mentioned specifically that they use alternative object
        systems such as OTcl.  These users would be essentially
        disenfranchised if, for instance, a _::class_ command were to
        appear in the Core.

# Implementation

Jeff Hobbs has volunteered to lead the implementation effort with
the assistance of all volunteers who want to help.

# Notes

Eight members of the Tcl Core Team \(Harrison, Hobbs, Kenny, Kupries,
Lehenbauer, McLennan, Porter and Welch\) agreed orally to this proposal
at the 2001 Open Source Convention.  Since not all have had the
opportunity to read the formal written version of the proposal, that
vote shall not be considered binding.

# References

   * <http://tcltk.com//itcl>

   * [[6]](6.md)

# Copyright

This document has been placed in the public domain.


Name change from tip/51.tip to tip/51.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
136

137
138
139
140
141
142
143
144
145
146

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

163
164
165
166
167
168
169
170
171
172
173
174
175

176
177
178
179
180
181
182
183
184
185



186
187
188
189



190
191
192
193
194
195

196
197
198

199
200
201

202
203
204
205
206

207

208
TIP:            51
Title:          Native Menubutton on Macintosh
Version:	$Revision: 1.4 $
Author:         Mats Bengtsson <[email protected]>
State:          Withdrawn
Type:           Project
Tcl-Version:    8.5
Vote:           Pending
Created:        04-Aug-2001
Post-History:


~ Abstract

This is a replacement for the menubutton on the Macintosh with a
native implementation which is compliant with the Appearance Manager
in Mac OS 8 and later.

~ Rationale

The present (in 8.3.3 and earlier) menubutton on the Macintosh is
implemented using Tk drawing to draw something similar to the native
menubutton on Mac how it looks on Pre Mac OS 8.0 systems, and
therefore fails to give the correct appearance on Mac OS 8.0 systems
and later. This TIP presents a step to increase the native appearance
on the Macintosh (similar to [25].)

#image:51compare Comparison of Native (to left) and Standard Menu Buttons.

~ Reference Implementation

The proposed change is now implemented as a loadable extension (in C)
on Macintosh, and can be downloaded
[http://hem.fyristorg.com/matben/download/MacMenuButton.sit]. This
implementation differs from the other buttons in Mac Tk (button,
radiobutton, checkbutton), which use a mixture of native Apple drawing
code and Tk drawing code, since it uses only native Apple code for
drawing.  This extension requires Tcl/Tk 8.3.2p1 or later due to the
changed stub loading mechanism. The new implementation is not a
complete replacement since it lacks the ''-bitmap'' and ''-image''
options, and a few other things, see below.

The changes necessary are:

    * Replace the ''tkMacMenubutton.c'' file with the new one.

    * Add a MENU resource item, which is included in the shared library,
      but needs to be added to the core.

    * Modifications to ''tkMacFont.c'' (see appendix). Put declaration
      so it can be used from any file. Possibly also add the new
      function to the stub table since it can be practical for other
      extension writers.

    * Need to check for the presence of the Appearance manager:

|if (TkMacHaveAppearance()) 
|   use native (new) menubutton 
|else 
|   use present menubutton

All functionality from the documentation that is applicable is
implemented in the extension, with some exceptions:

    * The ''-image'' and ''-bitmap'' options are not supported, yet.
    
    * There is no button pressed (SELECTED) flag so it highlights when
      the mouse enters, just as a reminder that it must be fixed.
      (see appendix)
        
    * Don't know which color to pick for the three pixels in each
      corner.  It is now the ''-background'' color, but the ordinary
      button uses ''-highlightbackground''?
    
    * The position of the popup menu should be changed in order to
      conform better with standard Mac appearance..
    
    * Something needs to be done so that we can get Mac native font
      stuffs from a ''Tk_Font'' object; I've included a crude hack in
      the appendix.
        
    * It is compliant to the Appearance Manager which means that
      foreground and background colors are set via themes and not from
      command switches.

    * Minor differences to comply with the Appearance Manager.

All these deviations are consistent with the look-and-feel of Mac OS
8.0 and on. Existing scripts using menubutton are compatible with the
new menubutton.

Open questions: 

    * Option to use for the color of the corner pixels.

    * If (and how) a SELECTED flag should be added to
      ''tkMenuButton.h'', and code to support it in
      ''tkMenuButton.c''.

    * Implementation of the ''-bitmap'' and ''-image'' options.

    * A ''-compound'' option as described in TIP #11.

~ Copyright

This document has been placed in the public domain.

~ Appendix

    * Addition to ''tkMenuButton.h'':

|#define SELECTED		8

    > Other modifications to tkMenuButton.c must be made to support
      this flag.

    * Addition to ''tkMacFont.c'' (possibly add to exported
      functions):

|/*
| *---------------------------------------------------------------------------
| *

| * GetMacFontAttributes -- 
| *

| *      Takes a Tk_Font and gets the Mac font attributes faceNum, size, and style.
| *      Note that the Mac font size is in pixels while the Tk_Font size is
| *      in points. No need to do any UTF-8 translations since this is
| *      implicit in GetFamilyOrAliasNum().
| *      The code here is essentially a modified TkpGetFontFromAttributes() and
| *      InitFont(), both from tkMacFont.c.
| *

| * Results:
| *      Sets the Mac font attributes.
| *

| * Side effects:
| *      None.
| *

| *---------------------------------------------------------------------------
| */
|void
|GetMacFontAttributes(
|        Tk_Window tkwin,        /* Tk window. (in) */
|        Tk_Font tkFont,         /* Tk font. (in) */
|        short *faceNumPtr,      /* Mac font face id. (out) */
|        short *macSizePtr,      /* Mac font size in pixels. (out) */
|        Style *stylePtr)        /* Mac font style specifier. (out) */
|{

|    int i, j;
|    char *faceName, *fallback;
|    char ***fallbacks;
|    MacFont *fontPtr;
|    const TkFontAttributes *faPtr;
|    int size;           /* Size in points. */
|        
|    /*
|     * This is just a macro to access the attribute struct member.
|     */
|     
|    faPtr = GetFontAttributes(tkFont);
|
|    /*
|     * Algorithm to get the closest font to the one requested.
|     *

|     * try fontname
|     * try all aliases for fontname
|     * foreach fallback for fontname
|     *      try the fallback
|     *      try all aliases for the fallback
|     */
|     
|    *faceNumPtr = 0;
|    faceName = faPtr->family;
|    if (faceName != NULL) {
|        if (GetFamilyOrAliasNum(faceName, faceNumPtr) != 0) {
|            goto found;
|        }

|        fallbacks = TkFontGetFallbacks();
|        for (i = 0; fallbacks[i] != NULL; i++) {
|            for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) {
|                if (strcasecmp(faceName, fallback) == 0) {
|                    for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) {
|                        if (GetFamilyOrAliasNum(fallback, faceNumPtr)) {
|                            goto found;
|                        }
|                    }
|                }



|                break;
|            }
|        }
|    }



|    
|    found:    
|    *stylePtr = 0;
|    if (faPtr->weight != TK_FW_NORMAL) {
|        *stylePtr |= bold;
|    }

|    if (faPtr->slant != TK_FS_ROMAN) {
|        *stylePtr |= italic;
|    }

|    if (faPtr->underline) {
|        *stylePtr |= underline;
|    }

|    if (faPtr->size == 0) {
|        size = -GetDefFontSize();
|    } else {
|        size = faPtr->size;
|    }

|    *macSizePtr = (short) TkFontGetPixels(tkwin, size);

|}
<
|
<
|
|
|
|
|
|
|
>

|





|

|




|

|

|

|

|
|
|



|




|




|






|
|
|
|




|

|

|


|
|





|
















|
|
|

|

|

|



|

|

|

|


|
|

|
|
<
>
|
<
>
|
|
|
|
|
|
<
>
|
|
<
>
|
|
<
>
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
<
<
>
>
>
|
<
<
<
>
>
>
|
|
|
|
|
<
>
|
|
<
>
|
|
<
>
|
|
|
|
<
>
|
>
|

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
136
137
138
139
140
141
142
143
144

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

161
162
163
164
165
166
167
168
169
170
171
172
173

174
175
176
177
178
179
180
181



182
183
184
185



186
187
188
189
190
191
192
193

194
195
196

197
198
199

200
201
202
203
204

205
206
207
208

# TIP 51: Native Menubutton on Macintosh

	Author:         Mats Bengtsson <[email protected]>
	State:          Withdrawn
	Type:           Project
	Tcl-Version:    8.5
	Vote:           Pending
	Created:        04-Aug-2001
	Post-History:
-----

# Abstract

This is a replacement for the menubutton on the Macintosh with a
native implementation which is compliant with the Appearance Manager
in Mac OS 8 and later.

# Rationale

The present \(in 8.3.3 and earlier\) menubutton on the Macintosh is
implemented using Tk drawing to draw something similar to the native
menubutton on Mac how it looks on Pre Mac OS 8.0 systems, and
therefore fails to give the correct appearance on Mac OS 8.0 systems
and later. This TIP presents a step to increase the native appearance
on the Macintosh \(similar to [[25]](25.md).\)

![Comparison of Native (to left) and Standard Menu Buttons.](../assets/51compare.gif)

# Reference Implementation

The proposed change is now implemented as a loadable extension \(in C\)
on Macintosh, and can be downloaded
<http://hem.fyristorg.com/matben/download/MacMenuButton.sit> . This
implementation differs from the other buttons in Mac Tk \(button,
radiobutton, checkbutton\), which use a mixture of native Apple drawing
code and Tk drawing code, since it uses only native Apple code for
drawing.  This extension requires Tcl/Tk 8.3.2p1 or later due to the
changed stub loading mechanism. The new implementation is not a
complete replacement since it lacks the _-bitmap_ and _-image_
options, and a few other things, see below.

The changes necessary are:

    * Replace the _tkMacMenubutton.c_ file with the new one.

    * Add a MENU resource item, which is included in the shared library,
      but needs to be added to the core.

    * Modifications to _tkMacFont.c_ \(see appendix\). Put declaration
      so it can be used from any file. Possibly also add the new
      function to the stub table since it can be practical for other
      extension writers.

    * Need to check for the presence of the Appearance manager:

		if (TkMacHaveAppearance()) 
		   use native (new) menubutton 
		else 
		   use present menubutton

All functionality from the documentation that is applicable is
implemented in the extension, with some exceptions:

    * The _-image_ and _-bitmap_ options are not supported, yet.
    
    * There is no button pressed \(SELECTED\) flag so it highlights when
      the mouse enters, just as a reminder that it must be fixed.
      \(see appendix\)
        
    * Don't know which color to pick for the three pixels in each
      corner.  It is now the _-background_ color, but the ordinary
      button uses _-highlightbackground_?
    
    * The position of the popup menu should be changed in order to
      conform better with standard Mac appearance..
    
    * Something needs to be done so that we can get Mac native font
      stuffs from a _Tk\_Font_ object; I've included a crude hack in
      the appendix.
        
    * It is compliant to the Appearance Manager which means that
      foreground and background colors are set via themes and not from
      command switches.

    * Minor differences to comply with the Appearance Manager.

All these deviations are consistent with the look-and-feel of Mac OS
8.0 and on. Existing scripts using menubutton are compatible with the
new menubutton.

Open questions: 

    * Option to use for the color of the corner pixels.

    * If \(and how\) a SELECTED flag should be added to
      _tkMenuButton.h_, and code to support it in
      _tkMenuButton.c_.

    * Implementation of the _-bitmap_ and _-image_ options.

    * A _-compound_ option as described in TIP \#11.

# Copyright

This document has been placed in the public domain.

# Appendix

    * Addition to _tkMenuButton.h_:

		#define SELECTED		8

	    > Other modifications to tkMenuButton.c must be made to support
      this flag.

    * Addition to _tkMacFont.c_ \(possibly add to exported
      functions\):

		/*
		 *---------------------------------------------------------------------------

		 *
		 * GetMacFontAttributes -- 

		 *
		 *      Takes a Tk_Font and gets the Mac font attributes faceNum, size, and style.
		 *      Note that the Mac font size is in pixels while the Tk_Font size is
		 *      in points. No need to do any UTF-8 translations since this is
		 *      implicit in GetFamilyOrAliasNum().
		 *      The code here is essentially a modified TkpGetFontFromAttributes() and
		 *      InitFont(), both from tkMacFont.c.

		 *
		 * Results:
		 *      Sets the Mac font attributes.

		 *
		 * Side effects:
		 *      None.

		 *
		 *---------------------------------------------------------------------------
		 */
		void
		GetMacFontAttributes(
		        Tk_Window tkwin,        /* Tk window. (in) */
		        Tk_Font tkFont,         /* Tk font. (in) */
		        short *faceNumPtr,      /* Mac font face id. (out) */
		        short *macSizePtr,      /* Mac font size in pixels. (out) */
		        Style *stylePtr)        /* Mac font style specifier. (out) */

		{
		    int i, j;
		    char *faceName, *fallback;
		    char ***fallbacks;
		    MacFont *fontPtr;
		    const TkFontAttributes *faPtr;
		    int size;           /* Size in points. */
		        
		    /*
		     * This is just a macro to access the attribute struct member.
		     */
		     
		    faPtr = GetFontAttributes(tkFont);
		
		    /*
		     * Algorithm to get the closest font to the one requested.

		     *
		     * try fontname
		     * try all aliases for fontname
		     * foreach fallback for fontname
		     *      try the fallback
		     *      try all aliases for the fallback
		     */
		     
		    *faceNumPtr = 0;
		    faceName = faPtr->family;
		    if (faceName != NULL) {
		        if (GetFamilyOrAliasNum(faceName, faceNumPtr) != 0) {
		            goto found;

		        }
		        fallbacks = TkFontGetFallbacks();
		        for (i = 0; fallbacks[i] != NULL; i++) {
		            for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) {
		                if (strcasecmp(faceName, fallback) == 0) {
		                    for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) {
		                        if (GetFamilyOrAliasNum(fallback, faceNumPtr)) {
		                            goto found;



		                        }
		                    }
		                }
		                break;



		            }
		        }
		    }
		    
		    found:    
		    *stylePtr = 0;
		    if (faPtr->weight != TK_FW_NORMAL) {
		        *stylePtr |= bold;

		    }
		    if (faPtr->slant != TK_FS_ROMAN) {
		        *stylePtr |= italic;

		    }
		    if (faPtr->underline) {
		        *stylePtr |= underline;

		    }
		    if (faPtr->size == 0) {
		        size = -GetDefFontSize();
		    } else {
		        size = faPtr->size;

		    }
		    *macSizePtr = (short) TkFontGetPixels(tkwin, size);
		}

Name change from tip/52.tip to tip/52.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

TIP:            52
Title:          Hierarchical Namespace Lookup of Commands and Variables
Version:        $Revision: 1.6 $
Author:         David Cuthbert <[email protected]>
Author:         Andreas Kupries <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        09-Aug-2001
Post-History:   
Discussions-To: news:comp.lang.tcl
Keywords:       namespace,lookup,hierarchy
Tcl-Version:    8.5


~ Abstract

This TIP proposes to change the command and variable namespace lookup
system so that the full hierarchy of namespaces is parsed, rather than
just the current namespace followed by the global namespace.  This is
primarily intended to rectify problems often encountered with the use
of [[incr Tcl]] (ITcl) and namespaces.  In addition, package
encapsulation can be enhanced with judicious application of this
feature.

~ Rationale

Currently, the following code is invalid in Tcl/ITcl:

|package require Itcl
|
|namespace eval SampleNS {
|    proc Hello {} { puts "Hello world!" }
|
|    ::itcl::class X {
|        public constructor {} {} { Hello }
|    }
|}


|
|SampleNS::X x1  ;# Error: invalid command name "Hello"

This is due to the fact that ITcl classes double as namespaces.
Therefore, the lookup of ''Hello'' takes place first in
''::SampleNS::X'', followed by ''::'' (the global namespace).

The current workaround - to reopen the class' namespace and issue a
''namespace import'' directive - is of limited value since ''namespace
import'' is not capable of bringing in names defined later on.  The
following code illustrates this point:

|package require Itcl
|
|namespace eval SampleNS {
|    ::itcl::class X1 {
|        public method GetSibling {} { return [X2 \#auto] }
|    }

|    namespace eval X1 { namespace import ::SampleNS }
|
|    # Further down, or perhaps in a separate file source later:
|
|    ::itcl::class X2 { }
|}

|
|set x [SampleNS::X1 \#auto]
|$x GetSibling ;# Error: invalid command name "X2"

Non-ITcl code can also make use of hierarchical namespaces to better
encapsulate support procedures.  In this example, the child namespace
''private'' illustrates that the ''GetUniqueId'' procedure should not
be used outside of the package; however, ''GetUniqueId'' still has
access to the procedures and variables in the package's main
namespace:

|# MyPackage
|
|namespace eval MyPackage {
|    variable nextId 0
|
|    namespace eval private {
|        proc GetUniqueId {} {
|            variable nextId
|            return "MyPackage.[incr nextId]"
|        }
|    }


|
|    proc CreateObject {} {
|        set name ::[private::GetUniqueId]
|        proc $name args { body }
|        return $name
|    }
|}



~ Specification

Currently, the ''NAME RESOLUTION'' section of the ''namespace''
documentation states:

 > If the name does not start with a :: (i.e., is ''relative''), Tcl
   follows a fixed rule for looking it up: Command and variable names
   are always resolved by looking first in the current namespace, and
   then in the global namespace.  Namespace names, on the other hand,
   are always resolved by looking in only the current namespace.

The proposed change to this is as follows:

 > If the name does not start with a :: (i.e., is ''relative''), Tcl
   follows a fixed rule for looking it up: Command and variable names
   are always resolved by traversing the namespace hierarchy - that
   is, the current namespace is examined first, followed by the
   parent, the parent's parent, and so on, until (finally) the global
   namespace is examined.  Namespace names, on the other hand, are
   always resolved by looking in only the current namespace.

By keeping the current behaviour for namespace names, this TIP affects
only completely unqualified commands and variables (i.e. those that do
not contain ::).  Changing the behaviour of partially qualified names
(those that are relative ''and'' contain ::) is often unintuitive and
can lead to unexpected errors.

~ Consequences

 1. ITcl classes and child namespaces can refer to command and
    variable names in their parent hierarchy without requiring the
    names to be fully qualified.  This improves the intuitiveness and
    readability of Tcl code.  In addition, it can reduce the
    brittleness of the code should parent namespace names undergo a
    change (e.g., ''namespace eval scriptics.com'' to ''namespace eval
    ajubasolutions.com'').

 2. Currently well-defined behaviour is modified.  This can break
    existing code if the following conditions are met:

 > * The code employs the use of namespaces with a depth greater than
     one below the global namespace.

 > * The code creates a variable or procedure in a parent namespace
     with the same name as a variable or procedure in the global
     namespace.

 > * The code in the child namespace uses unscoped names to refer to
     commands and/or variables in the global namespace.

 > A cursory examination of existing Tcl code available on the
   Internet revealed no code which used deeply nested namespaces.

 3. Existing well-defined behaviour of the internal Tcl function
    ''TclGetNamespaceForQualName'' is modified.  Under the sample
    implementation, the ''altNsPtrPtr'' parameter (which currently
    returns a pointer to the global namespace if a name was found
    there) always returns NULL.  It is up to the calling functions
    (e.g., Tcl_FindCommand and Tcl_FindNamespaceVar) to traverse the
    hierarchy.  Although the Tcl and Tk code-base can be modified to
    accommodate this, extensions which depend on this internal
    function may be broken.

~ Namespace History

Namespaces were originally developed by Michael McLennan for ITcl, and
apparently had this hierarchical resolution feature.  When they were
adopted into Tcl, an optimisation was made which led to the current
behaviour.

This TIP argues for the reversal of this decision based on experiences
with the new behaviour.

~ See Also

 * Tcl manual page ''namespace''.

 * Tcl source code file ''tcl8.4a3/generic/tclNamesp.c''.

 * Sample implementation at http://www.kanga.org/tclnamespace/

~ Comments

 * Andreas Kupries:

 > Related information: SF entry [[ #218101 ]] "no man page for library procedures Tcl_AddInterpResolver Tcl" [http://sourceforge.net/tracker/?func=detail&aid=218101&group_id=10894&atid=110894]

 > Not addressed in this TIP: Impact on speed of the interpreter.
(Seeking out mail on Tcl core where author of talks about this)

~ Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > Insufficiently subtle.  52 will break any code that assumes the
   current behaviour (and you can bet someone will have that
   assumption) and 142 doesn't let two namespaces have different
   search paths (unless the variable is always interpreted locally,
   which just creates bizarre variable name magic.)


~ Copyright

Copyright � 2001 by David Cuthbert.  Distribution in whole or part,
with or without annotations, is unlimited.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|





|



|



|
|
|
|
|
|
|
<
<
>
>
|
|


|
|


|
|


|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|



|
|



|
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
<
<
|
>
>
|

|


|







|



|




|
|
|


|






|
|




|


|



|


|



|
|

|
|




|









|

|

|

|

|



|

|
|

|






|
|
|
|


|

|

>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

# TIP 52: Hierarchical Namespace Lookup of Commands and Variables

	Author:         David Cuthbert <[email protected]>
	Author:         Andreas Kupries <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        09-Aug-2001
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Keywords:       namespace,lookup,hierarchy
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to change the command and variable namespace lookup
system so that the full hierarchy of namespaces is parsed, rather than
just the current namespace followed by the global namespace.  This is
primarily intended to rectify problems often encountered with the use
of [incr Tcl] \(ITcl\) and namespaces.  In addition, package
encapsulation can be enhanced with judicious application of this
feature.

# Rationale

Currently, the following code is invalid in Tcl/ITcl:

	package require Itcl
	
	namespace eval SampleNS {
	    proc Hello {} { puts "Hello world!" }
	
	    ::itcl::class X {
	        public constructor {} {} { Hello }


	    }
	}
	
	SampleNS::X x1  ;# Error: invalid command name "Hello"

This is due to the fact that ITcl classes double as namespaces.
Therefore, the lookup of _Hello_ takes place first in
_::SampleNS::X_, followed by _::_ \(the global namespace\).

The current workaround - to reopen the class' namespace and issue a
_namespace import_ directive - is of limited value since _namespace
import_ is not capable of bringing in names defined later on.  The
following code illustrates this point:

	package require Itcl
	
	namespace eval SampleNS {
	    ::itcl::class X1 {
	        public method GetSibling {} { return [X2 \#auto] }

	    }
	    namespace eval X1 { namespace import ::SampleNS }
	
	    # Further down, or perhaps in a separate file source later:
	
	    ::itcl::class X2 { }

	}
	
	set x [SampleNS::X1 \#auto]
	$x GetSibling ;# Error: invalid command name "X2"

Non-ITcl code can also make use of hierarchical namespaces to better
encapsulate support procedures.  In this example, the child namespace
_private_ illustrates that the _GetUniqueId_ procedure should not
be used outside of the package; however, _GetUniqueId_ still has
access to the procedures and variables in the package's main
namespace:

	# MyPackage
	
	namespace eval MyPackage {
	    variable nextId 0
	
	    namespace eval private {
	        proc GetUniqueId {} {
	            variable nextId
	            return "MyPackage.[incr nextId]"


	        }
	    }
	
	    proc CreateObject {} {
	        set name ::[private::GetUniqueId]
	        proc $name args { body }
	        return $name


	    }
	}

# Specification

Currently, the _NAME RESOLUTION_ section of the _namespace_
documentation states:

 > If the name does not start with a :: \(i.e., is _relative_\), Tcl
   follows a fixed rule for looking it up: Command and variable names
   are always resolved by looking first in the current namespace, and
   then in the global namespace.  Namespace names, on the other hand,
   are always resolved by looking in only the current namespace.

The proposed change to this is as follows:

 > If the name does not start with a :: \(i.e., is _relative_\), Tcl
   follows a fixed rule for looking it up: Command and variable names
   are always resolved by traversing the namespace hierarchy - that
   is, the current namespace is examined first, followed by the
   parent, the parent's parent, and so on, until \(finally\) the global
   namespace is examined.  Namespace names, on the other hand, are
   always resolved by looking in only the current namespace.

By keeping the current behaviour for namespace names, this TIP affects
only completely unqualified commands and variables \(i.e. those that do
not contain ::\).  Changing the behaviour of partially qualified names
\(those that are relative _and_ contain ::\) is often unintuitive and
can lead to unexpected errors.

# Consequences

 1. ITcl classes and child namespaces can refer to command and
    variable names in their parent hierarchy without requiring the
    names to be fully qualified.  This improves the intuitiveness and
    readability of Tcl code.  In addition, it can reduce the
    brittleness of the code should parent namespace names undergo a
    change \(e.g., _namespace eval scriptics.com_ to _namespace eval
    ajubasolutions.com_\).

 2. Currently well-defined behaviour is modified.  This can break
    existing code if the following conditions are met:

	 > \* The code employs the use of namespaces with a depth greater than
     one below the global namespace.

	 > \* The code creates a variable or procedure in a parent namespace
     with the same name as a variable or procedure in the global
     namespace.

	 > \* The code in the child namespace uses unscoped names to refer to
     commands and/or variables in the global namespace.

	 > A cursory examination of existing Tcl code available on the
   Internet revealed no code which used deeply nested namespaces.

 3. Existing well-defined behaviour of the internal Tcl function
    _TclGetNamespaceForQualName_ is modified.  Under the sample
    implementation, the _altNsPtrPtr_ parameter \(which currently
    returns a pointer to the global namespace if a name was found
    there\) always returns NULL.  It is up to the calling functions
    \(e.g., Tcl\_FindCommand and Tcl\_FindNamespaceVar\) to traverse the
    hierarchy.  Although the Tcl and Tk code-base can be modified to
    accommodate this, extensions which depend on this internal
    function may be broken.

# Namespace History

Namespaces were originally developed by Michael McLennan for ITcl, and
apparently had this hierarchical resolution feature.  When they were
adopted into Tcl, an optimisation was made which led to the current
behaviour.

This TIP argues for the reversal of this decision based on experiences
with the new behaviour.

# See Also

 * Tcl manual page _namespace_.

 * Tcl source code file _tcl8.4a3/generic/tclNamesp.c_.

 * Sample implementation at <http://www.kanga.org/tclnamespace/>

# Comments

 * Andreas Kupries:

	 > Related information: SF entry [ #218101 ] "no man page for library procedures Tcl\_AddInterpResolver Tcl" <http://sourceforge.net/tracker/?func=detail&aid=218101&group_id=10894&atid=110894> 

	 > Not addressed in this TIP: Impact on speed of the interpreter.
\(Seeking out mail on Tcl core where author of talks about this\)

# Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > Insufficiently subtle.  52 will break any code that assumes the
   current behaviour \(and you can bet someone will have that
   assumption\) and 142 doesn't let two namespaces have different
   search paths \(unless the variable is always interpreted locally,
   which just creates bizarre variable name magic.\)


# Copyright

Copyright © 2001 by David Cuthbert.  Distribution in whole or part,
with or without annotations, is unlimited.

Name change from tip/53.tip to tip/53.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

TIP:            53
Title:          Addition of 'assert' Command
Version:        $Revision: 1.4 $
Author:         Gerald W. Lester <[email protected]>
Author:         Kevin Kenny <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        14-Aug-2001
Post-History:   
Keywords:       bytecode,compiler
Tcl-Version:    8.4


~ Abstract

This TIP proposes the addition of an ''assert'' command and supporting
infrastructure to the Tcl core.

~ Rationale

Many languages, including other scripting languages, have assertion
checking features that can be used to assist in validating program
correctness.  Typically, these assertion checking features can be
"compiled out" of production systems so as not to impact performance. 
To have a similar effect in Tcl, the assertion checking features must
be implemented at the byte code compiler level.

If, doing byte code compilation, an assert command is encountered the
byte code stream generated will be dependent on the value of the
''assert_enabled'' command line option.  If the option is true, a byte
code stream will be emitted to implement the assert command.  If the
option is not true, no byte code will be emitted.

Similarly, if the interpreter encounters an ''assert'' command (either
compiled or uncompiled), it will only execute it if the
''assert_enabled'' command line option is true.

It is acceptable for the compiler to throw an error if the
''booleanExpression'' is not brace quoted.

~ Tcl-Level Specification

The manual entry for the ''assert'' command is included here:

----

~NAME

 > assert - Assert a run time validation condition

~SYNOPSIS

|   assert booleanExpression messageText

~DESCRIPTION

 > This command has no effect if the assert_enabled command line
   option is not true at both compile and run time.  If the
   ''assert_enabled'' command line option is true at both compile and
   run time, the following behavior will occur:

 > 1. The ''booleanExpression'' will be evaluated

 > 2. If the ''booleanExpression'' evaluates to a true value,
      ''assert::failed'' will be called at the global level with
      ''messageText'' as its one and only parameter.

 > The default implementation of ''assert::failed'' will write
   ''messageText'' to standard out and ''exit'' with a status code of
   1.

----

~ Remarks

This TIP has been withdrawn because of other changes, both inside and
outside the Tcl core.

 1. The bytecode compiler (8.4a4) contains code that recognizes a
    no-op procedure of the form ''proc no-op args {}'' and generates
    no bytecode if such a procedure is called with arguments that have
    no side effects.

 2. The ''control'' package within tcllib implements a
    ''::control::assert'' procedure that provides all the requested
    functionality.

These two, taken together, provide an implementation of the requested
functionality that is acceptable to the original author of this TIP.

~ Copyright

This TIP is in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|










|



|
|
|


|

|

|



|



|

|

|

|

|


|

|
|
|

|
|




|




|
|



|
|





|


>

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

# TIP 53: Addition of 'assert' Command

	Author:         Gerald W. Lester <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        14-Aug-2001
	Post-History:   
	Keywords:       bytecode,compiler
	Tcl-Version:    8.4
-----

# Abstract

This TIP proposes the addition of an _assert_ command and supporting
infrastructure to the Tcl core.

# Rationale

Many languages, including other scripting languages, have assertion
checking features that can be used to assist in validating program
correctness.  Typically, these assertion checking features can be
"compiled out" of production systems so as not to impact performance. 
To have a similar effect in Tcl, the assertion checking features must
be implemented at the byte code compiler level.

If, doing byte code compilation, an assert command is encountered the
byte code stream generated will be dependent on the value of the
_assert\_enabled_ command line option.  If the option is true, a byte
code stream will be emitted to implement the assert command.  If the
option is not true, no byte code will be emitted.

Similarly, if the interpreter encounters an _assert_ command \(either
compiled or uncompiled\), it will only execute it if the
_assert\_enabled_ command line option is true.

It is acceptable for the compiler to throw an error if the
_booleanExpression_ is not brace quoted.

# Tcl-Level Specification

The manual entry for the _assert_ command is included here:

----

# NAME

 > assert - Assert a run time validation condition

# SYNOPSIS

	   assert booleanExpression messageText

# DESCRIPTION

 > This command has no effect if the assert\_enabled command line
   option is not true at both compile and run time.  If the
   _assert\_enabled_ command line option is true at both compile and
   run time, the following behavior will occur:

 > 1. The _booleanExpression_ will be evaluated

 > 2. If the _booleanExpression_ evaluates to a true value,
      _assert::failed_ will be called at the global level with
      _messageText_ as its one and only parameter.

 > The default implementation of _assert::failed_ will write
   _messageText_ to standard out and _exit_ with a status code of
   1.

----

# Remarks

This TIP has been withdrawn because of other changes, both inside and
outside the Tcl core.

 1. The bytecode compiler \(8.4a4\) contains code that recognizes a
    no-op procedure of the form _proc no-op args \{\}_ and generates
    no bytecode if such a procedure is called with arguments that have
    no side effects.

 2. The _control_ package within tcllib implements a
    _::control::assert_ procedure that provides all the requested
    functionality.

These two, taken together, provide an implementation of the requested
functionality that is acceptable to the original author of this TIP.

# Copyright

This TIP is in the public domain.

Name change from tip/54.tip to tip/54.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

TIP:            54
Title:          Using PURLs to Unite the Tcl Webspace
Version:        $Revision: 1.8 $
Author:         Andreas Kupries <[email protected]>
Author:         Jeff Hobbs <[email protected]>
State:          Withdrawn
Type:           Process
Vote:           Pending
Created:        16-Aug-2001
Post-History:   


~ Abstract

This TIP proposes the use of PURLs to unify the scattered landscape of
Tcl URLs into a coherent set of information about the language, the
community, extensions, etc.

~ Background & Rationale

One of the recurring themes in the community in general (and
news:comp.lang.tcl in particular) is the lack of central website
people can turn to for an introduction to the language, the community,
search for extensions and packages, et cetera.

Most of the solutions proposed so far have the distinctive
disadvantage of not being able to use the existing sites and bind them
into a whole. This is further aggravated by the fact that the
'natural' domain names, like for example http://www.tcl.com/ and
http://www.tcl.org are already taken by other entities, commercial and
not, and thus not available anymore.  We do have control of the http://www.tcl-tk.net/ domain, provided by David Welton.

Instead of giving up at this point I propose to use PURLs a.k.a.
''Persistent URLs'' to construct a virtual website (the ''Tcl space'')
out of all the existing independent efforts. See http://www.purl.org/
for more explanations of PURLs.

Note that PURLs not only can refer to single URLs but to entire
sites. The latter is done through a technique called 'partial
redirection'. This ... is emphasized here because partially redirected
PURL have to be used with a trailing slash whereas PURLs referring to
single URL must not have a trailing slash.

In the lists below partially redirected PURLs are indicated by a
trailing slash.

A restriction we face is that PURLs are case insensitive. This means
that the names we will have to come up with have to be unique even
with case removed.

One of the most important features is the persistency. In real life
however organizations, people, websites, etc. can disappear. According
to http://www.purl.org/OCLC/PURL/FAQ#toc3.14 the PURL stays in
existence but can be redirected to a page detailing the history of the
purl. This would include the decommission. We could also do our own
scheme and redirect the purl to a page explaining the history in a
more Tcl-specific manner (like: Company went out of business, was
acquired, etc.).

~ Specification

This TIP is driven by several conflicting needs:

   * The names will be persistent, so give them some thought before
     creating them; they cannot be undone. This also implies that we
     to set up a simple and minimal structure first so as not to block
     future enhancements and flexibility.

   * Define the structure now before the URN space gets as scattered
     as the URL space is. Note that this process has already
     begun. The PURL resolver at http://www.purl.org/ currently has
     registered 24 Tcl-related PURLs which are not bound together in
     the framework proposed here. Action is necessary to prevent
     further confusion.

Of the existing PURLs the PURL domain ''/tcl'' created by Don Libes is
the most promising one for the unification of the Tcl space. Six of
the 24 aforementioned PURLs are defined below this domain too,
providing a (good) framework on which to build.

The existing PURLs and sub-domains in the ''/tcl'' domain are:

   * ''expect''	- reference to the homepage of the expect extension

   * ''faq''	- reference to the main FAQ

   * ''faqs''	- introduction to the available FAQ documents.

   * ''home/''	- refers to the Tcl Developers Xchange

   * ''tip/''	- refers to the TIP archives

   * ''wiki''	- refers to the entry page of the Tcl'ers WIKI

With the exception of ''expect'' all of these are general classes
and/or refer to important sites. They are used as is, except for
''expect'' which has to be redirected into the proposed sub-domain
''package''.

The following new sub-domains covering the most important general
classes of information and/or websites are proposed here. Please note
that the examples used in the list below are using purely informal
everyday names to refer to entities in the proposed domain. These
examples should not be seen as suggestions for the concrete naming
scheme used by the domain.

   * ''announce'' - Direct reference to a page explaining how to
     announce packages, applications and other tcl-related news and
     linking to the relevant newsgroups, mail archives and submission
     addresses. This includes, but is not restricted to:

   > * A link to the newsgroup ''comp.lang.tcl.announce''.

   > * A link to the eGroups/Yahoo archive of the c.l.t.a newsgroup.

   > * The submission address of c.l.t.a. to directly submit via email
       announcements.

   * ''newsletter'' - Direct reference to an archive of ''Tcl-URL!''.

   * ''package/'' - Sub-domain to contain references to the homepages
     of the known packages. This TIP makes no distinction between
     C-level extensions and script libraries. From the point of view
     of the core these are all packages to be required.

   > Examples of packages are ''Expect'', ''tcllib'', etc.

   * ''application/'' - Sub-domain to contain references to the
     homepages of applications related to Tcl, written in Tcl or using
     it internally.

   > Examples of applications are ''frink'', ''tclHttpd'',
     ''AOLServer'', etc.

   * ''person/'' - Sub-domain to contain references to the homepages of
     people active in the community, as far as they are interested in
     such a reference. References in this domain shall be personal and
     not organization-related. The latter will go into their own
     domain.

   > Examples of people are ''Larry Virden'', ''Cameron Laird'', etc.

   * ''org/'' - Sub-domain to contain references to organizations
     important to the Tcl community.

   > Examples are the Tcl Core Team, the Tcl Core Maintainers,
     Tcl-based based companies (PhaseIt, ActiveState), companies and
     organizations using Tcl (NIST, CAS), etc.

~ Management

The ''/tcl'' domain was created by Don Libes which made him
automatically the maintainer of the domain
[http://www.purl.org/maint/search_user.pl.cgi?userid=^LIBES$]. He has
already extended the maintainership to the entity TCLGROUP
[http://www.purl.org/maint/search_group.pl.cgi?groupid=^TCLGROUP$],
currently consisting of

   * Gordon Johnstone <[email protected]>

   * Jeffrey Hobbs <[email protected]>

   * Don Libes <[email protected]>

   * Andreas Kupries <[email protected]>

   * Larry Virden <[email protected]>

   * Don G. Porter <[email protected]>

   * Jean-Claude Wippler <[email protected]>

For the future I propose that

   * High-level changes to the Tcl space, like new sub-domains, have to
     go through the TCT and the TIP process for approval. This is also
     in line with [0] declaring the responsibility of the TCT for the
     Tcl webspace.

   * The day-to-day routine of adding new packages, persons,
     organizations, etc. is delegated to a new group, the ''Tcl
     Namespace Maintainers''.

   > Initially this group would consist of the people mentioned above,
     with membership open to volunteers from the community.

~ Discussion

   * All of the newly proposed sub-domains will be simple listings
     mapping from the names of the entities contained in them to the
     proper locations. Further categorization of the entities by
     topic, gender or other attributes is out of the scope of this
     TIP. This type of categorization rather is in the domain of
     general and specialized catalogs which can be set up later and
     then bound into the unified webspace proposed here.

   > Note that such catalogs can and should make use of the proposed
     domains to reduce the effort necessary by them to stay current
     with respect to the location of the referenced entities (people,
     packages, etc).

   * The first pre-draft of this TIP contained definitions for the
     names to use in the various domains. These definitions have been
     removed on the grounds that their format and other issues like
     resolution of naming conflicts, order of precedence, etc. are
     best handled in one or more separate documents. The role of this
     TIP is to lay down a framework within which the community can
     operate and not to fill in every conceivable detail.

   > These details can be discussed and decided upon by the group of
     maintainers proposed in the last section.

   * This proposal makes the Tcl community dependent on an external
     entity, namely the maintainers of http://www.purl.org/. This is
     considered acceptable.

~ Example

The following examples show how to use PURLs, using some of the
already existing ones:

    * http://www.purl.org/tcl/tip/ refers to the TIP archive.

    * http://www.purl.org/tcl/wiki/ refers to the Tcl'ers Wiki.

~ Copyright

This document is in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|





|

|
|






|
|
|


|
|

















|



|
|

|










|




|


|

|

|

|

|

|

|

|

|

|
|








|




|

|

|


|

|




|

|



|
|

|





|

|


|
|
|

|

|

|

|








|











|



|
|

|


|









|

|
|









|



|


|




|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

# TIP 54: Using PURLs to Unite the Tcl Webspace

	Author:         Andreas Kupries <[email protected]>
	Author:         Jeff Hobbs <[email protected]>
	State:          Withdrawn
	Type:           Process
	Vote:           Pending
	Created:        16-Aug-2001
	Post-History:   
-----

# Abstract

This TIP proposes the use of PURLs to unify the scattered landscape of
Tcl URLs into a coherent set of information about the language, the
community, extensions, etc.

# Background & Rationale

One of the recurring themes in the community in general \(and
news:comp.lang.tcl in particular\) is the lack of central website
people can turn to for an introduction to the language, the community,
search for extensions and packages, et cetera.

Most of the solutions proposed so far have the distinctive
disadvantage of not being able to use the existing sites and bind them
into a whole. This is further aggravated by the fact that the
'natural' domain names, like for example <http://www.tcl.com/> and
<http://www.tcl.org> are already taken by other entities, commercial and
not, and thus not available anymore.  We do have control of the <http://www.tcl-tk.net/> domain, provided by David Welton.

Instead of giving up at this point I propose to use PURLs a.k.a.
_Persistent URLs_ to construct a virtual website \(the _Tcl space_\)
out of all the existing independent efforts. See <http://www.purl.org/>
for more explanations of PURLs.

Note that PURLs not only can refer to single URLs but to entire
sites. The latter is done through a technique called 'partial
redirection'. This ... is emphasized here because partially redirected
PURL have to be used with a trailing slash whereas PURLs referring to
single URL must not have a trailing slash.

In the lists below partially redirected PURLs are indicated by a
trailing slash.

A restriction we face is that PURLs are case insensitive. This means
that the names we will have to come up with have to be unique even
with case removed.

One of the most important features is the persistency. In real life
however organizations, people, websites, etc. can disappear. According
to <http://www.purl.org/OCLC/PURL/FAQ\#toc3.14> the PURL stays in
existence but can be redirected to a page detailing the history of the
purl. This would include the decommission. We could also do our own
scheme and redirect the purl to a page explaining the history in a
more Tcl-specific manner \(like: Company went out of business, was
acquired, etc.\).

# Specification

This TIP is driven by several conflicting needs:

   * The names will be persistent, so give them some thought before
     creating them; they cannot be undone. This also implies that we
     to set up a simple and minimal structure first so as not to block
     future enhancements and flexibility.

   * Define the structure now before the URN space gets as scattered
     as the URL space is. Note that this process has already
     begun. The PURL resolver at <http://www.purl.org/> currently has
     registered 24 Tcl-related PURLs which are not bound together in
     the framework proposed here. Action is necessary to prevent
     further confusion.

Of the existing PURLs the PURL domain _/tcl_ created by Don Libes is
the most promising one for the unification of the Tcl space. Six of
the 24 aforementioned PURLs are defined below this domain too,
providing a \(good\) framework on which to build.

The existing PURLs and sub-domains in the _/tcl_ domain are:

   * _expect_	- reference to the homepage of the expect extension

   * _faq_	- reference to the main FAQ

   * _faqs_	- introduction to the available FAQ documents.

   * _home/_	- refers to the Tcl Developers Xchange

   * _tip/_	- refers to the TIP archives

   * _wiki_	- refers to the entry page of the Tcl'ers WIKI

With the exception of _expect_ all of these are general classes
and/or refer to important sites. They are used as is, except for
_expect_ which has to be redirected into the proposed sub-domain
_package_.

The following new sub-domains covering the most important general
classes of information and/or websites are proposed here. Please note
that the examples used in the list below are using purely informal
everyday names to refer to entities in the proposed domain. These
examples should not be seen as suggestions for the concrete naming
scheme used by the domain.

   * _announce_ - Direct reference to a page explaining how to
     announce packages, applications and other tcl-related news and
     linking to the relevant newsgroups, mail archives and submission
     addresses. This includes, but is not restricted to:

	   > \* A link to the newsgroup _comp.lang.tcl.announce_.

	   > \* A link to the eGroups/Yahoo archive of the c.l.t.a newsgroup.

	   > \* The submission address of c.l.t.a. to directly submit via email
       announcements.

   * _newsletter_ - Direct reference to an archive of _Tcl-URL!_.

   * _package/_ - Sub-domain to contain references to the homepages
     of the known packages. This TIP makes no distinction between
     C-level extensions and script libraries. From the point of view
     of the core these are all packages to be required.

	   > Examples of packages are _Expect_, _tcllib_, etc.

   * _application/_ - Sub-domain to contain references to the
     homepages of applications related to Tcl, written in Tcl or using
     it internally.

	   > Examples of applications are _frink_, _tclHttpd_,
     _AOLServer_, etc.

   * _person/_ - Sub-domain to contain references to the homepages of
     people active in the community, as far as they are interested in
     such a reference. References in this domain shall be personal and
     not organization-related. The latter will go into their own
     domain.

	   > Examples of people are _Larry Virden_, _Cameron Laird_, etc.

   * _org/_ - Sub-domain to contain references to organizations
     important to the Tcl community.

	   > Examples are the Tcl Core Team, the Tcl Core Maintainers,
     Tcl-based based companies \(PhaseIt, ActiveState\), companies and
     organizations using Tcl \(NIST, CAS\), etc.

# Management

The _/tcl_ domain was created by Don Libes which made him
automatically the maintainer of the domain
<http://www.purl.org/maint/search_user.pl.cgi?userid=^LIBES$> . He has
already extended the maintainership to the entity TCLGROUP
<http://www.purl.org/maint/search_group.pl.cgi?groupid=^TCLGROUP$> ,
currently consisting of

   * Gordon Johnstone <[email protected]>

   * Jeffrey Hobbs <[email protected]>

   * Don Libes <[email protected]>

   * Andreas Kupries <andreas\[email protected]>

   * Larry Virden <[email protected]>

   * Don G. Porter <[email protected]>

   * Jean-Claude Wippler <[email protected]>

For the future I propose that

   * High-level changes to the Tcl space, like new sub-domains, have to
     go through the TCT and the TIP process for approval. This is also
     in line with [[0]](0.md) declaring the responsibility of the TCT for the
     Tcl webspace.

   * The day-to-day routine of adding new packages, persons,
     organizations, etc. is delegated to a new group, the _Tcl
     Namespace Maintainers_.

	   > Initially this group would consist of the people mentioned above,
     with membership open to volunteers from the community.

# Discussion

   * All of the newly proposed sub-domains will be simple listings
     mapping from the names of the entities contained in them to the
     proper locations. Further categorization of the entities by
     topic, gender or other attributes is out of the scope of this
     TIP. This type of categorization rather is in the domain of
     general and specialized catalogs which can be set up later and
     then bound into the unified webspace proposed here.

	   > Note that such catalogs can and should make use of the proposed
     domains to reduce the effort necessary by them to stay current
     with respect to the location of the referenced entities \(people,
     packages, etc\).

   * The first pre-draft of this TIP contained definitions for the
     names to use in the various domains. These definitions have been
     removed on the grounds that their format and other issues like
     resolution of naming conflicts, order of precedence, etc. are
     best handled in one or more separate documents. The role of this
     TIP is to lay down a framework within which the community can
     operate and not to fill in every conceivable detail.

	   > These details can be discussed and decided upon by the group of
     maintainers proposed in the last section.

   * This proposal makes the Tcl community dependent on an external
     entity, namely the maintainers of <http://www.purl.org/.> This is
     considered acceptable.

# Example

The following examples show how to use PURLs, using some of the
already existing ones:

    * <http://www.purl.org/tcl/tip/> refers to the TIP archive.

    * <http://www.purl.org/tcl/wiki/> refers to the Tcl'ers Wiki.

# Copyright

This document is in the public domain.

Name change from tip/55.tip to tip/55.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
TIP:            55
Title:          Package Format for Tcl Extensions
Version:        $Revision: 1.18 $
Author:         Steve Cassidy <[email protected]>
Author:         Larry W. Virden <[email protected]>
State:          Draft
Type:           Informative
Vote:           No voting
Created:        16-Aug-2001
Post-History:   


~ Abstract

This document specifies the contents of a binary distribution of a Tcl
package, especially directory structure and required files, suitable
for automated installation into an existing Tcl installation.

~ Rationale

There is currently no standard way of distributing or installing a Tcl
extension package.  The TEA document defines a standard interface to
''building'' packages and includes an ''install'' target but
presumes that the packages is being installed on the same machine as
it was built. This TIP defines a directory structure and assorted
files for the binary distribution of a package which can be placed
into an archive (for example zip or tar file) and transferred for
installation on another machine.  A basic mechanism for installation of
packages is also described.

~ Definitions

The following definitions are excerpted from [78]:

 package: A collection of files providing additional functionality to
   a user of a Tcl interpreter when loaded into said interpreter.

 > Some files in a package implement the provided functionality
   whereas other files contain metadata required by the package
   management of Tcl to be able to use the package.

 distribution: An encapsulation of one or more ''packages'' for
   transport between places, machines, organizations, and people.

 shared library: A piece of binary code that provides a set of
   operations and data structures like a normal library, but which does
   not need to be physically incorporated into the executables that
   use it until they are actually executed. This is the normal way to
   distribute binary code for a Tcl package such that it can be
   incorporated into a Tcl interpreter with the ''load'' command. On
   Windows, shared libraries are known as DLLs, on the Macintosh ...

~ References

Much of the required structure for an installable distribution is
defined by the requirements of Tcl's existing package loading methods.
The structure of an installable distribution should largely mirror
the structure of an installed package where possible.

The R system (a statistical package [http://www.r-project.org/]) has a
well defined package format which enables automatic installation of new
packages and integration of documentation and demonstration programs
for these with that of the main R system.

A number of packaging and installation systems (for example, Debian
[http://www.debian.org] and RPM [http://www.redhat.com]) have been
developed by the Linux community which provide an interesting range of
facilities.  These systems commonly provide facilities for pre and post
installation scripts and pre and post removal scripts to help set up
and shut down packages.  Also included are detailed dependency
relations between packages which can be used by an installer to ensure
that a package will work once it is installed or warn of potential
conflicts after installation.

A significant part of this proposal is the proposed format of the
package metadata which derives from other metadata standardisation
efforts, mainly the Dublin Core [http://purl.org/dc/] and the Resource
Description Framework [http://www.w3.org/RDF].

~ Requirements

The simplest case of a Tcl package is one that contains only Tcl code;
these will be considered first, and the additional issues raised by
packages containing compiled code will be dealt with later.

The minimum contents of a Tcl only package are defined by the
requirements of [[package require xyzzy]].  The package needs to be
placed in a directory on the ''auto_path'' and must contain one or more
''.tcl'' files which implement the functionality provided by the
package.

In addition to these files, it is useful to include documentation for
the commands implemented by the package and some additional metadata
about the author etc.  Distributions might also optionally include
demonstration scripts and applications illustrating their use, these
could either be incorporated into the documentation or included as
stand-alone Tcl files.

Distributions which include shared libraries add an additional layer of
complexity since these will only run on the platforms for which they
have been compiled.  There are two clear options here: either
distributions are platform specific, intended for installation on one
platform alone, or the structure of the distribution is extended to
allow the option of including multiple shared libraries.  The latter
option would allow a single installation to serve multiple platforms
and so should be preferred although this TIP will not ''require'' a
distribution to support multiple platforms.

~ Proposed Directory Structure

The following directory structure is proposed for an installable
distribution:

|  packagename$version
|      + DESCRIPTION.txt  -- Metadata, description of the package
|      + doc/             -- documentation
|      + examples/        -- example scripts and applications
|      + $architecture/   -- shared library directories
|      + pkgIndex.tcl     -- package index file (optional)

In addition, a distribution may include any additional files or
directories required for its operation.

''DESCRIPTION'' is a file containing metadata about the
package(s) contained in the distribution. Its format will be described
in a later section of this document.

The file ''pkgIndex.tcl'' currently required by the package-loading
mechanism of the Tcl core is ''optionally'' distributed. In most cases,
it will be generated by the installer; all the information which is
necessary to do this is part of the distribution.  Distribution authors
should only include ''pkgIndex.tcl'' if special features of their
distribution mean that the generated file would not work.

If the ''pkgIndex.tcl'' file is included in the distribution it should
load files from their locations within the distribution directory
structure. For example, Tcl files should be loaded from the ''tcl''
directory.

''doc/'' directory contains documentation in an accepted format.
Currently Tcl documentation is delivered either in source form (nroff
or TMML) or as HTML files.  Given the lack of a standard cross platform
solution, this TIP does not require a specific format; however, the
inclusion of either a text or HTML formatted help file is strongly
encouraged.  If HTML formatted help is included the main file should be
named ''index.html'' or ''index.htm'' so that it can be linked to a
central web page.  If only plain text documentation is included there
should be a file called ''readme.txt'' (in either upper or lower case)
which will serve as the top level documentation file.

''examples/'' directory contains one or more Tcl files giving examples
of the use of this package. These should be complete scripts
suitable for either sourcing in tclsh/wish or running from the command
line. The examples should be self contained and any external data
should be included in files in this directory or a sub-directory.  This
directory should contain a file ''readme.txt'' which explains how to
run the examples and provides a commentary on what they do.

''$architecture'' directories contain shared libraries for various
platforms. The special architecture ''tcl'' is used for Tcl script
files. They either implement the package or contain companion procedure
definitions to the shared libraries of the package.

The distribution need not provide all possible combinations of
architectures and may only provide one shared library.  This structure
is proposed to allow shared libraries to co-exist in a multi-platform
environment and to allow binary packages to be distributed in
multi-platform distributions.  The architectures included in the
distribution should be named in the DESCRIPTION.txt file.

The possible values of $architecture and methods for generating them
are discussed in a later section.

~ Metadata

This section defines the metadata describing the package contained in
the distribution in a format-neutral way. The model for this data is
that provided by the Resource Description Framework (RDF
[http://www.w3.org/rdf]) which defines a triple based data model.  The
RDF model defines objects, their properties and relationships between
them.  In addition, where possible, element names are taken from the
Dublin Core Metadata Element Set
[http://dublincore.org/documents/1999/07/02/dces/] which defines a
standard set of element names for metadata. Dublin Core names are
marked with DC in parentheses in the following list.

In a package description, the object being described is the package
itself, hence the element names are all intended to describe
packages. Other objects might be described including people and
organisations. The package description should not include these
objects but a package repository might store them separately keyed on
the values stored in this description (e.g. email addresses of creators).

 * ''Identifier'' (DC)

 > This element is a string containing the name of the distributed
   package. The name may consist only of alphanumeric characters,
   colons, dashes and underscores.  This name should correspond to the
   name of
   the package defined by this distribution (that is, the code should
   contain ''package provide xyzzy'' where ''xyzzy'' is the value of
   this element.

 > Care must be taken to make this name unique among the package names
   in the archive. To overcome this, namespace style names separated by
   double colons should be used.

 > Examples: xyzzy, tcllib, xml::soap, cassidy::wonderful-package_2

 * ''Version''

 > This element is a string containing the version of the
   package. It consists of 4 components separated by full stops. The
   components are ''major version'', ''minor version'', ''maturity''
   and ''level''; and are written in this order.

 > The major and minor version components are integer numbers greater
   than or equal to zero.

 > The component ''maturity'' is restricted to the values a, b.
   The represent the maturity states ''alpha'', ''beta''
   respectively. For a production release, this component can be omitted.

 > The ''level'' component allows a more fine-grained differentiation
   of maturity levels.  When a package has maturity ''production'' the
   ''level'' component is often called the ''patchlevel'' of the package.
   If the ''level'' component is zero, it may be omitted.

 > The period each side of the ''maturity'' component may be omitted.

 > Valid version numbers can be decoded via the following regular
   expression:

|regexp {([0-9]+)\.([0-9]+)\.?([ab])?\.?([0-9]*)} $ver => major minor maturity level

 > Examples: 8.4.0  8.4a1 2.5.b.5

 * ''Title'' (DC)

 > This element is a free form string containing a one sentence
   description of the package contained in the distribution.

 > Example: Installer Tools for Tcl Packages

 * ''Creator'' (DC)

 > This element is a string containing the name of the person,
   organisation or service responsible for the creation of the
   package optionally followed by the email address of the author in
   angle brackets [http://www.faqs.org/rfcs/rfc2822.html]. More detail
   about an author can be provided in a separate object in the RDF
   description and if this is provided the email address should be used
   as the value of the Name field in that object.

 > If there is more than one author this field may appear multiple
   times.

 > Email addresses may be obfuscated to avoid spam harvesters.

 > Example: Steve Cassidy <Steve.Cassidy at mq dot edu dot au>

 * ''Contributor'' (DC)

 > This element is a string analogous to the Creator element which
   contains the name of a contributor to the package.

 * ''Rights'' (DC)

 > Typically, a Rights element will contain a rights management
   statement for the resource, or reference a service providing such
   information.  This will usually be a reference to the license under
   which the package is distributed. This can be a free form string
   naming the license or a URL referring to a document containing the
   text of the license.

 > If the Rights element is absent, no assumptions can be made
   about the status of these and other rights with respect to
   the resource.

 > Examples: BSD, http://www.opensource.org/licenses/artistic-license.html

 * ''URL''

 > This element is a string containing an url referring to a
   document or site at which the information about the package can be
   found. This url is ''not'' the location of the distribution, as this
   might be part of a larger repository separate from the package site.

 > Example: http://www.shlrc.mq.edu.au/~steve/tcl/

 * ''Available'' (DC)

 > This element is the release data of the package in the form YYYY-MM-DD.

 > YYYY is a four-digit integer number greater than zero denoting the
   year the distribution was released.

 > MM is a two-digit integer number greater than zero and less than
   13. It is padded with zero at the front if it less than 10. It
   denotes the month the distribution was released. The number 1
   represents January, 2 represents February; and 12 represents December.

 > DD is a two-digit integer number greater than zero and less than 32.
   It is and padded with zero at the front if less than 10. It denotes
   the day in the month the distribution was released.

 > A valid data string can be obtained with the Tcl command
   [[clock format [clock seconds] -format "%Y-%m-%d"]]

 > Example: 2002-01-23

 > (The DC element is Date but it can be refined to Created,
   Available, Applies)

 * ''Description'' (DC)

 > This element is a free form string briefly describing the package.

 * ''Architecture''

 > This element is a string describing one of the architectures
  included in the distribution. As a distribution is allowed to
  contain the files for several architectures, this element may
  appear multiple times and should correspond to a directory in the
  distribution.

 * ''Require''

 > Names a package that must be installed for this package to operate
   properly. This should have the same format as the ''package
   require'' command, eg. ''?-exact? package ?version?''.

 > Example: http 2.0

 * ''Recommend''

 > Declares a strong, but not absolute dependency on another package.
   In most cases this package should be installed unless the user has
   specific reasons not to install them.

 * ''Suggest''

 > Declares a package which would enhance the functionality of this
   package but which is not a requirement for the basic functionality
   of the package.

 * ''Conflict''

 > Names a package with which can't be installed alongside this
   package. The syntax is the same as for Require.  If a conflicting
   package is present on the system, an installer might offer an option
   of removing it or not installing this package.

 * ''Subject'' (DC)

 > The topic or content of the package expressed as a set of Keywords.
   At some future time, a set of canonical keywords may be established
   by a repository manager.

The following Dublin Core elements were not included in the standard
set above but may be used in a package description if appropriate.

 * ''Publisher''

 > An entity responsible for making the package available.

 * ''Type''

 > The nature or genre of the content of the resource. For a Tcl
   package the value of this element would be Software if the DCMI
   Type Vocabulary
   [http://au.dublincore.org/documents/2000/07/11/dcmi-type-vocabulary/]
   was used.  A more useful set of types might be developed in the
   future for Tcl packages.

 * ''Format''

 > The physical or digital manifestation of the resource.  This might
   be used by archive maintainers to specify the format of a package
   archive, eg. zip, tar etc.

 * ''Source''

 > A Reference to a resource from which the present resource is derived.

 * ''Language''

 > A language of the intellectual content of the resource.  Could be
   used if multi-language packages are available. Should use the two
   letter language code defined by RFC 1766, eg. 'fr' for French, 'en'
   for English.

~ Encoding of the Metadata

The primary means of storing RDF data is using XML but it can be stored
in many other formats.  This TIP prescribes a simple text based
encoding according to the RFC 2822 format which is described in this
section. Data stored in this format can be converted to XML format for
use by other tools, similarly XML formatted descriptions can be
converted into this text format without loss of information.

The text format description is stored in the file ''DESCRIPTION.txt''.
The XML formatted version of the data may be stored in the file
''DESCRIPTION.rdf'' within the archive and may be automatically
generated if not present.

The general format of this file is that of a RFC 2822 mail message,
without body and using custom headers. The available headers are the
case-independent logical names from the preceding section but may be
augmented by other fields defined by repository maintainers or other
applications. The headers are allowed appear in any order.

Example:

|  Identifier: stemmer
|  Version: 1.0.0
|  Title: A stemmer for English.
|  Creator: Steve Cassidy <[email protected]>
|  Description:   Provides a procedure to remove any prefixes or suffixes on
|         a word to give the word stem. Uses Porter's algorithm to do this
|         in an intelligent manner with an accuracy of around 80%.
|  Rights: BSD
|  URL: http://www.shlrc.mq.edu.au/emu/tcl/
|  Available: 2001-08-16
|  Architecture: tcl
|  Subject: linguistics
|  Subject: text

~ Combination Distributions

It is often useful to combine a number of related packages so that they
can be installed together to provide a certain kind of functionality,
for example, web page production tools or database access.  Perl uses
the term ''Bundle'' to refer to such a group of related packages.
There are two alternative mechanisms for distribution of such a package
within the mechanisms suggested here.
Firstly, since a distribution may contain more than one package, the
set of files making up the various packages could be combined together
and described by a single DESCRIPTION.txt file.  This is similar to the
way that tcllib is currently distributed.  The disadvantage would be
that all of the Tcl files implementing these packages would have to
reside in the same directory which could cause name clashes.

The second alternative is to create a distribution consisting of only a
DESCRIPTION.txt file to describe which Requires the component packages
causing them to be installed from the repository. For example, tcllib
might be described as follows:

|  Identifier: tcllib
|  Version: 1.0.0
|  Title: The Standard Tcl Library
|  Description:  This package is intended to be a collection of Tcl
|             packages that provide utility functions useful to a large
|             collection of Tcl programmers.
|  Rights: BSD
|  URL: http://sourceforge.net/projects/tcllib
|  Contributor: Andreas Kupries  <andreas_kupries at users dot sourceforge dot net>
|  Contributor: Don Porter <dgp at users dot sourceforge dot net>
|  Require: base64
|  Require: cmdline
|  Require: csv
|  ...

Installing tcllib would cause the installer to fetch base64, cmdline,
csv etc from the repository and install them in order to satisfy the
tcllib requirement.  A new pkgIndex.tcl file could be constructed to
load all of these packages if ''[[package require tcllib]]'' was called.

~ Architecture

Possible values for $architecture in the directory structure include:

 * the value of
   ''tcl_platform(platform)'': windows, unix, macintosh

 * a composite of tcl_platform
   values: ''$tcl_platform(machine)-$tcl_platform(os)-$tcl_platform(osVersion)''

 * a canonical system name as returned by
   ''config.guess'': ''i686-pc-linux-gnu''

~ Installing Packages

A package structured according to this TIP can be installed using the following
steps:

  1. Download the package archive (eg. zip file)

  2. Locate a writable directory included on $auto_path (or ask for a
     installation directory)

  3. Unpack the archive in the desired location.

  4. Run pkg_mkIndex with appropriate arguments to generate a
     pkgIndex.tcl file if none is present. Arguments will include the
     appropriate Architecture directories for the platform.

  5. ''(optional)'' link help files and demos to the central index.

~ Alternatives

Alternatives might be considered for the package DESCRIPTION.txt file, for
the documentation directory and for the location of shared libraries.

An alternative for package description file is to include an
alternative package description, for example the XML based ``ppd''
format used to describe Perl packages on the ActiveState Perl package
repository. The main motivation for the simple format proposed is that
it is trivial for authors to write and trivial for programs to read and
can be transformed into standards based RDF XML.  The use of the DC
element names means that search engines etc. will be able to usefully
index the packages in a repository.

<
|
<
|
|
|
|
|
|
|
>

|





|



|



|



|

|








|







|


|






|




|
|










|
|

|






|
|
|
















|


|




|
|
|
|
|
|




|
|


|
|


|


|

|


|
|
|



|

|


|




|


|
|













|



|
|



|








|

|

|



|
|


|



|

|

|

|
|

|


|
|


|
|
|
|

|

|


|

|

|

|


|

|

|


|




|


|

|

|

|


|

|






|



|

|

|

|


|

|

|

|


|




|



|
|

|

|
|

|

|

|

|





|

|
|
|

|

|

|



|

|



|

|




|

|






|

|

|

|


|



|

|



|

|

|

|




|








|

|










|
|
|
|
|
|
|
|
|
|
|
|
|

|




|














|
|
|
|
|
|
|
|
|
|
|
|
|
|




|

|




|

|
|


|

|




|

|
|



|



|

|





|








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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511

# TIP 55: Package Format for Tcl Extensions

	Author:         Steve Cassidy <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           No voting
	Created:        16-Aug-2001
	Post-History:   
-----

# Abstract

This document specifies the contents of a binary distribution of a Tcl
package, especially directory structure and required files, suitable
for automated installation into an existing Tcl installation.

# Rationale

There is currently no standard way of distributing or installing a Tcl
extension package.  The TEA document defines a standard interface to
_building_ packages and includes an _install_ target but
presumes that the packages is being installed on the same machine as
it was built. This TIP defines a directory structure and assorted
files for the binary distribution of a package which can be placed
into an archive \(for example zip or tar file\) and transferred for
installation on another machine.  A basic mechanism for installation of
packages is also described.

# Definitions

The following definitions are excerpted from [[78]](78.md):

 package: A collection of files providing additional functionality to
   a user of a Tcl interpreter when loaded into said interpreter.

 > Some files in a package implement the provided functionality
   whereas other files contain metadata required by the package
   management of Tcl to be able to use the package.

 distribution: An encapsulation of one or more _packages_ for
   transport between places, machines, organizations, and people.

 shared library: A piece of binary code that provides a set of
   operations and data structures like a normal library, but which does
   not need to be physically incorporated into the executables that
   use it until they are actually executed. This is the normal way to
   distribute binary code for a Tcl package such that it can be
   incorporated into a Tcl interpreter with the _load_ command. On
   Windows, shared libraries are known as DLLs, on the Macintosh ...

# References

Much of the required structure for an installable distribution is
defined by the requirements of Tcl's existing package loading methods.
The structure of an installable distribution should largely mirror
the structure of an installed package where possible.

The R system \(a statistical package <http://www.r-project.org/> \) has a
well defined package format which enables automatic installation of new
packages and integration of documentation and demonstration programs
for these with that of the main R system.

A number of packaging and installation systems \(for example, Debian
<http://www.debian.org>  and RPM <http://www.redhat.com> \) have been
developed by the Linux community which provide an interesting range of
facilities.  These systems commonly provide facilities for pre and post
installation scripts and pre and post removal scripts to help set up
and shut down packages.  Also included are detailed dependency
relations between packages which can be used by an installer to ensure
that a package will work once it is installed or warn of potential
conflicts after installation.

A significant part of this proposal is the proposed format of the
package metadata which derives from other metadata standardisation
efforts, mainly the Dublin Core <http://purl.org/dc/>  and the Resource
Description Framework <http://www.w3.org/RDF> .

# Requirements

The simplest case of a Tcl package is one that contains only Tcl code;
these will be considered first, and the additional issues raised by
packages containing compiled code will be dealt with later.

The minimum contents of a Tcl only package are defined by the
requirements of [package require xyzzy].  The package needs to be
placed in a directory on the _auto\_path_ and must contain one or more
_.tcl_ files which implement the functionality provided by the
package.

In addition to these files, it is useful to include documentation for
the commands implemented by the package and some additional metadata
about the author etc.  Distributions might also optionally include
demonstration scripts and applications illustrating their use, these
could either be incorporated into the documentation or included as
stand-alone Tcl files.

Distributions which include shared libraries add an additional layer of
complexity since these will only run on the platforms for which they
have been compiled.  There are two clear options here: either
distributions are platform specific, intended for installation on one
platform alone, or the structure of the distribution is extended to
allow the option of including multiple shared libraries.  The latter
option would allow a single installation to serve multiple platforms
and so should be preferred although this TIP will not _require_ a
distribution to support multiple platforms.

# Proposed Directory Structure

The following directory structure is proposed for an installable
distribution:

	  packagename$version
	      + DESCRIPTION.txt  -- Metadata, description of the package
	      + doc/             -- documentation
	      + examples/        -- example scripts and applications
	      + $architecture/   -- shared library directories
	      + pkgIndex.tcl     -- package index file (optional)

In addition, a distribution may include any additional files or
directories required for its operation.

_DESCRIPTION_ is a file containing metadata about the
package\(s\) contained in the distribution. Its format will be described
in a later section of this document.

The file _pkgIndex.tcl_ currently required by the package-loading
mechanism of the Tcl core is _optionally_ distributed. In most cases,
it will be generated by the installer; all the information which is
necessary to do this is part of the distribution.  Distribution authors
should only include _pkgIndex.tcl_ if special features of their
distribution mean that the generated file would not work.

If the _pkgIndex.tcl_ file is included in the distribution it should
load files from their locations within the distribution directory
structure. For example, Tcl files should be loaded from the _tcl_
directory.

_doc/_ directory contains documentation in an accepted format.
Currently Tcl documentation is delivered either in source form \(nroff
or TMML\) or as HTML files.  Given the lack of a standard cross platform
solution, this TIP does not require a specific format; however, the
inclusion of either a text or HTML formatted help file is strongly
encouraged.  If HTML formatted help is included the main file should be
named _index.html_ or _index.htm_ so that it can be linked to a
central web page.  If only plain text documentation is included there
should be a file called _readme.txt_ \(in either upper or lower case\)
which will serve as the top level documentation file.

_examples/_ directory contains one or more Tcl files giving examples
of the use of this package. These should be complete scripts
suitable for either sourcing in tclsh/wish or running from the command
line. The examples should be self contained and any external data
should be included in files in this directory or a sub-directory.  This
directory should contain a file _readme.txt_ which explains how to
run the examples and provides a commentary on what they do.

_$architecture_ directories contain shared libraries for various
platforms. The special architecture _tcl_ is used for Tcl script
files. They either implement the package or contain companion procedure
definitions to the shared libraries of the package.

The distribution need not provide all possible combinations of
architectures and may only provide one shared library.  This structure
is proposed to allow shared libraries to co-exist in a multi-platform
environment and to allow binary packages to be distributed in
multi-platform distributions.  The architectures included in the
distribution should be named in the DESCRIPTION.txt file.

The possible values of $architecture and methods for generating them
are discussed in a later section.

# Metadata

This section defines the metadata describing the package contained in
the distribution in a format-neutral way. The model for this data is
that provided by the Resource Description Framework \(RDF
<http://www.w3.org/rdf> \) which defines a triple based data model.  The
RDF model defines objects, their properties and relationships between
them.  In addition, where possible, element names are taken from the
Dublin Core Metadata Element Set
<http://dublincore.org/documents/1999/07/02/dces/>  which defines a
standard set of element names for metadata. Dublin Core names are
marked with DC in parentheses in the following list.

In a package description, the object being described is the package
itself, hence the element names are all intended to describe
packages. Other objects might be described including people and
organisations. The package description should not include these
objects but a package repository might store them separately keyed on
the values stored in this description \(e.g. email addresses of creators\).

 * _Identifier_ \(DC\)

	 > This element is a string containing the name of the distributed
   package. The name may consist only of alphanumeric characters,
   colons, dashes and underscores.  This name should correspond to the
   name of
   the package defined by this distribution \(that is, the code should
   contain _package provide xyzzy_ where _xyzzy_ is the value of
   this element.

	 > Care must be taken to make this name unique among the package names
   in the archive. To overcome this, namespace style names separated by
   double colons should be used.

	 > Examples: xyzzy, tcllib, xml::soap, cassidy::wonderful-package\_2

 * _Version_

	 > This element is a string containing the version of the
   package. It consists of 4 components separated by full stops. The
   components are _major version_, _minor version_, _maturity_
   and _level_; and are written in this order.

	 > The major and minor version components are integer numbers greater
   than or equal to zero.

	 > The component _maturity_ is restricted to the values a, b.
   The represent the maturity states _alpha_, _beta_
   respectively. For a production release, this component can be omitted.

	 > The _level_ component allows a more fine-grained differentiation
   of maturity levels.  When a package has maturity _production_ the
   _level_ component is often called the _patchlevel_ of the package.
   If the _level_ component is zero, it may be omitted.

	 > The period each side of the _maturity_ component may be omitted.

	 > Valid version numbers can be decoded via the following regular
   expression:

		regexp {([0-9]+)\.([0-9]+)\.?([ab])?\.?([0-9]*)} $ver => major minor maturity level

	 > Examples: 8.4.0  8.4a1 2.5.b.5

 * _Title_ \(DC\)

	 > This element is a free form string containing a one sentence
   description of the package contained in the distribution.

	 > Example: Installer Tools for Tcl Packages

 * _Creator_ \(DC\)

	 > This element is a string containing the name of the person,
   organisation or service responsible for the creation of the
   package optionally followed by the email address of the author in
   angle brackets <http://www.faqs.org/rfcs/rfc2822.html> . More detail
   about an author can be provided in a separate object in the RDF
   description and if this is provided the email address should be used
   as the value of the Name field in that object.

	 > If there is more than one author this field may appear multiple
   times.

	 > Email addresses may be obfuscated to avoid spam harvesters.

	 > Example: Steve Cassidy <Steve.Cassidy at mq dot edu dot au>

 * _Contributor_ \(DC\)

	 > This element is a string analogous to the Creator element which
   contains the name of a contributor to the package.

 * _Rights_ \(DC\)

	 > Typically, a Rights element will contain a rights management
   statement for the resource, or reference a service providing such
   information.  This will usually be a reference to the license under
   which the package is distributed. This can be a free form string
   naming the license or a URL referring to a document containing the
   text of the license.

	 > If the Rights element is absent, no assumptions can be made
   about the status of these and other rights with respect to
   the resource.

	 > Examples: BSD, <http://www.opensource.org/licenses/artistic-license.html>

 * _URL_

	 > This element is a string containing an url referring to a
   document or site at which the information about the package can be
   found. This url is _not_ the location of the distribution, as this
   might be part of a larger repository separate from the package site.

	 > Example: <http://www.shlrc.mq.edu.au/~steve/tcl/>

 * _Available_ \(DC\)

	 > This element is the release data of the package in the form YYYY-MM-DD.

	 > YYYY is a four-digit integer number greater than zero denoting the
   year the distribution was released.

	 > MM is a two-digit integer number greater than zero and less than
   13. It is padded with zero at the front if it less than 10. It
   denotes the month the distribution was released. The number 1
   represents January, 2 represents February; and 12 represents December.

	 > DD is a two-digit integer number greater than zero and less than 32.
   It is and padded with zero at the front if less than 10. It denotes
   the day in the month the distribution was released.

	 > A valid data string can be obtained with the Tcl command
   [clock format [clock seconds] -format "%Y-%m-%d"]

	 > Example: 2002-01-23

	 > \(The DC element is Date but it can be refined to Created,
   Available, Applies\)

 * _Description_ \(DC\)

	 > This element is a free form string briefly describing the package.

 * _Architecture_

	 > This element is a string describing one of the architectures
  included in the distribution. As a distribution is allowed to
  contain the files for several architectures, this element may
  appear multiple times and should correspond to a directory in the
  distribution.

 * _Require_

	 > Names a package that must be installed for this package to operate
   properly. This should have the same format as the _package
   require_ command, eg. _?-exact? package ?version?_.

	 > Example: http 2.0

 * _Recommend_

	 > Declares a strong, but not absolute dependency on another package.
   In most cases this package should be installed unless the user has
   specific reasons not to install them.

 * _Suggest_

	 > Declares a package which would enhance the functionality of this
   package but which is not a requirement for the basic functionality
   of the package.

 * _Conflict_

	 > Names a package with which can't be installed alongside this
   package. The syntax is the same as for Require.  If a conflicting
   package is present on the system, an installer might offer an option
   of removing it or not installing this package.

 * _Subject_ \(DC\)

	 > The topic or content of the package expressed as a set of Keywords.
   At some future time, a set of canonical keywords may be established
   by a repository manager.

The following Dublin Core elements were not included in the standard
set above but may be used in a package description if appropriate.

 * _Publisher_

	 > An entity responsible for making the package available.

 * _Type_

	 > The nature or genre of the content of the resource. For a Tcl
   package the value of this element would be Software if the DCMI
   Type Vocabulary
   <http://au.dublincore.org/documents/2000/07/11/dcmi-type-vocabulary/> 
   was used.  A more useful set of types might be developed in the
   future for Tcl packages.

 * _Format_

	 > The physical or digital manifestation of the resource.  This might
   be used by archive maintainers to specify the format of a package
   archive, eg. zip, tar etc.

 * _Source_

	 > A Reference to a resource from which the present resource is derived.

 * _Language_

	 > A language of the intellectual content of the resource.  Could be
   used if multi-language packages are available. Should use the two
   letter language code defined by RFC 1766, eg. 'fr' for French, 'en'
   for English.

# Encoding of the Metadata

The primary means of storing RDF data is using XML but it can be stored
in many other formats.  This TIP prescribes a simple text based
encoding according to the RFC 2822 format which is described in this
section. Data stored in this format can be converted to XML format for
use by other tools, similarly XML formatted descriptions can be
converted into this text format without loss of information.

The text format description is stored in the file _DESCRIPTION.txt_.
The XML formatted version of the data may be stored in the file
_DESCRIPTION.rdf_ within the archive and may be automatically
generated if not present.

The general format of this file is that of a RFC 2822 mail message,
without body and using custom headers. The available headers are the
case-independent logical names from the preceding section but may be
augmented by other fields defined by repository maintainers or other
applications. The headers are allowed appear in any order.

Example:

	  Identifier: stemmer
	  Version: 1.0.0
	  Title: A stemmer for English.
	  Creator: Steve Cassidy <[email protected]>
	  Description:   Provides a procedure to remove any prefixes or suffixes on
	         a word to give the word stem. Uses Porter's algorithm to do this
	         in an intelligent manner with an accuracy of around 80%.
	  Rights: BSD
	  URL: http://www.shlrc.mq.edu.au/emu/tcl/
	  Available: 2001-08-16
	  Architecture: tcl
	  Subject: linguistics
	  Subject: text

# Combination Distributions

It is often useful to combine a number of related packages so that they
can be installed together to provide a certain kind of functionality,
for example, web page production tools or database access.  Perl uses
the term _Bundle_ to refer to such a group of related packages.
There are two alternative mechanisms for distribution of such a package
within the mechanisms suggested here.
Firstly, since a distribution may contain more than one package, the
set of files making up the various packages could be combined together
and described by a single DESCRIPTION.txt file.  This is similar to the
way that tcllib is currently distributed.  The disadvantage would be
that all of the Tcl files implementing these packages would have to
reside in the same directory which could cause name clashes.

The second alternative is to create a distribution consisting of only a
DESCRIPTION.txt file to describe which Requires the component packages
causing them to be installed from the repository. For example, tcllib
might be described as follows:

	  Identifier: tcllib
	  Version: 1.0.0
	  Title: The Standard Tcl Library
	  Description:  This package is intended to be a collection of Tcl
	             packages that provide utility functions useful to a large
	             collection of Tcl programmers.
	  Rights: BSD
	  URL: http://sourceforge.net/projects/tcllib
	  Contributor: Andreas Kupries  <andreas_kupries at users dot sourceforge dot net>
	  Contributor: Don Porter <dgp at users dot sourceforge dot net>
	  Require: base64
	  Require: cmdline
	  Require: csv
	  ...

Installing tcllib would cause the installer to fetch base64, cmdline,
csv etc from the repository and install them in order to satisfy the
tcllib requirement.  A new pkgIndex.tcl file could be constructed to
load all of these packages if _[package require tcllib]_ was called.

# Architecture

Possible values for $architecture in the directory structure include:

 * the value of
   _tcl\_platform\(platform\)_: windows, unix, macintosh

 * a composite of tcl\_platform
   values: _$tcl\_platform\(machine\)-$tcl\_platform\(os\)-$tcl\_platform\(osVersion\)_

 * a canonical system name as returned by
   _config.guess_: _i686-pc-linux-gnu_

# Installing Packages

A package structured according to this TIP can be installed using the following
steps:

  1. Download the package archive \(eg. zip file\)

  2. Locate a writable directory included on $auto\_path \(or ask for a
     installation directory\)

  3. Unpack the archive in the desired location.

  4. Run pkg\_mkIndex with appropriate arguments to generate a
     pkgIndex.tcl file if none is present. Arguments will include the
     appropriate Architecture directories for the platform.

  5. _\(optional\)_ link help files and demos to the central index.

# Alternatives

Alternatives might be considered for the package DESCRIPTION.txt file, for
the documentation directory and for the location of shared libraries.

An alternative for package description file is to include an
alternative package description, for example the XML based \`\`ppd_
format used to describe Perl packages on the ActiveState Perl package
repository. The main motivation for the simple format proposed is that
it is trivial for authors to write and trivial for programs to read and
can be transformed into standards based RDF XML.  The use of the DC
element names means that search engines etc. will be able to usefully
index the packages in a repository.

528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557

The alternative to having shared libraries in specific directories is
to have separate packages for each new platform. This has the
advantage of making the packages smaller and more closely correspond
to the existing directory structure of an installed package.  The
main motivation for the suggested directory structure is to allow
multi-platform packages or to facilitate multi-platform installations.

~ Supporting Tools

The standards outlined in this TIP should be supported by Tcl scripts
to:

 * Generate empty package templates for new projects.

 * Validate package directories or archive files.

 * Read and write the DESCRIPTION.txt file and provide a standard
   interface to the information it contains. Convert between RFC 2822
   and XML formats.

 * Install a package from an appropriately structured archive.

In addition, the TEA standard should be extended with a ''package''
makefile target which will act like the current ''install'' target but
which will copy files to a local directory and optionally build an
archive of the package for distribution.

~ Copyright

This document has been placed in the public domain.








|














|
|



|


>
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
The alternative to having shared libraries in specific directories is
to have separate packages for each new platform. This has the
advantage of making the packages smaller and more closely correspond
to the existing directory structure of an installed package.  The
main motivation for the suggested directory structure is to allow
multi-platform packages or to facilitate multi-platform installations.

# Supporting Tools

The standards outlined in this TIP should be supported by Tcl scripts
to:

 * Generate empty package templates for new projects.

 * Validate package directories or archive files.

 * Read and write the DESCRIPTION.txt file and provide a standard
   interface to the information it contains. Convert between RFC 2822
   and XML formats.

 * Install a package from an appropriately structured archive.

In addition, the TEA standard should be extended with a _package_
makefile target which will act like the current _install_ target but
which will copy files to a local directory and optionally build an
archive of the package for distribution.

# Copyright

This document has been placed in the public domain.

Name change from tip/56.tip to tip/56.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

TIP:		56
Title:		Standardize Call Interface to Tcl_Eval* Functions
State:		Final
Type:		Project
Tcl-Version:	8.4
Vote:		Done
Post-History:	
Version:	$Revision: 1.4 $
Author:		Miguel Sofer <[email protected]>
Created:	28-Aug-2001


~ Abstract

This TIP replaces ''Tcl_EvalTokens'' with ''Tcl_EvalTokensStandard'',
which obeys the standard result management conventions for script
evaluation functions.

~ Rationale

The standard call interface for ''Tcl_Eval*'' functions returns a Tcl
completion code (TCL_OK, TCL_ERROR, TCL_RETURN, TCL_BREAK, or
TCL_CONTINUE), and sets a result object in the interpreter.  The
single exception is the function ''Tcl_EvalTokens'', that returns a
pointer to the result object, or a NULL when an exception occurs.
This effectively transforms all exceptions into errors.  This TIP
proposes to replace ''Tcl_EvalTokens'' with a new function
''Tcl_EvalTokensStandard'' that performs the same chores but adheres
to the standard call interface.

There are two arguments for the replacement of ''Tcl_EvalTokens'':

   * Present a consistent call interface to all ''Tcl_Eval*''
     functions.

   * Allow the return of non-error exceptional returns when evaluating
     tokens; the impossibility to do this is the cause of Bugs #455151
(https://sourceforge.net/tracker/index.php?func=detail&aid=455151&group_id=10894&atid=110894)
     and #219384
(https://sourceforge.net/tracker/index.php?func=detail&aid=219384&group_id=10894&atid=110894)

~ Proposed Change

The proposal is to deprecate the use of ''Tcl_EvalTokens'' and replace
it with a new ''Tcl_EvalTokensStandard''. The core should only use the
new function, the old one remains only for backward compatibility with
extensions.

The proposal is implemented in the patch included in [[Bug: 455151]]
https://sourceforge.net/tracker/index.php?func=detail&aid=455151&group_id=10894&atid=110894

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
>

|

|



|

|
|
|
|


|
|


|

|



|
|
|
|

|

|
|



|
|

|


>

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

# TIP 56: Standardize Call Interface to Tcl_Eval* Functions
	State:		Final
	Type:		Project
	Tcl-Version:	8.4
	Vote:		Done
	Post-History:	

	Author:		Miguel Sofer <[email protected]>
	Created:	28-Aug-2001
-----

# Abstract

This TIP replaces _Tcl\_EvalTokens_ with _Tcl\_EvalTokensStandard_,
which obeys the standard result management conventions for script
evaluation functions.

# Rationale

The standard call interface for _Tcl\_Eval\*_ functions returns a Tcl
completion code \(TCL\_OK, TCL\_ERROR, TCL\_RETURN, TCL\_BREAK, or
TCL\_CONTINUE\), and sets a result object in the interpreter.  The
single exception is the function _Tcl\_EvalTokens_, that returns a
pointer to the result object, or a NULL when an exception occurs.
This effectively transforms all exceptions into errors.  This TIP
proposes to replace _Tcl\_EvalTokens_ with a new function
_Tcl\_EvalTokensStandard_ that performs the same chores but adheres
to the standard call interface.

There are two arguments for the replacement of _Tcl\_EvalTokens_:

   * Present a consistent call interface to all _Tcl\_Eval\*_
     functions.

   * Allow the return of non-error exceptional returns when evaluating
     tokens; the impossibility to do this is the cause of Bugs \#455151
\(<https://sourceforge.net/tracker/index.php?func=detail&aid=455151&group\_id=10894&atid=110894\)>
     and \#219384
\(<https://sourceforge.net/tracker/index.php?func=detail&aid=219384&group\_id=10894&atid=110894\)>

# Proposed Change

The proposal is to deprecate the use of _Tcl\_EvalTokens_ and replace
it with a new _Tcl\_EvalTokensStandard_. The core should only use the
new function, the old one remains only for backward compatibility with
extensions.

The proposal is implemented in the patch included in [Bug: 455151]
<https://sourceforge.net/tracker/index.php?func=detail&aid=455151&group\_id=10894&atid=110894>

# Copyright

This document has been placed in the public domain.

Name change from tip/57.tip to tip/57.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

TIP:            57
Title:          Move TclX's [lassign] into the Tcl Core
Version:        $Revision: 2.4 $
Author:         Donal K. Fellows <[email protected]>
Author:         Agnar Renolen <[email protected]>
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        30-Aug-2001
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes to move the ''lassign'' command from the TclX
extension into the Tcl core to make multiple assignment a much easier
process for people.

~Rationale

In many cases, a command needs to return more than one return value to
the caller.  For example, suppose that the statement:

| set coords [LocateFeature $featureID]

would set the variable "coords" to a list containing two elements "x"
and "y".  Assume that you need to set the "x" and "y" components
directly, you can do this today using the following statement:

| foreach {x y} [LocateFeature $featureID] {}

Now, this is not what the ''foreach'' command was designed for, and it
is not obvious at first glance from the source code what the statement
does.  Although it is quite useful for the purpose described in this
TIP, It would be more logical if the developer could write the
following:

| set {x y} [LocateFeature $featureID]

or

| mset {x y} [LocateFeature $featureID]

However, there is already a command in TclX for doing this kind of
operation: [lassign].  Given that many people already know TclX,
importing the command from there makes a great deal of sense.  It also
has the nice feature of returning those list items that were not
assigned, making it easy to strip a few words off the front of a list.
That sort of operation is useful when performing tasks like
command-line option parsing.

~Proposal

Define a new command in Tcl called [lassign] with the following syntax
(''$val'' indicates an argument that the caller would supply):

| lassign $listValue $varName ?$varName ...?

The command interprets its first argument as a list value and all
subsequent arguments as variable names.  The first item in the list
value (i.e. at index 0) will be assigned to the first variable named,
the second item in the list value will be assigned to the second
variable named (if present), etc.  When there are more variables than
list items, the remaining variables will be assigned the empty string.
The result of the command is a sublist of the input list-value that
contains only items that were not assigned to a variable; if all
values were assigned, the result is an empty list.

This is exactly the specification of the behaviour of the
correspondingly-named command in TclX.

~Notes

It should be possible to efficiently compile [lassign] in many cases,
which would make a tremendous difference in execution speed over not
only the TclX version of [lassign], but also over the [foreach]
"idiom", especially when assigning to variables that are not simple
local variables (the case which [foreach] compilation is optimized
for.)  For this reason, I'm not committing to implementing [lassign]
using the TclX code.

This TIP was substantially different in the past.  Please view the CVS
history for details.

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|



|




|





|

|





|



|









|


|

|



|

|








|





|
|





|


>

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

# TIP 57: Move TclX's [lassign] into the Tcl Core

	Author:         Donal K. Fellows <[email protected]>
	Author:         Agnar Renolen <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        30-Aug-2001
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes to move the _lassign_ command from the TclX
extension into the Tcl core to make multiple assignment a much easier
process for people.

# Rationale

In many cases, a command needs to return more than one return value to
the caller.  For example, suppose that the statement:

	 set coords [LocateFeature $featureID]

would set the variable "coords" to a list containing two elements "x"
and "y".  Assume that you need to set the "x" and "y" components
directly, you can do this today using the following statement:

	 foreach {x y} [LocateFeature $featureID] {}

Now, this is not what the _foreach_ command was designed for, and it
is not obvious at first glance from the source code what the statement
does.  Although it is quite useful for the purpose described in this
TIP, It would be more logical if the developer could write the
following:

	 set {x y} [LocateFeature $featureID]

or

	 mset {x y} [LocateFeature $featureID]

However, there is already a command in TclX for doing this kind of
operation: [lassign].  Given that many people already know TclX,
importing the command from there makes a great deal of sense.  It also
has the nice feature of returning those list items that were not
assigned, making it easy to strip a few words off the front of a list.
That sort of operation is useful when performing tasks like
command-line option parsing.

# Proposal

Define a new command in Tcl called [lassign] with the following syntax
\(_$val_ indicates an argument that the caller would supply\):

	 lassign $listValue $varName ?$varName ...?

The command interprets its first argument as a list value and all
subsequent arguments as variable names.  The first item in the list
value \(i.e. at index 0\) will be assigned to the first variable named,
the second item in the list value will be assigned to the second
variable named \(if present\), etc.  When there are more variables than
list items, the remaining variables will be assigned the empty string.
The result of the command is a sublist of the input list-value that
contains only items that were not assigned to a variable; if all
values were assigned, the result is an empty list.

This is exactly the specification of the behaviour of the
correspondingly-named command in TclX.

# Notes

It should be possible to efficiently compile [lassign] in many cases,
which would make a tremendous difference in execution speed over not
only the TclX version of [lassign], but also over the [foreach]
"idiom", especially when assigning to variables that are not simple
local variables \(the case which [foreach] compilation is optimized
for.\)  For this reason, I'm not committing to implementing [lassign]
using the TclX code.

This TIP was substantially different in the past.  Please view the CVS
history for details.

# Copyright

This document is placed in the public domain.

Name change from tip/58.tip to tip/58.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

TIP:            58
Title:          Extend [set] to Assign Multiple Values to Multiple Variables
Version:        $Revision: 1.6 $
Author:         Anselm Lingnau <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        02-Sep-2001
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes a multiple assignment command as a
backwards-compatible extension to the Tcl ''set'' command.

~ Introduction

Often one needs to assign values to several variables in close
proximity.  Right now several ''set'' commands are necessary:

|  set a 123
|  set b 456

or

|  set a 123; set b 456

Or one abuses the ''foreach'' command:

|  foreach {a b} {123 456} break

However, by analogy to the ''variable'' and ''array set'' commands,
the following would be useful:

|  set a 123 b 456

This would assign 123 to the variable ''a'' and 456 to the variable
''b''.

Note that this extension is backwards-compatible to existing uses of
the ''set'' command since until now only one or two arguments to
''set'' were allowed.

~ Specification

The ''set'' command is extended to allow either one or an even number
of arguments.  The behaviour in the case of one argument remains the
one documented in the ''set'' manual page; when an even number of
arguments is specified, the behaviour of ''set v0 e0 ... vn en'' is
identical to that of the sequence of commands ''set v0 e0; ...; set vn
en'' according to the traditional semantics, except that the way
Tcl processes commands means that ''e0'' ... ''en'' are all
evaluated before any assignments are performed. I.e., the commands

|  set a 1
|  set a 2 b $a
|  puts $b

print ''1'', not ''2''. If this is an issue you must use separate
''set'' statements.

The command ''set v0 e0 ... vn en'' returns the value of ''en''.

~ Rationale

This extension is an obvious analogy to the ''variable'' and ''array
set'' commands of Tcl, both of which allow an alternating list of
names and expressions to be given as arguments.  It is completely
backwards-compatible (''set'' invocations with more than two arguments
used to be syntax errors) and very easily implemented.

This extension in no way prejudices against the adoption and use of
other multiple-assignment commands, such as ''lassign'' (see [57]).
In particular, the ''set'' extension is unsuitable for assigning a
list result to a number of variables element by element.  However, its
simplicity and consistency to other similar Tcl commands is appealing.

~ Reference Implementation

A patch to Tcl 8.4a3 which implements the ''set'' extension may be
found at http://anselm.our-isp.org/set-patch.diff - a patched Tcl
8.4a3 passes the Tcl 8.4a3 regression test suite with no test
failures.  No test cases nor documentation for the ''set'' extensions
have been devised yet but this is easy to do once there is a consensus
that this feature is actually desirable.

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|

|


|

|
|



|

|

|

|


|

|
|


|
|

|

|

|
|
|
|
|


|
|
|

|
|

|

|

|
|

|
|


|
|



|

|
|

|



|


>

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

# TIP 58: Extend [set] to Assign Multiple Values to Multiple Variables

	Author:         Anselm Lingnau <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        02-Sep-2001
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes a multiple assignment command as a
backwards-compatible extension to the Tcl _set_ command.

# Introduction

Often one needs to assign values to several variables in close
proximity.  Right now several _set_ commands are necessary:

	  set a 123
	  set b 456

or

	  set a 123; set b 456

Or one abuses the _foreach_ command:

	  foreach {a b} {123 456} break

However, by analogy to the _variable_ and _array set_ commands,
the following would be useful:

	  set a 123 b 456

This would assign 123 to the variable _a_ and 456 to the variable
_b_.

Note that this extension is backwards-compatible to existing uses of
the _set_ command since until now only one or two arguments to
_set_ were allowed.

# Specification

The _set_ command is extended to allow either one or an even number
of arguments.  The behaviour in the case of one argument remains the
one documented in the _set_ manual page; when an even number of
arguments is specified, the behaviour of _set v0 e0 ... vn en_ is
identical to that of the sequence of commands _set v0 e0; ...; set vn
en_ according to the traditional semantics, except that the way
Tcl processes commands means that _e0_ ... _en_ are all
evaluated before any assignments are performed. I.e., the commands

	  set a 1
	  set a 2 b $a
	  puts $b

print _1_, not _2_. If this is an issue you must use separate
_set_ statements.

The command _set v0 e0 ... vn en_ returns the value of _en_.

# Rationale

This extension is an obvious analogy to the _variable_ and _array
set_ commands of Tcl, both of which allow an alternating list of
names and expressions to be given as arguments.  It is completely
backwards-compatible \(_set_ invocations with more than two arguments
used to be syntax errors\) and very easily implemented.

This extension in no way prejudices against the adoption and use of
other multiple-assignment commands, such as _lassign_ \(see [[57]](57.md)\).
In particular, the _set_ extension is unsuitable for assigning a
list result to a number of variables element by element.  However, its
simplicity and consistency to other similar Tcl commands is appealing.

# Reference Implementation

A patch to Tcl 8.4a3 which implements the _set_ extension may be
found at <http://anselm.our-isp.org/set-patch.diff> - a patched Tcl
8.4a3 passes the Tcl 8.4a3 regression test suite with no test
failures.  No test cases nor documentation for the _set_ extensions
have been devised yet but this is easy to do once there is a consensus
that this feature is actually desirable.

# Copyright

This document is placed in the public domain.

Name change from tip/59.tip to tip/59.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352

TIP:            59
Title:          Embed Build Information in Tcl Binary Library
Version:        $Revision: 1.16 $
Author:         Andreas Kupries <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        04-Sep-2001
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP provides an interface through which Tcl may be queried for
information on its own configuration, in order to
extract the information directly instead of reading it from a Bourne
shell file.  An important reason to do this is to have the information
not only available but also tightly bound to the binary configured by
it, so that the information doesn't get lost.

~ Foreword

This TIP proposes a rather small change to Tcl and tries very hard to
follow the KISS principle. Given that the casual observer might find
it rather long, be assured, the actual specification in here is not
very long, nor complicated. Most of the following explanations were
added to preserve the KISS principle and head off attempts to extend
the TIP beyond its small goal and scope.

Note: All instances of "Tcl library" in the following text refer to
the generated installable library and not the script library coming
with the core.

~ Background and Rationale

The main reason for writing this TIP are the disadvantages inherent in
the current way of storing the configuration of Tcl, namely in the file
''tclConfig.sh''.

   * It is a separate file, easily lost or not installed at all,
     making it difficult for extension developers to access this
     information.

   > Note: The non-installation of development files like ''tclConfig.sh''
     might even be required by through vendor policies and such and
     thus not under the control of the package author or builder.

   * The name does not convey that ''tclConfig.sh'' contains platform
     and build specific information. When installing different builds
     this usually leads to clashes. This makes it again difficult for
     extension developers to find the right file for their current build.

   * Not every extension generates such a file for use by other
     extensions.

Thus, this TIP proposes:

   * an extension of the public API so that extensions are able to
     define configuration introspection commands and to declare the
     returned information during initialization with the information
     embedded into their installable libraries during compilation.

   * to embed the information about the configuration of the
     Tcl library as strings into the generated installable library and
     make them accessible at the script level through Tcl variables,
     thus allowing developers on any platform Tcl compiles on to
     access this information.

The file ''tclConfig.sh'' is ''not'' replaced by this system, both
sets of information exist in parallel.

Neither is the variable ''tcl_platform'' replaced. This means that some information, like ''threaded'', is held redundantly. Other information in ''tcl_platform'', like ''user'' is runtime and not configuration information. The operating system information is important to a build system, but this is out of the scope of this TIP.

~ Interface Specification

Any embedded information is made accessible at the Tcl level through a
new command. The name of the command used by Tcl itself is
''::tcl::pkgconfig''. Extensions have to use their own commands. These
commands will be named ''pkgconfig'' too and have to be placed within in
the namespaces owned by the extensions initializing them.

At the C-level the public API of the Tcl core is extended with a
single function to register the embedded configuration information.
This function is added to the public stub table of the Tcl core so
that it can be used by Tcl and extensions to register their own
configuration information in the system during initialization.

The function takes three (3) arguments; first, the name of the package
registering its configuration information, second, a pointer to an
array of structures, and third a string declaring the encoding used by
the configuration values.  Each element of the array refers to two
strings containing the key and the value associated with that key. The
end of the array is signaled by an empty key.

Formalized, name and signature of this new function are

| Tcl_RegisterConfig (CONST char* pkgName, Config* configuration, CONST char* valEncoding)
|
| typedef struct Config {
|    char* key;
|    char* value;
| }


The string ''valEncoding'' contains the name of an encoding known to
Tcl. All these names are use only characters in the ASCII subset of
UTF-8 and are thus implicity in the UTF-8 encoding. It is expected
that keys are legible english text and therefore using the ASCII
subset of UTF-8. In other words, they are expected to be in UTF-8
too. The values associated with the keys can be any string
however. For these the contents of ''valEncoding'' define which
encoding was used to represent the characters of the strings.

During compile time the value of ''valEncoding'' is specified as a
makefile variable for non-''configure'' based build systems and
through the new option ''--with-encoding=FOO'' of configure
otherwise. The default value is ''iso8859-1''.

This approach gives us all what we desire with not too many drawbacks.

   * The default case (no special characters) requires no action on
     part of the builder at all.

   * The non-default case (path containing special characters like
     Kanji) is supported.

   * Cross-compilation is unimpeded and no more complex than normal
     compilation.

   * The requirement for conversion of strings is a drawback, but
     should not have a big impact on performance. It has no impact on
     the performance of scripts which do not use the embedded
     information. The impact is even more negligigble if the result of
     the conversion is cached.

The function will

   * create a namespace having the provided ''pkgName'', if not yet existing.

   * create the command ''pkgconfig'' in that namespace and link it
     to the provided information so that the keys from
     ''configuration'' and their associated values can be retrieved through
     calls to ''pkgconfig''.

The command ''pkgconfig'' will provide two subcommands, ''list'' and
''get''. The first subcommand, ''list'' takes no arguments and returns
a list containing the names of the defined keys. The second subcommand
takes one argument, the name of a key and returns the string
associated with that key.

~ How to Gather the Embedded Information

The information to be embedded is gathered in a platform-specific way
and written into the file ''generic/tclPkgConfig.c''. The different
platforms may employ platform specific intermediate files to hold the
information, but in the compilation phase only ''tclPkgConfig.c'' will
be used.

   * Under unix it is determined primarily by the existing
     ''configure'' script. The configuration information coming
     from the Makefile, or from other compile time means, is
     embedded into the ''tclConfig.c'' file by means of
    preprocessor statements (#ifdef ... #endif).

   * For the Windows and Mac platforms volunteers may have to create
     files ''tclWinConfig.c.some-ext'' containing this information for
     each supported build environment, like VC++, Borland, Cygwin,
     etc.

   > ''tclWinConfig.c.vc'' = VC++.

   > ''tclWinConfig.c.bc'' = Borland.

   > ''tclWinConfig.c.in'' = Cygwin. ''.in'' is used because Cygwin
     can use configure to determine the values and embed them into a
     template.

   * As for other platforms, these are handled either like Unix or
     like Mac, depending on the availability and usability of
     ''configure''.

   > Volunteers are required to write the appropriate files for their
     build environment.

~ Specification of Tcl Configuration Information

The configuration information registered by Tcl itself is specified
here. A discussion of the choices made here follows in the next
section. Please read this discussion before commenting on the
specification.

The values associated with the keys below are all of one of the
following types:

   * Boolean flag. Allowed values are all the values which are
     accepted by Tcl itself. Examples are:

|       true, false, on, off, 1, 0

   * String. General container for all other information.

   * Templated string. With respect to placeholders in the same format
     as 'Script' below, but does not have to be a valid Tcl script.

   * Script. A string containing a full Tcl script. The user should
     handle this string like a procedure body. The script is allowed
     to contain placeholders to be filled by the user of the string.
     Placeholders follow the syntax of full-braced Tcl variables,
     i.e. ''${some_name}'. The actual values can be filled in by the
     user of the configuration information. Possible ways to do so are
     [regsub], [string map] or [subst -nocommand]. The best way
     however would be to use the script as a procedure body, with the
     placeholders as the arguments of the procedure. This will avoid
     many problems regarding bracing and the protection of special
     characters.

   > Which placeholders are possible for a particular script or
     template is described together with the meaning of the key.

   > Beyond the placeholders a script or templated string is allowed
     to contain references to other keys returned by the ''config''
     command. These references use the same variable syntax as the
     placeholders.

The registered keys follow below. They will be always present with
some value. Non-boolean keys not applicable to a particular platform
will contain the empty string as their value.

   * Configuration of Tcl itself:

   >   * ''debug''. Boolean flag. Set to false if Tcl was not compiled
         to contain debugging information.

   >   * ''threaded''. Boolean flag. Set to false if Tcl was not
         compiled as thread-enabled.

   >   * ''profiled''. Boolean flag. Set to false if Tcl was not
         compiled to contain profiling statements.

   >   * ''64bit''. Boolean flag. Set to false if Tcl was not compiled
         in 64bit mode.

   >   * ''optimized''. Boolean flag. Set to false if Tcl was compiled
         without compiler optimizations.

   >   * ''mem_debug''. Boolean flag. Set to false if Tcl has no
         memory debugging compiled into it.

   >   * ''compile_debug''. Boolean flag. Set to false if Tcl has no
         bytecode compiler debugging compiled in.

   >   * ''compile_stats''. Boolean flag. Set to false if Tcl has no
         bytecode compiler statistics compiled in.

   * Installation configuration of Tcl. In other words, various
     important locations.

   >   * ''prefix,runtime''.  String. The directory for platform
         independent files as seen by the interpreter during runtime.

   >   * ''exec_prefix,runtime'' String. The directory for platform
         dependent files as seen by the interpreter during runtime.

   >   * ''prefix,install''. String. The directory for platform
         independent files as seen by the installer at install-time.

   >   * ''exec_prefix,install''. String. The directory for platform
         dependent files as seen by the installer at install-time.

~ Discussion

The placement of this information into a separate package was proposed
but rejected because of the trouble of finding the right information
for the right library in the case of multiple configurations installed
into the same directory space.  Embedding into the library does not
cost much space and binds the information tightly to the right spot.

Another reason to do it this way is that this enables us to embed
information coming from the Makefile itself (like ''MEM_DEBUG'') or
from other compile time means. This would not be possible for a file
generated solely by the Tcl configure. It would also restrict the
embedding to the platforms which allow the use of ''configure''
script.

The usage of a separate package to just access the information placed
into the Tcl library was also proposed. This was rejected too, due to
the overhead for the management of the package in comparison to the
small size of the code actually involved.

Another proposal rejected in the early discussions was to have this
TIP define an entire build system based upon Tcl. This TIP is
certainly a step in this direction and facilitates the building of
such a build system (sic!). Still, specifying such here was seen as
too large a step right now, with too many issues to be solved and thus
delaying the implementation of this TIP.

Only the configuration of the particular variant of the Tcl library or
extension which was generated is recorded in the library. No attempt
is made to record the information required to allow the compilation of
any possible variant of an extension. Doing so would reach again into
the bigger topic of specifying a full build system. We've already
established that as being out of the intended scope of this TIP.

Note further that the scheme as specified above does not prevent us
from adding the full information in a later stage. In other words, it
does not restrict the development of a more powerful system in the
future.

This should be enough reasoning to allow the acceptance of even this
admittedly simple system.

The configuration information registered by Tcl is currently a very
small subset of the information in ''tclConfig.sh''. A future TIP is
planned to provide the missing information in a regular and generalized
manner.

If an extension requires more information than provided by the Tcl
configuration it will have to obtain this information itself. For
instance, TclBlend requires a CLASSPATH, the name of a Java compiler,
etc. whereas the TclPython and TclPerl extensions require paths to
those environments, etc. It is not reasonable that the configure
script for Tcl itself have to accommodate all requirements of all
extensions of Tcl.  Instead, the configure scripts or whatever other
means is used to obtain the configuration information for the
extensions should reflect their needs, and register the requirements
gathered into their own configuration command. Note that an extension
is only expected to create variables for information unique to
it. Everything else can be had from the configuration command of Tcl
and the extensions it depends on.

This TIP is not in opposition to [34] but rather fleshes out one of
the many details in the specification which were left open by that
TIP.

This TIP also does not propose to change the process for building Tcl
itself. The goal is rather to make the building of extensions easier
in the future.

A naming convention for keys returned by the ''config'' command would
have been possible but would also require quite a lot more text, both
in careful definition of the general categories and in explanations of
the choices made.

~ Implementation

Work on implementing this feature is tracked at Tcl Patch 507083 at
the Tcl project at SourceForge.  Implementation effort also takes
place on the tip-59-implementation branch in the Tcl CVS repository
(see [31]).

~ Copyright

This document is in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|








|












|



|





|



|




















|


|

|



|
|








|








|
|
|
|
|
<
|
>
|





|


|
|
|
|



|


|
|












|

|

|
|

|
|




|


|

|



|

|
|


|
|


|

|

|





|

|


|












|










|







|


|
|









|


|


|


|


|


|


|


|





|


|


|


|


|








|


|










|



















|

















|







|




|




|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352

# TIP 59: Embed Build Information in Tcl Binary Library

	Author:         Andreas Kupries <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        04-Sep-2001
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP provides an interface through which Tcl may be queried for
information on its own configuration, in order to
extract the information directly instead of reading it from a Bourne
shell file.  An important reason to do this is to have the information
not only available but also tightly bound to the binary configured by
it, so that the information doesn't get lost.

# Foreword

This TIP proposes a rather small change to Tcl and tries very hard to
follow the KISS principle. Given that the casual observer might find
it rather long, be assured, the actual specification in here is not
very long, nor complicated. Most of the following explanations were
added to preserve the KISS principle and head off attempts to extend
the TIP beyond its small goal and scope.

Note: All instances of "Tcl library" in the following text refer to
the generated installable library and not the script library coming
with the core.

# Background and Rationale

The main reason for writing this TIP are the disadvantages inherent in
the current way of storing the configuration of Tcl, namely in the file
_tclConfig.sh_.

   * It is a separate file, easily lost or not installed at all,
     making it difficult for extension developers to access this
     information.

	   > Note: The non-installation of development files like _tclConfig.sh_
     might even be required by through vendor policies and such and
     thus not under the control of the package author or builder.

   * The name does not convey that _tclConfig.sh_ contains platform
     and build specific information. When installing different builds
     this usually leads to clashes. This makes it again difficult for
     extension developers to find the right file for their current build.

   * Not every extension generates such a file for use by other
     extensions.

Thus, this TIP proposes:

   * an extension of the public API so that extensions are able to
     define configuration introspection commands and to declare the
     returned information during initialization with the information
     embedded into their installable libraries during compilation.

   * to embed the information about the configuration of the
     Tcl library as strings into the generated installable library and
     make them accessible at the script level through Tcl variables,
     thus allowing developers on any platform Tcl compiles on to
     access this information.

The file _tclConfig.sh_ is _not_ replaced by this system, both
sets of information exist in parallel.

Neither is the variable _tcl\_platform_ replaced. This means that some information, like _threaded_, is held redundantly. Other information in _tcl\_platform_, like _user_ is runtime and not configuration information. The operating system information is important to a build system, but this is out of the scope of this TIP.

# Interface Specification

Any embedded information is made accessible at the Tcl level through a
new command. The name of the command used by Tcl itself is
_::tcl::pkgconfig_. Extensions have to use their own commands. These
commands will be named _pkgconfig_ too and have to be placed within in
the namespaces owned by the extensions initializing them.

At the C-level the public API of the Tcl core is extended with a
single function to register the embedded configuration information.
This function is added to the public stub table of the Tcl core so
that it can be used by Tcl and extensions to register their own
configuration information in the system during initialization.

The function takes three \(3\) arguments; first, the name of the package
registering its configuration information, second, a pointer to an
array of structures, and third a string declaring the encoding used by
the configuration values.  Each element of the array refers to two
strings containing the key and the value associated with that key. The
end of the array is signaled by an empty key.

Formalized, name and signature of this new function are

	 Tcl_RegisterConfig (CONST char* pkgName, Config* configuration, CONST char* valEncoding)
	
	 typedef struct Config {
	    char* key;
	    char* value;

	 }

The string _valEncoding_ contains the name of an encoding known to
Tcl. All these names are use only characters in the ASCII subset of
UTF-8 and are thus implicity in the UTF-8 encoding. It is expected
that keys are legible english text and therefore using the ASCII
subset of UTF-8. In other words, they are expected to be in UTF-8
too. The values associated with the keys can be any string
however. For these the contents of _valEncoding_ define which
encoding was used to represent the characters of the strings.

During compile time the value of _valEncoding_ is specified as a
makefile variable for non-_configure_ based build systems and
through the new option _--with-encoding=FOO_ of configure
otherwise. The default value is _iso8859-1_.

This approach gives us all what we desire with not too many drawbacks.

   * The default case \(no special characters\) requires no action on
     part of the builder at all.

   * The non-default case \(path containing special characters like
     Kanji\) is supported.

   * Cross-compilation is unimpeded and no more complex than normal
     compilation.

   * The requirement for conversion of strings is a drawback, but
     should not have a big impact on performance. It has no impact on
     the performance of scripts which do not use the embedded
     information. The impact is even more negligigble if the result of
     the conversion is cached.

The function will

   * create a namespace having the provided _pkgName_, if not yet existing.

   * create the command _pkgconfig_ in that namespace and link it
     to the provided information so that the keys from
     _configuration_ and their associated values can be retrieved through
     calls to _pkgconfig_.

The command _pkgconfig_ will provide two subcommands, _list_ and
_get_. The first subcommand, _list_ takes no arguments and returns
a list containing the names of the defined keys. The second subcommand
takes one argument, the name of a key and returns the string
associated with that key.

# How to Gather the Embedded Information

The information to be embedded is gathered in a platform-specific way
and written into the file _generic/tclPkgConfig.c_. The different
platforms may employ platform specific intermediate files to hold the
information, but in the compilation phase only _tclPkgConfig.c_ will
be used.

   * Under unix it is determined primarily by the existing
     _configure_ script. The configuration information coming
     from the Makefile, or from other compile time means, is
     embedded into the _tclConfig.c_ file by means of
    preprocessor statements \(\#ifdef ... \#endif\).

   * For the Windows and Mac platforms volunteers may have to create
     files _tclWinConfig.c.some-ext_ containing this information for
     each supported build environment, like VC\+\+, Borland, Cygwin,
     etc.

	   > _tclWinConfig.c.vc_ = VC\+\+.

	   > _tclWinConfig.c.bc_ = Borland.

	   > _tclWinConfig.c.in_ = Cygwin. _.in_ is used because Cygwin
     can use configure to determine the values and embed them into a
     template.

   * As for other platforms, these are handled either like Unix or
     like Mac, depending on the availability and usability of
     _configure_.

	   > Volunteers are required to write the appropriate files for their
     build environment.

# Specification of Tcl Configuration Information

The configuration information registered by Tcl itself is specified
here. A discussion of the choices made here follows in the next
section. Please read this discussion before commenting on the
specification.

The values associated with the keys below are all of one of the
following types:

   * Boolean flag. Allowed values are all the values which are
     accepted by Tcl itself. Examples are:

		       true, false, on, off, 1, 0

   * String. General container for all other information.

   * Templated string. With respect to placeholders in the same format
     as 'Script' below, but does not have to be a valid Tcl script.

   * Script. A string containing a full Tcl script. The user should
     handle this string like a procedure body. The script is allowed
     to contain placeholders to be filled by the user of the string.
     Placeholders follow the syntax of full-braced Tcl variables,
     i.e. _$\{some\_name\}'. The actual values can be filled in by the
     user of the configuration information. Possible ways to do so are
     [regsub], [string map] or [subst -nocommand]. The best way
     however would be to use the script as a procedure body, with the
     placeholders as the arguments of the procedure. This will avoid
     many problems regarding bracing and the protection of special
     characters.

	   > Which placeholders are possible for a particular script or
     template is described together with the meaning of the key.

	   > Beyond the placeholders a script or templated string is allowed
     to contain references to other keys returned by the _config_
     command. These references use the same variable syntax as the
     placeholders.

The registered keys follow below. They will be always present with
some value. Non-boolean keys not applicable to a particular platform
will contain the empty string as their value.

   * Configuration of Tcl itself:

	   >   \* _debug_. Boolean flag. Set to false if Tcl was not compiled
         to contain debugging information.

	   >   \* _threaded_. Boolean flag. Set to false if Tcl was not
         compiled as thread-enabled.

	   >   \* _profiled_. Boolean flag. Set to false if Tcl was not
         compiled to contain profiling statements.

	   >   \* _64bit_. Boolean flag. Set to false if Tcl was not compiled
         in 64bit mode.

	   >   \* _optimized_. Boolean flag. Set to false if Tcl was compiled
         without compiler optimizations.

	   >   \* _mem\_debug_. Boolean flag. Set to false if Tcl has no
         memory debugging compiled into it.

	   >   \* _compile\_debug_. Boolean flag. Set to false if Tcl has no
         bytecode compiler debugging compiled in.

	   >   \* _compile\_stats_. Boolean flag. Set to false if Tcl has no
         bytecode compiler statistics compiled in.

   * Installation configuration of Tcl. In other words, various
     important locations.

	   >   \* _prefix,runtime_.  String. The directory for platform
         independent files as seen by the interpreter during runtime.

	   >   \* _exec\_prefix,runtime_ String. The directory for platform
         dependent files as seen by the interpreter during runtime.

	   >   \* _prefix,install_. String. The directory for platform
         independent files as seen by the installer at install-time.

	   >   \* _exec\_prefix,install_. String. The directory for platform
         dependent files as seen by the installer at install-time.

# Discussion

The placement of this information into a separate package was proposed
but rejected because of the trouble of finding the right information
for the right library in the case of multiple configurations installed
into the same directory space.  Embedding into the library does not
cost much space and binds the information tightly to the right spot.

Another reason to do it this way is that this enables us to embed
information coming from the Makefile itself \(like _MEM\_DEBUG_\) or
from other compile time means. This would not be possible for a file
generated solely by the Tcl configure. It would also restrict the
embedding to the platforms which allow the use of _configure_
script.

The usage of a separate package to just access the information placed
into the Tcl library was also proposed. This was rejected too, due to
the overhead for the management of the package in comparison to the
small size of the code actually involved.

Another proposal rejected in the early discussions was to have this
TIP define an entire build system based upon Tcl. This TIP is
certainly a step in this direction and facilitates the building of
such a build system \(sic!\). Still, specifying such here was seen as
too large a step right now, with too many issues to be solved and thus
delaying the implementation of this TIP.

Only the configuration of the particular variant of the Tcl library or
extension which was generated is recorded in the library. No attempt
is made to record the information required to allow the compilation of
any possible variant of an extension. Doing so would reach again into
the bigger topic of specifying a full build system. We've already
established that as being out of the intended scope of this TIP.

Note further that the scheme as specified above does not prevent us
from adding the full information in a later stage. In other words, it
does not restrict the development of a more powerful system in the
future.

This should be enough reasoning to allow the acceptance of even this
admittedly simple system.

The configuration information registered by Tcl is currently a very
small subset of the information in _tclConfig.sh_. A future TIP is
planned to provide the missing information in a regular and generalized
manner.

If an extension requires more information than provided by the Tcl
configuration it will have to obtain this information itself. For
instance, TclBlend requires a CLASSPATH, the name of a Java compiler,
etc. whereas the TclPython and TclPerl extensions require paths to
those environments, etc. It is not reasonable that the configure
script for Tcl itself have to accommodate all requirements of all
extensions of Tcl.  Instead, the configure scripts or whatever other
means is used to obtain the configuration information for the
extensions should reflect their needs, and register the requirements
gathered into their own configuration command. Note that an extension
is only expected to create variables for information unique to
it. Everything else can be had from the configuration command of Tcl
and the extensions it depends on.

This TIP is not in opposition to [[34]](34.md) but rather fleshes out one of
the many details in the specification which were left open by that
TIP.

This TIP also does not propose to change the process for building Tcl
itself. The goal is rather to make the building of extensions easier
in the future.

A naming convention for keys returned by the _config_ command would
have been possible but would also require quite a lot more text, both
in careful definition of the general categories and in explanations of
the choices made.

# Implementation

Work on implementing this feature is tracked at Tcl Patch 507083 at
the Tcl project at SourceForge.  Implementation effort also takes
place on the tip-59-implementation branch in the Tcl CVS repository
\(see [[31]](31.md)\).

# Copyright

This document is in the public domain.

Name change from tip/6.tip to tip/6.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

TIP:            6
Title:          Include [Incr Tcl] in the Core Tcl distribution
Version:        $Revision: 1.6 $
Author:         Mark Harrison <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        16-Oct-2000
Post-History:   
Tcl-Version:    8.4.0


~ Abstract

Include [[Incr Tcl]] in the Core Tcl distribution.

~ Proposal

[[incr Tcl]] [http://tcltk.com/itcl/] shall be included in the core
Tcl distribution.  It shall be included in the Tcl source tree, and
built as part of the standard Tcl distribution.

Specific items:

 *  "itclsh" will not be included

 *  "itcl_*" commands will not be included

 *  everything will move from ::itcl to ::

 *  the "find" subcommands will be reintegrated into "info"

~ Rationale

The lack of a standard object and data abstraction system continues to
hinder Tcl development.

  > "Lets face it, not including any sort of OO system is one of
    the major failings of Tcl. Indexing into global arrays is
    a sad hack when compared to a real OO system."
           ''- Mo DeJong <[email protected]>''

Earlier this year, it seemed that it would finally be included in Tcl
8.4, but that plan was rescinded.

Note that this is distinct from the "batteries included" (BI)
distribution, and is not intended to be a model for building the BI
distribution.  It is a special case for inclusion in the core tcl
command set, since a "class" command is a fundamental language
construct.

~ Alternatives

Include [[incr Tcl]] in a "batteries included" (BI) distribution.

Many people will not opt for the BI distribution ([4]) due to its
larger size.  It is quite likely that (for example) a Linux
distribution my include Tcl as a standard component, but place the BI
on a supplemental disk.

~ Objections

''I don't want any object system included!''

You can delete the [[incr Tcl]] library with no harm to your code.

''John Ousterhout hates objects!''

This misconception is primarily due to a misreading of one of his
papers.  A better summary of his position is that "scripting is a
better solution than objects in many cases."  John Ousterhout has told
me that he will not stand in the way of adding object-oriented
programming to Tcl.

''[[incr Tcl]]'s object model is not good!''

[[incr Tcl]] supports the same object model as C++ and Java.  Many
programmers are familiar with this model and accept it as a good
model.

''The CLOS object model is better!''

Quoting John Ousterhout, "People vote with their feet".  For whatever
reason, slot-based systems failed to gain as much popularity as
C++/Java-like systems.

''There are many Tcl object systems to choose from!''

None are even a fraction as long-lived, popular, or well-supported as
[[incr Tcl]].

~ Special Provisions

Since [[incr Tcl]] still exists as a separately named entity, this TIP
shall not be construed as relieving any individual from the
responsibility of providing appropriate [[incr Apparel]].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|

|

|







|





|







|




|





|

|

|
|



|

|

|

|







|

|



|



|

|


|

|

|

|

|


>

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

# TIP 6: Include [Incr Tcl] in the Core Tcl distribution

	Author:         Mark Harrison <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        16-Oct-2000
	Post-History:   
	Tcl-Version:    8.4.0
-----

# Abstract

Include [Incr Tcl] in the Core Tcl distribution.

# Proposal

[incr Tcl] <http://tcltk.com/itcl/>  shall be included in the core
Tcl distribution.  It shall be included in the Tcl source tree, and
built as part of the standard Tcl distribution.

Specific items:

 *  "itclsh" will not be included

 *  "itcl\_\*" commands will not be included

 *  everything will move from ::itcl to ::

 *  the "find" subcommands will be reintegrated into "info"

# Rationale

The lack of a standard object and data abstraction system continues to
hinder Tcl development.

  > "Lets face it, not including any sort of OO system is one of
    the major failings of Tcl. Indexing into global arrays is
    a sad hack when compared to a real OO system."
           _- Mo DeJong <[email protected]>_

Earlier this year, it seemed that it would finally be included in Tcl
8.4, but that plan was rescinded.

Note that this is distinct from the "batteries included" \(BI\)
distribution, and is not intended to be a model for building the BI
distribution.  It is a special case for inclusion in the core tcl
command set, since a "class" command is a fundamental language
construct.

# Alternatives

Include [incr Tcl] in a "batteries included" \(BI\) distribution.

Many people will not opt for the BI distribution \([[4]](4.md)\) due to its
larger size.  It is quite likely that \(for example\) a Linux
distribution my include Tcl as a standard component, but place the BI
on a supplemental disk.

# Objections

_I don't want any object system included!_

You can delete the [incr Tcl] library with no harm to your code.

_John Ousterhout hates objects!_

This misconception is primarily due to a misreading of one of his
papers.  A better summary of his position is that "scripting is a
better solution than objects in many cases."  John Ousterhout has told
me that he will not stand in the way of adding object-oriented
programming to Tcl.

_[incr Tcl]'s object model is not good!_

[incr Tcl] supports the same object model as C\+\+ and Java.  Many
programmers are familiar with this model and accept it as a good
model.

_The CLOS object model is better!_

Quoting John Ousterhout, "People vote with their feet".  For whatever
reason, slot-based systems failed to gain as much popularity as
C\+\+/Java-like systems.

_There are many Tcl object systems to choose from!_

None are even a fraction as long-lived, popular, or well-supported as
[incr Tcl].

# Special Provisions

Since [incr Tcl] still exists as a separately named entity, this TIP
shall not be construed as relieving any individual from the
responsibility of providing appropriate [incr Apparel].

# Copyright

This document has been placed in the public domain.

Name change from tip/60.tip to tip/60.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
136
137
138
139
140
141
142
143
144
145
146

147
148
149
150

151
152
153
154
155
156
157
158
159
160

161
162
163
164

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

TIP:            60
Title:          EXTERN Macro Change to Support a Wider Set of Attributes
Version:        $Revision: 1.21 $
Author:         David Gravereaux <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        06-Sep-2001
Post-History:   
Tcl-Version:    8.6


~ Abstract

This TIP proposes a change to how the EXTERN macro in ''tcl.h'' works
to support a wider range of compiler specific attributes.

~ Rationale

With working on Borland support recently, I found that luckily the
newest "free commandline tools"
[http://www.borland.com/bcppbuilder/freecompiler/] does support
Microsoft's ''__declspec(dllexport)'' attribute.  But at the same
time, the older way with ''__export'' is still valid, but can't be
used due to the order within the prototype declaration of the EXTERN
macro.

What's this with the MS compiler:

|	__declspec(dllexport) __cdecl int func (int a, int b);

will have to be this with Borland:

|	int __export __cdecl func (int a, int b);

The order of the attribute needs to be after the return type.

Even though ''__declspec'' is supported in the Microsoft style with
version 5.5+ of the Borland compiler, if EXTERN could swap around the
order a hair, old Turbo C v5.0 has a better chance to make a DOS
library.  Should someone feel the need.

Let's leave the existing EXTERN macro as-is and just make a new one called TCL_EXTERN to support the new behavior.

Karl Lembuaer (sp?) did a presentation @ OSCON regarding his recent
tinytcl project ''%TODO: add link here%'' about his DOS port of Tcl
6.7 for use in a hand-held device.

Stepping backward for DOS support, may actually be a leap forward in
an off-beat manner...

~ Rejected Alternatives

I saw something like this in a very old DDE extension that someone at
Sun wrote.  It was used as an example windows extension for years.

ftp://tcl.activestate.com/pub/tcl/misc/example.zip

In example.h is this:

|#if defined(__WIN32__)
|#   if defined(_MSC_VER)
|#	define EXPORT(a,b) __declspec(dllexport) a b
|#   else
|#	if defined(__BORLANDC__)
|#	    define EXPORT(a,b) a _export b
|#	else
|#	    define EXPORT(a,b) a b
|#	endif
|#   endif
|#else
|#   define EXPORT(a,b) a b
|#endif
|
|EXTERN EXPORT(int,Example_Init) _ANSI_ARGS_((Tcl_Interp *interp));

That work is doing the same job, but I prefer the method that I'm
proposing.

It is also mentioned on http://tcl.activestate.com/doc/howto/winext.html
and feel it is rather out-of-date and the order issue with ''__export''
should be brought into the core with this patch and be fix for good.

Is>

|	EXTERN int Foobar_Init (Tcl_Interp *interp);

Proposed>

|	TCL_EXTERN(int) Foobar_Init (Tcl_Interp *interp);

~ Reference Implementation

https://sourceforge.net/tracker/download.php?group_id=10894&atid=310894&file_id=70480&aid=436116

~ Examples

Is:

|EXTERN int
|Foobar_Init (Tcl_Interp *interp)
|{

|#ifdef USE_TCL_STUBS
|    if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
|        return TCL_ERROR;
|    }

|#endif
|    Tcl_CreateObjCommand(interp, "foobar", FooBar, NULL, NULL);
|    return TCL_OK;
|};

Proposed:

|TCL_EXTERN(int)
|Foobar_Init (Tcl_Interp *interp)
|{

|#ifdef USE_TCL_STUBS
|    if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
|        return TCL_ERROR;
|    }

|#endif
|    Tcl_CreateObjCommand(interp, "foobar", FooBar, NULL, NULL);
|    return TCL_OK;
|};

Preprocessor output is the following:

 >	Borland:

|/* foobar.c 14: */extern  int __export
|/* foobar.c 15: */Foobar_Init (Tcl_Interp *interp)
|/* foobar.c 16: */{
|/* foobar.c 17: */
|/* foobar.c 18: */if (Tcl_InitStubs(interp, "8.1", 0) == 0) {
|/* foobar.c 19: */return 1;
|/* foobar.c 20: */}
|/* foobar.c 21: */
|/* foobar.c 22: */(tclStubsPtr->tcl_CreateObjCommand)(interp, "foobar", FooBar, 0, 0);
|/* foobar.c 23: */return 0;
|/* foobar.c 24: */};

 >	VC++:

|extern  __declspec(dllexport) int
|Foobar_Init (Tcl_Interp *interp)
|{

|
|    if (Tcl_InitStubs(interp, "8.1", 0) == ((void *)0)) {
|        return 1;
|    }

|#line 22 "foobar.c"
|    (tclStubsPtr->tcl_CreateObjCommand)(interp, "foobar", FooBar, ((void *)0), ((void *)0));
|    return 0;
|};

 >	MinGW (native gcc on win):

|extern       int
|Foobar_Init (Tcl_Interp *interp)
|{

|
|    if (Tcl_InitStubs(interp, "8.1", 0) == ((void *)0) ) {
|        return 1 ;
|    }

|
|    (tclStubsPtr->tcl_CreateObjCommand) (interp, "foobar", FooBar, ((void *)0) , ((void *)0) );
|    return 0 ;
|};

~ Random Notes

In ''tclInt.h'' starting around line 1916, are prototypes for the
internal cmdprocs.  I can't think of any reason why they should be
exported.  Also note the comment about line:1673, as it states:

|/*
| *----------------------------------------------------------------
| * Procedures shared among Tcl modules but not used by the outside
| * world:
| *----------------------------------------------------------------
| */

As the current EXTERN macro places ""everything"" exportable, the use of EXTERN following this comment in ''tclInt.h'' is contradictory.  In place of EXTERN for this purpose I used the new TCL_EXTRNC in the reference implementation.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|



|
|
|





|



|



|
|



|

|
|





|








|
|
|
|
|
|
|
|
|
|
|
|
|
|
|




|
|




|



|

|

|

|



|
|
<
>
|
|
|
<
>
|
|
|
|



|
|
<
>
|
|
|
<
>
|
|
|
|





|
|
|
|
|
|
|
|
|
|
|

|

|
|
<
>
|
|
|
<
>
|
|
|
|

|

|
|
<
>
|
|
|
<
>
|
|
|
|

|

|



|
|
|
|
|
|

|

|


>

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
136
137
138
139
140
141
142
143
144

145
146
147
148

149
150
151
152
153
154
155
156
157
158

159
160
161
162

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

# TIP 60: EXTERN Macro Change to Support a Wider Set of Attributes

	Author:         David Gravereaux <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        06-Sep-2001
	Post-History:   
	Tcl-Version:    8.6
-----

# Abstract

This TIP proposes a change to how the EXTERN macro in _tcl.h_ works
to support a wider range of compiler specific attributes.

# Rationale

With working on Borland support recently, I found that luckily the
newest "free commandline tools"
<http://www.borland.com/bcppbuilder/freecompiler/>  does support
Microsoft's _\_\_declspec\(dllexport\)_ attribute.  But at the same
time, the older way with _\_\_export_ is still valid, but can't be
used due to the order within the prototype declaration of the EXTERN
macro.

What's this with the MS compiler:

		__declspec(dllexport) __cdecl int func (int a, int b);

will have to be this with Borland:

		int __export __cdecl func (int a, int b);

The order of the attribute needs to be after the return type.

Even though _\_\_declspec_ is supported in the Microsoft style with
version 5.5\+ of the Borland compiler, if EXTERN could swap around the
order a hair, old Turbo C v5.0 has a better chance to make a DOS
library.  Should someone feel the need.

Let's leave the existing EXTERN macro as-is and just make a new one called TCL\_EXTERN to support the new behavior.

Karl Lembuaer \(sp?\) did a presentation @ OSCON regarding his recent
tinytcl project _%TODO: add link here%_ about his DOS port of Tcl
6.7 for use in a hand-held device.

Stepping backward for DOS support, may actually be a leap forward in
an off-beat manner...

# Rejected Alternatives

I saw something like this in a very old DDE extension that someone at
Sun wrote.  It was used as an example windows extension for years.

ftp://tcl.activestate.com/pub/tcl/misc/example.zip

In example.h is this:

	#if defined(__WIN32__)
	#   if defined(_MSC_VER)
	#	define EXPORT(a,b) __declspec(dllexport) a b
	#   else
	#	if defined(__BORLANDC__)
	#	    define EXPORT(a,b) a _export b
	#	else
	#	    define EXPORT(a,b) a b
	#	endif
	#   endif
	#else
	#   define EXPORT(a,b) a b
	#endif
	
	EXTERN EXPORT(int,Example_Init) _ANSI_ARGS_((Tcl_Interp *interp));

That work is doing the same job, but I prefer the method that I'm
proposing.

It is also mentioned on <http://tcl.activestate.com/doc/howto/winext.html>
and feel it is rather out-of-date and the order issue with _\_\_export_
should be brought into the core with this patch and be fix for good.

Is>

		EXTERN int Foobar_Init (Tcl_Interp *interp);

Proposed>

		TCL_EXTERN(int) Foobar_Init (Tcl_Interp *interp);

# Reference Implementation

<https://sourceforge.net/tracker/download.php?group\_id=10894&atid=310894&file\_id=70480&aid=436116>

# Examples

Is:

	EXTERN int
	Foobar_Init (Tcl_Interp *interp)

	{
	#ifdef USE_TCL_STUBS
	    if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
	        return TCL_ERROR;

	    }
	#endif
	    Tcl_CreateObjCommand(interp, "foobar", FooBar, NULL, NULL);
	    return TCL_OK;
	};

Proposed:

	TCL_EXTERN(int)
	Foobar_Init (Tcl_Interp *interp)

	{
	#ifdef USE_TCL_STUBS
	    if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
	        return TCL_ERROR;

	    }
	#endif
	    Tcl_CreateObjCommand(interp, "foobar", FooBar, NULL, NULL);
	    return TCL_OK;
	};

Preprocessor output is the following:

 >	Borland:

	/* foobar.c 14: */extern  int __export
	/* foobar.c 15: */Foobar_Init (Tcl_Interp *interp)
	/* foobar.c 16: */{
	/* foobar.c 17: */
	/* foobar.c 18: */if (Tcl_InitStubs(interp, "8.1", 0) == 0) {
	/* foobar.c 19: */return 1;
	/* foobar.c 20: */}
	/* foobar.c 21: */
	/* foobar.c 22: */(tclStubsPtr->tcl_CreateObjCommand)(interp, "foobar", FooBar, 0, 0);
	/* foobar.c 23: */return 0;
	/* foobar.c 24: */};

 >	VC\+\+:

	extern  __declspec(dllexport) int
	Foobar_Init (Tcl_Interp *interp)

	{
	
	    if (Tcl_InitStubs(interp, "8.1", 0) == ((void *)0)) {
	        return 1;

	    }
	#line 22 "foobar.c"
	    (tclStubsPtr->tcl_CreateObjCommand)(interp, "foobar", FooBar, ((void *)0), ((void *)0));
	    return 0;
	};

 >	MinGW \(native gcc on win\):

	extern       int
	Foobar_Init (Tcl_Interp *interp)

	{
	
	    if (Tcl_InitStubs(interp, "8.1", 0) == ((void *)0) ) {
	        return 1 ;

	    }
	
	    (tclStubsPtr->tcl_CreateObjCommand) (interp, "foobar", FooBar, ((void *)0) , ((void *)0) );
	    return 0 ;
	};

# Random Notes

In _tclInt.h_ starting around line 1916, are prototypes for the
internal cmdprocs.  I can't think of any reason why they should be
exported.  Also note the comment about line:1673, as it states:

	/*
	 *----------------------------------------------------------------
	 * Procedures shared among Tcl modules but not used by the outside
	 * world:
	 *----------------------------------------------------------------
	 */

As the current EXTERN macro places ""everything"" exportable, the use of EXTERN following this comment in _tclInt.h_ is contradictory.  In place of EXTERN for this purpose I used the new TCL\_EXTRNC in the reference implementation.

# Copyright

This document has been placed in the public domain.

Name change from tip/61.tip to tip/61.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

TIP:            61
Title:          Make TK_NO_SECURITY Run-Time Switchable
Version:        $Revision: 1.4 $
Author:         Jeff Hobbs <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Deferred
Type:           Project
Vote:           Pending
Created:        12-Sep-2001
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP changes the compile time Tk define TK_NO_SECURITY to be
switchable at run-time.

~ Rationale

The TK_NO_SECURITY compile time #define is available to disable some
security checking when send is used.  The direct comments in the
Makefile are:

| # To turn off the security checks that disallow incoming sends when
| # the X server appears to be insecure, reverse the comments on the
| # following lines:
| SECURITY_FLAGS		=
| #SECURITY_FLAGS		= -DTK_NO_SECURITY

I propose to make this switch configurable at runtime through a ''tk
securesend'' option.

~ Benefits

Users would be able to debug between Tk applications on Unix using
''send'' without having to compile a special version of Tk or
manipulating the security settings of their X server to Tk's liking
(which can then conflict with other work).  It is common for users in
internal ("safe") networks to open up access to an X server with
''xhost +machine''.

~ Drawbacks

By allowing security to be disabled, users do possibly open up their
system to attack.  However, secure is the default setting, and any
paranoid users can ''rename send {}'' to ensure that it is not used at
all.

~ Reference Implementation

A full patch for this feature is available at:

http://sf.net/tracker/?func=detail&aid=456732&group_id=12997&atid=312997

The proposal adds one element to the private ''TkDisplay'' structure
(configuration for secure send is done per display), and creates the
Tcl level command:

|	tk securesend ?-displayof window? ?boolean?

It leaves the TK_NO_SECURITY flag alone.  If specified, send is
insecure by default, otherwise it is secure.

~ Comments

''DKF'' - It should be possible to control the setting of the
compile-time TK_NO_SECURITY flag from the ''configure'' script; having
to edit the Makefile by hand to adjust it makes it too easy to
inadvertently break something by introducing an unfortunate typo. Being
able to pass a ''--disable-security'' flag would make thing much easier
from a user's point of view, and will make it less likely that the Tk
maintainers will have to deal with bug reports that ultimately stem from
a dumb mistake made in a sensitive spot...

~ Copyright  

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|


|

|



|
|
|
|
|

|
|

|


|

|
|
|

|



|


|



|

|
|


|

|


|

|
|


|




|


>

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

# TIP 61: Make TK_NO_SECURITY Run-Time Switchable

	Author:         Jeff Hobbs <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Deferred
	Type:           Project
	Vote:           Pending
	Created:        12-Sep-2001
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP changes the compile time Tk define TK\_NO\_SECURITY to be
switchable at run-time.

# Rationale

The TK\_NO\_SECURITY compile time \#define is available to disable some
security checking when send is used.  The direct comments in the
Makefile are:

	 # To turn off the security checks that disallow incoming sends when
	 # the X server appears to be insecure, reverse the comments on the
	 # following lines:
	 SECURITY_FLAGS		=
	 #SECURITY_FLAGS		= -DTK_NO_SECURITY

I propose to make this switch configurable at runtime through a _tk
securesend_ option.

# Benefits

Users would be able to debug between Tk applications on Unix using
_send_ without having to compile a special version of Tk or
manipulating the security settings of their X server to Tk's liking
\(which can then conflict with other work\).  It is common for users in
internal \("safe"\) networks to open up access to an X server with
_xhost \+machine_.

# Drawbacks

By allowing security to be disabled, users do possibly open up their
system to attack.  However, secure is the default setting, and any
paranoid users can _rename send \{\}_ to ensure that it is not used at
all.

# Reference Implementation

A full patch for this feature is available at:

<http://sf.net/tracker/?func=detail&aid=456732&group\_id=12997&atid=312997>

The proposal adds one element to the private _TkDisplay_ structure
\(configuration for secure send is done per display\), and creates the
Tcl level command:

		tk securesend ?-displayof window? ?boolean?

It leaves the TK\_NO\_SECURITY flag alone.  If specified, send is
insecure by default, otherwise it is secure.

# Comments

_DKF_ - It should be possible to control the setting of the
compile-time TK\_NO\_SECURITY flag from the _configure_ script; having
to edit the Makefile by hand to adjust it makes it too easy to
inadvertently break something by introducing an unfortunate typo. Being
able to pass a _--disable-security_ flag would make thing much easier
from a user's point of view, and will make it less likely that the Tk
maintainers will have to deal with bug reports that ultimately stem from
a dumb mistake made in a sensitive spot...

# Copyright  

This document has been placed in the public domain.

Name change from tip/62.tip to tip/62.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170

171
172
173
174
175

176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

348
349
350
351
352
353
354



355
356
357

TIP:            62
Title:          Add Support for Command Tracing
Version:        $Revision: 1.11 $
Author:         Hemang Lavana <[email protected]>
Author:         Vince Darley <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        18-Sep-2001
Post-History:   
Tcl-Version:    8.4


~ Abstract

This TIP proposes that the Tcl's trace command be extended to include
the following features:
  1. tracing of command execution for the specified tcl command, and
  2. step-wise tracing of any command execution within a specified procedure.

~ Rationale

One of the main strengths of Tcl is the ability to trace ''read'',
''write'' or ''delete'' operations on variables.  Moreover, Tcl8.4 has
already added support for tracing ''rename'' or ''delete'' operations
on Tcl commands.  Addition of the proposed subcommand for tracing
executions will further improve the capabilities of Tcl without any loss
of performance (see ''Benchmark Results'' section below).

I can see several applications of this feature, including:

  *  overloading/wrapping of Tcl commands, please see
     http://mini.net/tcl/1494.html

  *  aid developer in debugging Tcl scripts

  *  profiler module in ''tcllib'' can benefit from this feature

~ Specification

This TIP proposes an enhancement to the trace command with the
following syntax:

|        trace add execution name ops command

The type ''execution'' is used to arrange for ''command'' to be executed
whenever the command ''name'' is invoked for execution.
''Name'' may refer to any of the tcl commands or procedures that have been
previously defined. It is an error to create an ''execution'' trace on a 
non-existant command or a procedure.

The ''ops'' argument can accept ''enter'', ''leave'', ''enterstep'', and
''leavestep'' as valid operations:

   1. ''enter'' - Invoke ''command'' whenever the command ''name'' is
        executed, just before the actual execution takes place.

   2. ''leave'' - Invoke ''command'' whenever the command ''name'' is
        executed, just after the actual execution takes place.

   3. ''enterstep'' - Invoke ''command'' for every tcl command which is
        executed inside the procedure ''name'', just before the actual
	execution takes place. Setting a ''enterstep'' trace on a ''command''
	will not result in an error and is simply ignored.

   4. ''leavestep'' - Invoke ''command'' for every tcl command which is
        executed inside the procedure ''name'', just after the actual
	execution takes place. Setting a ''leavestep'' trace on a ''command''
	will not result in an error and is simply ignored.

When the trace triggers, depending on the operations being traced, a
number of arguments are appended to command so that the actual command
is as follows:

For ''enter'' and ''enterstep'' operations:

|    command command-string op

''command-string'' gives the complete current command being executed,
including all arguments in their fully expanded form.
''Op'' indicates what operation is being performed on the
variable, and is one of ''enter'' or ''enterstep'' here.
The trace operation can be used to stop the command from executing,
by deleting the command in question.  Of course when the command is
subsequently executed, an 'invalid command' error will occur.

For ''leave'' and ''leavestep'' operations:

|   command command-string code result op

''command-string'' gives the complete current command being executed,
including all arguments in their fully expanded form.  ''code'' gives
the result code of that execution, and ''result'' gives its result
string.  ''Op'' indicates what operation is being performed on the
variable, and is one of ''leave'' or ''leavestep'' here.

''Command'' executes in the same context as the code that invoked
the traced operation: thus the ''command'', if invoked from a procedure,
will have access to the same local variables as code in the procedure.
This context may be different than the context in which the trace was
created. If ''command'' invokes a procedure (which it normally does)
then the procedure will have to use upvar or uplevel commands if it
wishes to access the local variables of the code which invoked the
trace operation. Note that if the value of a local variable is passed
as an argument to the traced command ''name'' and is modified by
the ''command'' procedure, the traced command ''name'' will still
be invoked with the old value of the local variable. This is because
the argument list to ''name'' is formed before the traced ''command''
is invoked. Please see the section on ''Future Scope'' below on how
to modify the arguments passed to ''name''.

While ''command'' is executing during an ''execution'' trace, traces
on ''name'' are temporarily disabled. This allows the ''command'' to
execute ''name'' in its body without invoking any other traces
again. If an error occurs while executing the ''command'' body,
then the command ''name'' as a whole will return that same error.
Therefore, if ''catch'' command is used for invocation of the
''name'' command, it will also ignore errors resulting from such traces.

When multiple traces are set on ''name'', then the sequence of trace
command invocation is as follows:

    1.  For ''enter'' and ''enterstep'' operations, the traced
        commands are invoked in the reverse order of how these
	traces were created.

    2.  For ''leave'' and ''leavestep'' operations, the traced
        commands are invoked in the same order as how these
	traces were created.

For example, if we have two traces on proc foo:

|    trace add execution foo {enter leave} {barA}
|    trace add execution foo {enter leave} {barB}

then the trace commands ''barA'' and ''barB'' will be invoked in
the following sequence:

|    barB {foo x} {enter}
|    barA {foo x} {enter}
|      foo x
|    barA {foo x} 0 {} {leave}
|    barB {foo x} 0 {} {leave}

The creation of many ''enterstep'' or ''leavestep'' traces can lead
to unintuitive results, since the invoked commands from one trace
can themselves lead to further command invocations for other traces.
However, these unintuitive results are completely predictable and safe
(and tested in the test suite).  Nevertheless the user will probably
only want to have one such trace active at a time.

Once created, the trace remains in effect either until the trace is
removed with the ''trace remove execution'' command, until the ''name''
is deleted or until the interpreter is deleted. Note that renaming the
command ''name'' will not remove the execution traces.

To implement ''enterstep'' and ''leavestep'' traces, it is necessary
to invoke traces regardless of at what level the ''command'' is being
traced. This means that the value for ''level'' argument to 
Tcl_CreateTrace and Tcl_CreateObjTrace APIs should also accept ''0''.
A value of ''0'' implies that commands at all levels will be traced. 

~ Examples

The following script defines a procedure ''foo'' and illustrates 
several cases as to how its execution can be traced.

|    # Define the proc foo
|    proc foo {var} {
|         return [string index $var [expr {$var*2}]]
|    }

|    
|    # Command to invoke on trace activation
|    proc print {args} {
|        puts stdout "PRINT: $args"
|    }

|    
|    proc main {} {
|        puts stdout "================CASE 1========================="
|        puts stdout "Trace proc foo only"
|        trace add execution foo {enter leave} {print exec}
|        foo 4
|    
|        puts stdout "================CASE 2========================="
|        puts stdout "Trace proc foo as well as all commands within it"
|        trace add execution foo {enterstep leavestep} {print step}
|        foo 4
|    
|        # Remove all traces
|        trace remove execution foo {enter leave} {print exec}
|        trace remove execution foo {enterstep leavestep} {print step}
|    
|        puts stdout "================CASE 3========================="
|        puts stdout "Add a trace on string command"
|        trace add execution string {enter leave} {print exec}
|        foo 4
|        trace remove execution string {enter leave} {print exec}
|    }

|    main

The expected output of running the above script would be:

|    ===================CASE 1========================
|    Trace proc foo only
|    PRINT: exec {foo 4} enter
|    PRINT: exec {foo 4} 0 {} leave
|    ===================CASE 2=======================
|    Trace proc foo as well as all commands within it
|    PRINT: exec {foo 4} enter
|    PRINT: step {expr {$var*2}} enterstep
|    PRINT: step {expr {$var*2}} 0 8 leavestep
|    PRINT: step {string index 4 8} enterstep
|    PRINT: step {string index 4 8} 0 {} leavestep
|    PRINT: step {return {}} enterstep
|    PRINT: step {return {}} 2 {} leavestep
|    PRINT: exec {foo 4} 0 {} leave
|    ===================CASE 3=======================
|    Add a trace on string command
|    PRINT: exec {string index 4 8} enter
|    PRINT: exec {string index 4 8} 0 {} leave

Case 1 specifies a enter and leave trace on proc foo.
Here the proc foo is fully byte-code-compiled.

Case 2 additionally invokes a enterstep and leavestep trace on
proc foo.  This means that it will trace each command 
that is inovked within the proc foo.
Here the proc foo is *not* byte-code-compiled. This is
implemented by setting the DONT_COMPILE_CMDS_INLINE flag.

Case 3 specifies a trace on string command only.
Here all commands within proc foo, except string command,
is byte-code-compiled. This is implemented by modifying
compilation engine to check for CMD_HAS_EXEC_TRACES flag
before generating any byte-code.

~ Reference Implementation

This proposal was originally implemented by Vince Darley.  Please see
Feature Request #462580:
http://sf.net/tracker/?func=detail&aid=462580&group_id=10894&atid=360894

The original patch from Vince Darley has been modified in the
following respects:

  1.  For ''enter'' and ''enterstep'' operations, the original patch
      passed arguments to the ''command'' in its unexpanded form.
      This behavior has been changed to pass the arguments in its
      fully expanded form since it should be more useful for debugging
      scripts.

  2.  The original patch could not trace Tcl commands that were
      invoked inside a procedure because tracing is currently not
      possible for compiled commands.  Therefore, the patch was
      modified such that Tcl commands are no longer internally
      compiled if a trace has been set on a command.

  3.  For multiple traces on same command, the original patch 
      invoked the traces in the same order as they were created.
      This behavior was changed so that for ''enter'' and ''enterstep''
      operations, the traces are invoked in the reverse order of
      its creation. For ''leave'' and ''leavestep'', the traces are
      still invoked in the original order.

  4.  The original patch was created on 2000-Sept-14.  It was updated
      to work with the current CVS head.

The latest patch for this tip 62 is available at:

  http://www.employees.org/~hlavana/tcl/

The main changes for the patch are described in brief next.

Two new flags have been defined in tcl.h:

|  #define TCL_TRACE_ENTER_EXEC          1
|  #define TCL_TRACE_LEAVE_EXEC          2

These flag values are passed to Tcl_CreateObjTrace and used by command
execution traces. More internal flags for slots 4, 8, 15, 16, 32 are
defined in tclCmdMZ.c file: TCL_TRACE_ENTER_DURING_EXEC, 
TCL_TRACE_LEAVE_DURING_EXEC,  TCL_TRACE_ANY_EXEC, TCL_TRACE_EXEC_IN_PROGRESS
and TCL_TRACE_EXEC_DIRECT.

A new function TclTraceExecutionObjCmd function implements the
''trace {add|remove|list} execution ...'' subcommands.
A new function TclCheckExecutionTraces is defined to check for traces added
by the execution subcommand. A new function TclCheckInterpTraces is defined
to check for global traces added by the Tcl_CreateObjTrace command.
The TclEvalObjvInternal has been modified to call the above
two functions before as well as after the original command is executed.
A new function TraceExecutionProc is invoked, when necessary, to execute
the actual trace command in the interpreter.

A new structure ActiveInterpTrace has been defined for internal use so
that it behaves reasonably when traces are deleted while active.
In tclVar.c file, the function CallTraces has been renamed to CallVarTraces
and iPtr->activeTracePtr has been renamed to iPtr->activeTraceVarPtr.

An additional check for (tracePtr->level == 0) has been added in
Tcl_EvalObjv and TclExecuteByteCode functions, so as to enable
command tracing at all levels.

~ Benchmark Results

The benchmark results corresponds to ''Version 1.1'' of the reference
implementation.

One potential objection to this TIP could be that it may affect the
performance of the Tcl-core.  Therefore, I have run the
''runbench.tcl'' script from the tclbench module for comparison on a
Sun Ultra5, Solaris2.6 machine.  The results have been posted at
http://sf.net/tracker/?func=detail&aid=462580&group_id=10894&atid=360894

These results show that there is hardly any performance hit, if any,
by addition of this feature.  Of course when you activate a trace on a
command, then you will see a performance hit, but since primary uses
of traces will be in profiling and debugging, that isn't an issue.

~ Future Scope

This proposal does not allow for the trace invocation ''command''
to do the following:

  1. modify the number of arguments passed to ''name''

  2. modify the value of arguments passed to ''name''

  3. modify the result value and result code returned by ''name''

  4. skip invocation of ''name'' altogether if desired.

Consider the example of adding a sub-command "string reverse ..."
as shown on http://mini.net/tcl/1570.html.
Instead of using the rename command, it should be possible to use
the trace command to do the same, as follows:

|    trace add execution string {enter} {::mylib::stringx}
|    proc ::mylib::stringx {subcmd args} {
|        switch -exact -- $subcmd {
|            "reverse" {
|                # Hmm ... this is my subcommand, process it here
|                set returnValue [code_to_reverse_string_value]
|
|                # We need a mechansim to return immediately here
|                # with the processed results and an appropriate
|                # code value and not invoke the original string command.
|            }

|            default {
|                # This is probably a vaild subcommand, so do nothing
|                # and let the original string command handle it
|            }
|        }
|    }




~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|






|

|
|
|


|




|



|

|




|

|
|
|
|


|
|

|


|


|
|
|


|
|
|






|

|

|

|
|




|

|

|
|
|
|
|

|
|


|



|
|

|
|
|

|
|
|
|
|
|
|

|


|



|





|
|

|


|
|
|
|
|

|



|



|

|

|
|
|
|
|

|

|


|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|







|
|




|


|


|
|




|
|












|

|







|





|
|

|

|
|
|


|


|










|
|


|

|




|

|






|

|


|

|

|

|


|



|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
<
<
<
|
>
>
>
|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

169
170
171
172
173

174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195

196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345

346
347
348
349



350
351
352
353
354
355
356
357

# TIP 62: Add Support for Command Tracing

	Author:         Hemang Lavana <[email protected]>
	Author:         Vince Darley <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        18-Sep-2001
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

This TIP proposes that the Tcl's trace command be extended to include
the following features:
  1. tracing of command execution for the specified tcl command, and
  2. step-wise tracing of any command execution within a specified procedure.

# Rationale

One of the main strengths of Tcl is the ability to trace _read_,
_write_ or _delete_ operations on variables.  Moreover, Tcl8.4 has
already added support for tracing _rename_ or _delete_ operations
on Tcl commands.  Addition of the proposed subcommand for tracing
executions will further improve the capabilities of Tcl without any loss
of performance \(see _Benchmark Results_ section below\).

I can see several applications of this feature, including:

  *  overloading/wrapping of Tcl commands, please see
     <http://mini.net/tcl/1494.html>

  *  aid developer in debugging Tcl scripts

  *  profiler module in _tcllib_ can benefit from this feature

# Specification

This TIP proposes an enhancement to the trace command with the
following syntax:

	        trace add execution name ops command

The type _execution_ is used to arrange for _command_ to be executed
whenever the command _name_ is invoked for execution.
_Name_ may refer to any of the tcl commands or procedures that have been
previously defined. It is an error to create an _execution_ trace on a 
non-existant command or a procedure.

The _ops_ argument can accept _enter_, _leave_, _enterstep_, and
_leavestep_ as valid operations:

   1. _enter_ - Invoke _command_ whenever the command _name_ is
        executed, just before the actual execution takes place.

   2. _leave_ - Invoke _command_ whenever the command _name_ is
        executed, just after the actual execution takes place.

   3. _enterstep_ - Invoke _command_ for every tcl command which is
        executed inside the procedure _name_, just before the actual
	execution takes place. Setting a _enterstep_ trace on a _command_
	will not result in an error and is simply ignored.

   4. _leavestep_ - Invoke _command_ for every tcl command which is
        executed inside the procedure _name_, just after the actual
	execution takes place. Setting a _leavestep_ trace on a _command_
	will not result in an error and is simply ignored.

When the trace triggers, depending on the operations being traced, a
number of arguments are appended to command so that the actual command
is as follows:

For _enter_ and _enterstep_ operations:

	    command command-string op

_command-string_ gives the complete current command being executed,
including all arguments in their fully expanded form.
_Op_ indicates what operation is being performed on the
variable, and is one of _enter_ or _enterstep_ here.
The trace operation can be used to stop the command from executing,
by deleting the command in question.  Of course when the command is
subsequently executed, an 'invalid command' error will occur.

For _leave_ and _leavestep_ operations:

	   command command-string code result op

_command-string_ gives the complete current command being executed,
including all arguments in their fully expanded form.  _code_ gives
the result code of that execution, and _result_ gives its result
string.  _Op_ indicates what operation is being performed on the
variable, and is one of _leave_ or _leavestep_ here.

_Command_ executes in the same context as the code that invoked
the traced operation: thus the _command_, if invoked from a procedure,
will have access to the same local variables as code in the procedure.
This context may be different than the context in which the trace was
created. If _command_ invokes a procedure \(which it normally does\)
then the procedure will have to use upvar or uplevel commands if it
wishes to access the local variables of the code which invoked the
trace operation. Note that if the value of a local variable is passed
as an argument to the traced command _name_ and is modified by
the _command_ procedure, the traced command _name_ will still
be invoked with the old value of the local variable. This is because
the argument list to _name_ is formed before the traced _command_
is invoked. Please see the section on _Future Scope_ below on how
to modify the arguments passed to _name_.

While _command_ is executing during an _execution_ trace, traces
on _name_ are temporarily disabled. This allows the _command_ to
execute _name_ in its body without invoking any other traces
again. If an error occurs while executing the _command_ body,
then the command _name_ as a whole will return that same error.
Therefore, if _catch_ command is used for invocation of the
_name_ command, it will also ignore errors resulting from such traces.

When multiple traces are set on _name_, then the sequence of trace
command invocation is as follows:

    1.  For _enter_ and _enterstep_ operations, the traced
        commands are invoked in the reverse order of how these
	traces were created.

    2.  For _leave_ and _leavestep_ operations, the traced
        commands are invoked in the same order as how these
	traces were created.

For example, if we have two traces on proc foo:

	    trace add execution foo {enter leave} {barA}
	    trace add execution foo {enter leave} {barB}

then the trace commands _barA_ and _barB_ will be invoked in
the following sequence:

	    barB {foo x} {enter}
	    barA {foo x} {enter}
	      foo x
	    barA {foo x} 0 {} {leave}
	    barB {foo x} 0 {} {leave}

The creation of many _enterstep_ or _leavestep_ traces can lead
to unintuitive results, since the invoked commands from one trace
can themselves lead to further command invocations for other traces.
However, these unintuitive results are completely predictable and safe
\(and tested in the test suite\).  Nevertheless the user will probably
only want to have one such trace active at a time.

Once created, the trace remains in effect either until the trace is
removed with the _trace remove execution_ command, until the _name_
is deleted or until the interpreter is deleted. Note that renaming the
command _name_ will not remove the execution traces.

To implement _enterstep_ and _leavestep_ traces, it is necessary
to invoke traces regardless of at what level the _command_ is being
traced. This means that the value for _level_ argument to 
Tcl\_CreateTrace and Tcl\_CreateObjTrace APIs should also accept _0_.
A value of _0_ implies that commands at all levels will be traced. 

# Examples

The following script defines a procedure _foo_ and illustrates 
several cases as to how its execution can be traced.

	    # Define the proc foo
	    proc foo {var} {
	         return [string index $var [expr {$var*2}]]

	    }
	    
	    # Command to invoke on trace activation
	    proc print {args} {
	        puts stdout "PRINT: $args"

	    }
	    
	    proc main {} {
	        puts stdout "================CASE 1========================="
	        puts stdout "Trace proc foo only"
	        trace add execution foo {enter leave} {print exec}
	        foo 4
	    
	        puts stdout "================CASE 2========================="
	        puts stdout "Trace proc foo as well as all commands within it"
	        trace add execution foo {enterstep leavestep} {print step}
	        foo 4
	    
	        # Remove all traces
	        trace remove execution foo {enter leave} {print exec}
	        trace remove execution foo {enterstep leavestep} {print step}
	    
	        puts stdout "================CASE 3========================="
	        puts stdout "Add a trace on string command"
	        trace add execution string {enter leave} {print exec}
	        foo 4
	        trace remove execution string {enter leave} {print exec}

	    }
	    main

The expected output of running the above script would be:

	    ===================CASE 1========================
	    Trace proc foo only
	    PRINT: exec {foo 4} enter
	    PRINT: exec {foo 4} 0 {} leave
	    ===================CASE 2=======================
	    Trace proc foo as well as all commands within it
	    PRINT: exec {foo 4} enter
	    PRINT: step {expr {$var*2}} enterstep
	    PRINT: step {expr {$var*2}} 0 8 leavestep
	    PRINT: step {string index 4 8} enterstep
	    PRINT: step {string index 4 8} 0 {} leavestep
	    PRINT: step {return {}} enterstep
	    PRINT: step {return {}} 2 {} leavestep
	    PRINT: exec {foo 4} 0 {} leave
	    ===================CASE 3=======================
	    Add a trace on string command
	    PRINT: exec {string index 4 8} enter
	    PRINT: exec {string index 4 8} 0 {} leave

Case 1 specifies a enter and leave trace on proc foo.
Here the proc foo is fully byte-code-compiled.

Case 2 additionally invokes a enterstep and leavestep trace on
proc foo.  This means that it will trace each command 
that is inovked within the proc foo.
Here the proc foo is \*not\* byte-code-compiled. This is
implemented by setting the DONT\_COMPILE\_CMDS\_INLINE flag.

Case 3 specifies a trace on string command only.
Here all commands within proc foo, except string command,
is byte-code-compiled. This is implemented by modifying
compilation engine to check for CMD\_HAS\_EXEC\_TRACES flag
before generating any byte-code.

# Reference Implementation

This proposal was originally implemented by Vince Darley.  Please see
Feature Request \#462580:
<http://sf.net/tracker/?func=detail&aid=462580&group\_id=10894&atid=360894>

The original patch from Vince Darley has been modified in the
following respects:

  1.  For _enter_ and _enterstep_ operations, the original patch
      passed arguments to the _command_ in its unexpanded form.
      This behavior has been changed to pass the arguments in its
      fully expanded form since it should be more useful for debugging
      scripts.

  2.  The original patch could not trace Tcl commands that were
      invoked inside a procedure because tracing is currently not
      possible for compiled commands.  Therefore, the patch was
      modified such that Tcl commands are no longer internally
      compiled if a trace has been set on a command.

  3.  For multiple traces on same command, the original patch 
      invoked the traces in the same order as they were created.
      This behavior was changed so that for _enter_ and _enterstep_
      operations, the traces are invoked in the reverse order of
      its creation. For _leave_ and _leavestep_, the traces are
      still invoked in the original order.

  4.  The original patch was created on 2000-Sept-14.  It was updated
      to work with the current CVS head.

The latest patch for this tip 62 is available at:

  <http://www.employees.org/~hlavana/tcl/>

The main changes for the patch are described in brief next.

Two new flags have been defined in tcl.h:

	  #define TCL_TRACE_ENTER_EXEC          1
	  #define TCL_TRACE_LEAVE_EXEC          2

These flag values are passed to Tcl\_CreateObjTrace and used by command
execution traces. More internal flags for slots 4, 8, 15, 16, 32 are
defined in tclCmdMZ.c file: TCL\_TRACE\_ENTER\_DURING\_EXEC, 
TCL\_TRACE\_LEAVE\_DURING\_EXEC,  TCL\_TRACE\_ANY\_EXEC, TCL\_TRACE\_EXEC\_IN\_PROGRESS
and TCL\_TRACE\_EXEC\_DIRECT.

A new function TclTraceExecutionObjCmd function implements the
_trace \{add\|remove\|list\} execution ..._ subcommands.
A new function TclCheckExecutionTraces is defined to check for traces added
by the execution subcommand. A new function TclCheckInterpTraces is defined
to check for global traces added by the Tcl\_CreateObjTrace command.
The TclEvalObjvInternal has been modified to call the above
two functions before as well as after the original command is executed.
A new function TraceExecutionProc is invoked, when necessary, to execute
the actual trace command in the interpreter.

A new structure ActiveInterpTrace has been defined for internal use so
that it behaves reasonably when traces are deleted while active.
In tclVar.c file, the function CallTraces has been renamed to CallVarTraces
and iPtr->activeTracePtr has been renamed to iPtr->activeTraceVarPtr.

An additional check for \(tracePtr->level == 0\) has been added in
Tcl\_EvalObjv and TclExecuteByteCode functions, so as to enable
command tracing at all levels.

# Benchmark Results

The benchmark results corresponds to _Version 1.1_ of the reference
implementation.

One potential objection to this TIP could be that it may affect the
performance of the Tcl-core.  Therefore, I have run the
_runbench.tcl_ script from the tclbench module for comparison on a
Sun Ultra5, Solaris2.6 machine.  The results have been posted at
<http://sf.net/tracker/?func=detail&aid=462580&group\_id=10894&atid=360894>

These results show that there is hardly any performance hit, if any,
by addition of this feature.  Of course when you activate a trace on a
command, then you will see a performance hit, but since primary uses
of traces will be in profiling and debugging, that isn't an issue.

# Future Scope

This proposal does not allow for the trace invocation _command_
to do the following:

  1. modify the number of arguments passed to _name_

  2. modify the value of arguments passed to _name_

  3. modify the result value and result code returned by _name_

  4. skip invocation of _name_ altogether if desired.

Consider the example of adding a sub-command "string reverse ..."
as shown on <http://mini.net/tcl/1570.html.>
Instead of using the rename command, it should be possible to use
the trace command to do the same, as follows:

	    trace add execution string {enter} {::mylib::stringx}
	    proc ::mylib::stringx {subcmd args} {
	        switch -exact -- $subcmd {
	            "reverse" {
	                # Hmm ... this is my subcommand, process it here
	                set returnValue [code_to_reverse_string_value]
	
	                # We need a mechansim to return immediately here
	                # with the processed results and an appropriate
	                # code value and not invoke the original string command.

	            }
	            default {
	                # This is probably a vaild subcommand, so do nothing
	                # and let the original string command handle it



	            }
	        }
	    }

# Copyright

This document has been placed in the public domain.

Name change from tip/63.tip to tip/63.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

TIP:            63
Title:          Add -compound Option to Menu Entries
Version:        $Revision: 1.5 $
Author:         Vince Darley <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        27-Sep-2001
Post-History:   
Tcl-Version:    8.4


~ Abstract

This TIP adds to menu entries the ability to display both textual
labels and images (or bitmaps) in exactly the same way as buttons and
menubuttons currently can, by adding a ''-compound'' option.

~ Rationale

Menu entries are very similar to labels in most respects, but they
currently lack the ability to show an image and a piece of text at the
same time.  It is a useful piece of functionality currently missing
from Tk (certainly many standard applications make use of such menu
entries, e.g. Internet Explorer).  The changes involved are relatively
small.

A very similar TIP [11] was accepted without much argument.

~ Proposal

This TIP implements the change by adding an additional option
''-compound'' to menu entries which behaves identically to Tk's
existing ''-compound'' option: it accepts the values ''none'',
''center'', ''left'', ''right'', ''top'', and ''bottom'', and controls
the relative placement of an image to the text label in the entry.

A reference implementation exists, and is available from:
ftp://ftp.ucsd.edu/pub/alpha/tcl/compoundmenu.diff (note this diff has
Windows-style line endings).  This implementation is known to work on
Windows and Unix, and since the changes are very, very similar on
MacOS I expect it to work there (except perhaps for simple editing
mistakes).

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|
|

|




|
|


|

|


|
|
|



|
|

|
|

|


>

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

# TIP 63: Add -compound Option to Menu Entries

	Author:         Vince Darley <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        27-Sep-2001
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

This TIP adds to menu entries the ability to display both textual
labels and images \(or bitmaps\) in exactly the same way as buttons and
menubuttons currently can, by adding a _-compound_ option.

# Rationale

Menu entries are very similar to labels in most respects, but they
currently lack the ability to show an image and a piece of text at the
same time.  It is a useful piece of functionality currently missing
from Tk \(certainly many standard applications make use of such menu
entries, e.g. Internet Explorer\).  The changes involved are relatively
small.

A very similar TIP [[11]](11.md) was accepted without much argument.

# Proposal

This TIP implements the change by adding an additional option
_-compound_ to menu entries which behaves identically to Tk's
existing _-compound_ option: it accepts the values _none_,
_center_, _left_, _right_, _top_, and _bottom_, and controls
the relative placement of an image to the text label in the entry.

A reference implementation exists, and is available from:
ftp://ftp.ucsd.edu/pub/alpha/tcl/compoundmenu.diff \(note this diff has
Windows-style line endings\).  This implementation is known to work on
Windows and Unix, and since the changes are very, very similar on
MacOS I expect it to work there \(except perhaps for simple editing
mistakes\).

# Copyright

This document has been placed in the public domain.

Name change from tip/64.tip to tip/64.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
136
137
138
139
140
141
142
143
144
145
146
147

TIP:            64
Title:          Improvements to Windows Font Handling
Version:        $Revision: 1.9 $
Author:         Chris Nelson <[email protected]>
Author:         Kevin Kenny <[email protected]>
State:          Deferred
Type:           Project
Vote:           Done
Created:        27-Sep-2001
Post-History:   
Tcl-Version:    8.4
Obsoleted-By:	145


~ Abstract

This TIP improves handling of native fonts in Tk under Microsoft
Windows making Tk applications more aesthetic and more consistent with
users' expectations of 'Windows applications.

~ Background

Tk 8.4 includes platform-specific system font names which relate to
configurable aspects of the native system.

  * On UNIX, this includes all X font names (e.g. as listed by
    ''xlsfonts'').

  * On Macintosh, this includes ''system'' and ''application''.

  * On Microsoft Windows, this includes ''system'', ''systemfixed'',
    ''ansi'', ''ansifixed'', ''device'', and ''oemfixed''.

Through v8.4a3, Tk used 8pt MS Sans Serif as the default font for
widgets.  While this was almost OK, it fails in two respects:

   * Users can change the font used for various 'Windows desktop
     features so MS Sans Serif may not be the correct font for, for
     example, menus.

   * Windows 2000 and Windows XP use Tahoma, not MS Sans Serif as
     their default font.

SourceForge patch #461442 (Make Tk use the default Windows font)
[http://sf.net/tracker/?func=detail&aid=461442&group_id=12997&atid=312997]
attempts to address Tk's deficiency by adding a ''windefault'' font
based on the Message font configured for the Windows desktop.  This
appears to be wrong.

This TIP attempts to fix the default Tk font the right way as well as
giving Tk programmers access to the rest of the fonts configured for
the 'Windows desktop.

NOTE: RFE 220772 on SourceForge
[http://sf.net/tracker/?func=detail&aid=220772&group_id=12997&atid=362997]
has a related patch.

~ The Default GUI Font

The Win API call ''GetStockObject()'' accesses brushes, pens, and
fonts which are pre-configured on the system.  The available fonts
are:

    1. ANSI_FIXED_FONT

    2. ANSI_VAR_FONT

    3. DEVICE_DEFAULT_FONT

    4. DEFAULT_GUI_FONT

    5. OEM_FIXED_FONT

    6. SYSTEM_FIXED_FONT

    7. SYSTEM_FONT

The ''TkStateMap systemMap'' in ''tkWinFont.c'' listed all but one of
these, DEFAULT_GUI_FONT.  As it turns out, this is the most important
as it is the one that 'Windows uses as it's default font (for example,
in Control Panel Applets).

I propose to add DEFAULT_GUI_FONT to the ''systemMap'' with a font
name of ''defaultgui'' and to change CTL_FONT in ''tkWinDefault.h''
from ''{MS Sans Serif} 8'' to ''defaultgui''.  This will require a
change in documentation to list the new system font name but is
otherwise simple and painless.  Furthermore, it makes Tk GUIs look
right on W2k.

A reference implementation for this is available in patch 461442
(referenced above).

~ Access to Desktop Fonts

The original implementation of ''windefault'' as a new font, accessed
the message font from the NONCLIENTMETRICS structure.  While this is
not, in fact, the correct default GUI font, it is an important system
font, as are the others on the NONCLIENTMETRICS structure.  The
structure lists:

   *  Caption (title bar) font

   *  Small Caption (palette title bar) font

   *  Menu font

   *  Tooltip (and status bar) font

   *  Message box font 

The 'Windows Desktop Properties also include a font for icon labels on
the desktop.  This font is accessed with ''SystemParametersInfo()''.

I propose to add 6 desktop fonts as system fonts on Windows.  The
names would be derived from their Desktop Properties entries:
''dtIcon'', ''dtTitleBar'', ''dtMenu'', ''dtMessageBox'',
''dtPaletteTitle'', ''dtToolTip''.  The "dt" prefix associates the
fonts with the desktop properties.  (Can or should font names have
internal capital letters?)

We might also add synonyms which relate to the structure field names
and/or customary use of the font.  I'd propose adding ''dtCaption'' as
equivalent to ''dtTitleBar'', ''dtSmallCaption'' as equivalent to
''dtPaletteTitle'', and ''dtStatus'' as equivalent to ''dtToolTip''.

A reference implementation for this is available in Patch #461442
(referenced above) albeit with different font names.

~ Dynamic fonts

Many 'Windows applications respond on-the-fly to changes in the desktop
fonts.  Tk responds to changes in Tk fonts via [[font configure]].  I
propose that Tk respond to the WM_SETTINGCHANGE message from Windows
to propagate changes to the desktop fonts enumerated above as it
propagates changes to Tk fonts when they are reconfigured.  I have yet
to prototype these changes.

~ Comments

''KBK'' wonders whether the dt* fonts have logical counterparts on the
other platforms (KDE, Gnome/Gtk, Macintosh, HP-VUE, ...) and if
implementors on those platforms might want to try to mirror this
functionality.  Since nobody has commented, he assumes that they
at least do not find the idea objectionable.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|





|




|
|

|

|
|











|
|
|








|


|

|



|

|

|

|

|

|

|

|
|
|
|

|
|
|





|

|

|





|

|



|




|



|
|
|
|


|
|
|

|
|

|


|
|




|

|
|




|


>

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
136
137
138
139
140
141
142
143
144
145
146
147

# TIP 64: Improvements to Windows Font Handling

	Author:         Chris Nelson <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	State:          Deferred
	Type:           Project
	Vote:           Done
	Created:        27-Sep-2001
	Post-History:   
	Tcl-Version:    8.4
	Obsoleted-By:	145
-----

# Abstract

This TIP improves handling of native fonts in Tk under Microsoft
Windows making Tk applications more aesthetic and more consistent with
users' expectations of 'Windows applications.

# Background

Tk 8.4 includes platform-specific system font names which relate to
configurable aspects of the native system.

  * On UNIX, this includes all X font names \(e.g. as listed by
    _xlsfonts_\).

  * On Macintosh, this includes _system_ and _application_.

  * On Microsoft Windows, this includes _system_, _systemfixed_,
    _ansi_, _ansifixed_, _device_, and _oemfixed_.

Through v8.4a3, Tk used 8pt MS Sans Serif as the default font for
widgets.  While this was almost OK, it fails in two respects:

   * Users can change the font used for various 'Windows desktop
     features so MS Sans Serif may not be the correct font for, for
     example, menus.

   * Windows 2000 and Windows XP use Tahoma, not MS Sans Serif as
     their default font.

SourceForge patch \#461442 \(Make Tk use the default Windows font\)
<http://sf.net/tracker/?func=detail&aid=461442&group_id=12997&atid=312997> 
attempts to address Tk's deficiency by adding a _windefault_ font
based on the Message font configured for the Windows desktop.  This
appears to be wrong.

This TIP attempts to fix the default Tk font the right way as well as
giving Tk programmers access to the rest of the fonts configured for
the 'Windows desktop.

NOTE: RFE 220772 on SourceForge
<http://sf.net/tracker/?func=detail&aid=220772&group_id=12997&atid=362997> 
has a related patch.

# The Default GUI Font

The Win API call _GetStockObject\(\)_ accesses brushes, pens, and
fonts which are pre-configured on the system.  The available fonts
are:

    1. ANSI\_FIXED\_FONT

    2. ANSI\_VAR\_FONT

    3. DEVICE\_DEFAULT\_FONT

    4. DEFAULT\_GUI\_FONT

    5. OEM\_FIXED\_FONT

    6. SYSTEM\_FIXED\_FONT

    7. SYSTEM\_FONT

The _TkStateMap systemMap_ in _tkWinFont.c_ listed all but one of
these, DEFAULT\_GUI\_FONT.  As it turns out, this is the most important
as it is the one that 'Windows uses as it's default font \(for example,
in Control Panel Applets\).

I propose to add DEFAULT\_GUI\_FONT to the _systemMap_ with a font
name of _defaultgui_ and to change CTL\_FONT in _tkWinDefault.h_
from _\{MS Sans Serif\} 8_ to _defaultgui_.  This will require a
change in documentation to list the new system font name but is
otherwise simple and painless.  Furthermore, it makes Tk GUIs look
right on W2k.

A reference implementation for this is available in patch 461442
\(referenced above\).

# Access to Desktop Fonts

The original implementation of _windefault_ as a new font, accessed
the message font from the NONCLIENTMETRICS structure.  While this is
not, in fact, the correct default GUI font, it is an important system
font, as are the others on the NONCLIENTMETRICS structure.  The
structure lists:

   *  Caption \(title bar\) font

   *  Small Caption \(palette title bar\) font

   *  Menu font

   *  Tooltip \(and status bar\) font

   *  Message box font 

The 'Windows Desktop Properties also include a font for icon labels on
the desktop.  This font is accessed with _SystemParametersInfo\(\)_.

I propose to add 6 desktop fonts as system fonts on Windows.  The
names would be derived from their Desktop Properties entries:
_dtIcon_, _dtTitleBar_, _dtMenu_, _dtMessageBox_,
_dtPaletteTitle_, _dtToolTip_.  The "dt" prefix associates the
fonts with the desktop properties.  \(Can or should font names have
internal capital letters?\)

We might also add synonyms which relate to the structure field names
and/or customary use of the font.  I'd propose adding _dtCaption_ as
equivalent to _dtTitleBar_, _dtSmallCaption_ as equivalent to
_dtPaletteTitle_, and _dtStatus_ as equivalent to _dtToolTip_.

A reference implementation for this is available in Patch \#461442
\(referenced above\) albeit with different font names.

# Dynamic fonts

Many 'Windows applications respond on-the-fly to changes in the desktop
fonts.  Tk responds to changes in Tk fonts via [font configure].  I
propose that Tk respond to the WM\_SETTINGCHANGE message from Windows
to propagate changes to the desktop fonts enumerated above as it
propagates changes to Tk fonts when they are reconfigured.  I have yet
to prototype these changes.

# Comments

_KBK_ wonders whether the dt\* fonts have logical counterparts on the
other platforms \(KDE, Gnome/Gtk, Macintosh, HP-VUE, ...\) and if
implementors on those platforms might want to try to mirror this
functionality.  Since nobody has commented, he assumes that they
at least do not find the idea objectionable.

# Copyright

This document has been placed in the public domain.

Name change from tip/65.tip to tip/65.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

TIP:            65
Title:          Enhanced [info args]
Version:        $Revision: 1.6 $
Author:         Glenn Jackman <[email protected]>
Author:         Don Porter <[email protected]>
Author:         Glenn Jackman <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        18-Sep-2001
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes a new subcommand to the [[info]] command be added
that would return the list of arguments, together with any default
values in the same format as the ''args'' parameter to the [[proc]]
command.

~ Introduction

The [[proc]] man page defines ''args'' as:

  > ... the formal arguments to the procedure.  It consists of a list,
    possibly empty, each of whose elements specifies one argument.
    Each argument specifier is also a list with either one or two
    fields.  If there is only a single field in the specifier then it
    is the name of the argument; if there are two fields, then the
    first is the argument name and the second is its default value.

Suppose we define a procedure like this:

|       proc test {one {two 2} {three {3 4 5}} args} {return}

We want to determine the formal arguments for this procedure.  We want
some method to return the list:

|       one {two 2} {three {3 4 5}} args

[[info args]] fails us because it does not return default values, only
the list of argument names {one two three args}.

The [[info default]] command exists, and does partially what we want.
However [[info default]] only operates on a single argument.  To
determine the complete list of arguments with default values, we must
iterate over the arguments returned by [[info args]].  We would define
a procedure like:

|       proc info_args_with_defaults {procname} {
|           set argspec [list]
|           # [info args] throws an error if $procname is not a procedure.
|           foreach arg [info args $procname] {
|               if {[info default $procname $arg value]} {
|                   lappend argspec [list $arg $value]
|               } else {
|                   lappend argspec $arg
|               }
|           }


|           return $argspec
|       }

|       info_args_with_defaults test  ;# ==> returns {one {two 2} {three {3 4 5}} args}

A more sophisticated scripted solution is to overload the [[info]]
command itself, as described in the Wiki at
http://wiki.tcl.tk/wrappingCommands

It would be much more convenient to be able to rely on the [[info]]
command itself to return the desired information, particularly since
it ''almost'' does what we want already.

''This topic was originally raised in the news:comp.lang.tcl newsgroup
in the thread http://groups.google.com/groups?th=4b0d5dba85d2c160''

~ Specification

Add [[info formalargs]] to the set of subcommands for
Tcl's built-in [[info]] command, with syntax:

| info formalargs $procName

This command will raise an error if ''$procName'' is not the
name of a proc.  Otherwise, it will return a list of formal
arguments of the named proc, along with their default values,
if any, in a format suitable for passing to the [[proc]] command
as a second argument.

~ Rationale

With the goal of maintaining backwards compatibility in mind, two
possibilities arise: adding a new switch to the existing [[info args]]
command, and adding a completely new subcommand to [[info]].

Adding a switch to [[info args]] may break backwards compatibility.
If we use the syntax [[info args ''?-withdefaults? procname'']], there
may be trouble with existing scripts containing a procedure named
"-withdefaults".  The syntax [[info args ''procname
?-withdefaults?'']] is completely backwards compatible.  However,
among Tcl commands that take subcommands, there is currently some
inconsistency as to where switches should appear.  [[clock]]
subcommands place these options after required parameters.
[[namespace]] and [[package]] subcommands place these options before
required parameters.  Some [[file]] subcommands put them before, some
after.  Currently, no [[info]] subcommands take switches.

Rather than compound to this inconsistency, creating a new [[info]]
subcommand feels cleaner.  Possible names include:

 argspec, arglist, args_with_defaults:	These all collide with the
    "arg", "ar", "a" shorthands for [[info args ''procname'']].  And
    ''args_with_defaults'' is just *way* too ugly.

 formalargs, fullargs:	Either of these could be used.  This collides
    with the "f" shorthand for [[info functions]]

 parameters:	This collides with the "pa" shorthand for [[info
    patchlevel]]

 prototype:	This collides with the "pro" and "pr" shorthands for
    [[info procs ''?pattern?'']]

 signature:	This could be used, as it does not collide with any
    shorthand for either [[info script]] or [[info sharedlibextension]].

The term "signature" has meaning in the Java and C++ worlds: the
function name and its arguments together comprise the signature.  The
purpose of this TIP is to return only the arguments with any defaults,
so to avoid any potential confusion I will rule out "signature".

Of the remaining possibilities, my choice would be "formalargs".  The
term "formal arguments" is used in the [[proc]] man page.
"formalargs" also incorporates the word "args", indicating a
relationship to [[info args]].

~ Reference Implementation

Refer to the submitted patch, which implements an subcommand named
[[info fullargs]], at:
http://sourceforge.net/tracker/index.php?func=detail&aid=461635&group_id=10894&atid=310894

~ Reasons for Rejection

Those voting against this proposal believed that since the desired
functionality is already possible with a short script of just a few
Tcl commands, it would be unnecessary bloat to add another subcommand.
Some also pointed to [112] as another approach to letting people extend
Tcl built-in commands with their own custom subcommands.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|

|


|

|










|




|

|
|

|
|

|


|
|
|
|
|
|
|
|
<
<
>
>
|
<
>
|

|

|

|

|

|
|

|

|
|

|

|


|


|


|
|

|
|

|
|

|

|
|
|

|


|
|
|


|

|
|


|


|

|





|

|

|


|
|

|




|


|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

# TIP 65: Enhanced [info args]

	Author:         Glenn Jackman <[email protected]>
	Author:         Don Porter <[email protected]>
	Author:         Glenn Jackman <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        18-Sep-2001
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes a new subcommand to the [info] command be added
that would return the list of arguments, together with any default
values in the same format as the _args_ parameter to the [proc]
command.

# Introduction

The [proc] man page defines _args_ as:

  > ... the formal arguments to the procedure.  It consists of a list,
    possibly empty, each of whose elements specifies one argument.
    Each argument specifier is also a list with either one or two
    fields.  If there is only a single field in the specifier then it
    is the name of the argument; if there are two fields, then the
    first is the argument name and the second is its default value.

Suppose we define a procedure like this:

	       proc test {one {two 2} {three {3 4 5}} args} {return}

We want to determine the formal arguments for this procedure.  We want
some method to return the list:

	       one {two 2} {three {3 4 5}} args

[info args] fails us because it does not return default values, only
the list of argument names \{one two three args\}.

The [info default] command exists, and does partially what we want.
However [info default] only operates on a single argument.  To
determine the complete list of arguments with default values, we must
iterate over the arguments returned by [info args].  We would define
a procedure like:

	       proc info_args_with_defaults {procname} {
	           set argspec [list]
	           # [info args] throws an error if $procname is not a procedure.
	           foreach arg [info args $procname] {
	               if {[info default $procname $arg value]} {
	                   lappend argspec [list $arg $value]
	               } else {
	                   lappend argspec $arg


	               }
	           }
	           return $argspec

	       }
	       info_args_with_defaults test  ;# ==> returns {one {two 2} {three {3 4 5}} args}

A more sophisticated scripted solution is to overload the [info]
command itself, as described in the Wiki at
<http://wiki.tcl.tk/wrappingCommands>

It would be much more convenient to be able to rely on the [info]
command itself to return the desired information, particularly since
it _almost_ does what we want already.

_This topic was originally raised in the news:comp.lang.tcl newsgroup
in the thread <http://groups.google.com/groups?th=4b0d5dba85d2c160_>

# Specification

Add [info formalargs] to the set of subcommands for
Tcl's built-in [info] command, with syntax:

	 info formalargs $procName

This command will raise an error if _$procName_ is not the
name of a proc.  Otherwise, it will return a list of formal
arguments of the named proc, along with their default values,
if any, in a format suitable for passing to the [proc] command
as a second argument.

# Rationale

With the goal of maintaining backwards compatibility in mind, two
possibilities arise: adding a new switch to the existing [info args]
command, and adding a completely new subcommand to [info].

Adding a switch to [info args] may break backwards compatibility.
If we use the syntax [info args _?-withdefaults? procname_], there
may be trouble with existing scripts containing a procedure named
"-withdefaults".  The syntax [info args _procname
?-withdefaults?_] is completely backwards compatible.  However,
among Tcl commands that take subcommands, there is currently some
inconsistency as to where switches should appear.  [clock]
subcommands place these options after required parameters.
[namespace] and [package] subcommands place these options before
required parameters.  Some [file] subcommands put them before, some
after.  Currently, no [info] subcommands take switches.

Rather than compound to this inconsistency, creating a new [info]
subcommand feels cleaner.  Possible names include:

 argspec, arglist, args\_with\_defaults:	These all collide with the
    "arg", "ar", "a" shorthands for [info args _procname_].  And
    _args\_with\_defaults_ is just \*way\* too ugly.

 formalargs, fullargs:	Either of these could be used.  This collides
    with the "f" shorthand for [info functions]

 parameters:	This collides with the "pa" shorthand for [info
    patchlevel]

 prototype:	This collides with the "pro" and "pr" shorthands for
    [info procs _?pattern?_]

 signature:	This could be used, as it does not collide with any
    shorthand for either [info script] or [info sharedlibextension].

The term "signature" has meaning in the Java and C\+\+ worlds: the
function name and its arguments together comprise the signature.  The
purpose of this TIP is to return only the arguments with any defaults,
so to avoid any potential confusion I will rule out "signature".

Of the remaining possibilities, my choice would be "formalargs".  The
term "formal arguments" is used in the [proc] man page.
"formalargs" also incorporates the word "args", indicating a
relationship to [info args].

# Reference Implementation

Refer to the submitted patch, which implements an subcommand named
[info fullargs], at:
<http://sourceforge.net/tracker/index.php?func=detail&aid=461635&group\_id=10894&atid=310894>

# Reasons for Rejection

Those voting against this proposal believed that since the desired
functionality is already possible with a short script of just a few
Tcl commands, it would be unnecessary bloat to add another subcommand.
Some also pointed to [[112]](112.md) as another approach to letting people extend
Tcl built-in commands with their own custom subcommands.

# Copyright

This document has been placed in the public domain.

Name change from tip/66.tip to tip/66.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
TIP:            66
Title:          Stand-alone and Embedded Tcl/Tk Applications
Version:        $Revision: 1.15 $
Author:         Arjen Markus <[email protected]>
State:          Draft
Type:           Informative
Vote:           Pending
Created:        02-Oct-2001
Post-History:   
Keywords:       installation,initialisation,embedded,resources


~ Abstract

This TIP describes the development and deployment of Tcl/Tk
applications, with particular attention on how to ''embed'' the
interpreter into executables written in C or C++.

~ Introduction and Background

Usually, an application that uses Tcl/Tk in some way uses an
independent installation and the application itself is started via a
standard shell, like ''tclsh'' or ''wish''.  There are numerous
occasions when such a set-up is not convenient:

 * Installation of external software is not allowed unless the IT
   department at the client's site consents - a very reasonable
   approach to the uncountable problems that occur due to conflicting
   software in modern computing environments.

<
|
<
|
|
|
|
|
|
|
>

|


|
|

|



|








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

# TIP 66: Stand-alone and Embedded Tcl/Tk Applications

	Author:         Arjen Markus <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        02-Oct-2001
	Post-History:   
	Keywords:       installation,initialisation,embedded,resources
-----

# Abstract

This TIP describes the development and deployment of Tcl/Tk
applications, with particular attention on how to _embed_ the
interpreter into executables written in C or C\+\+.

# Introduction and Background

Usually, an application that uses Tcl/Tk in some way uses an
independent installation and the application itself is started via a
standard shell, like _tclsh_ or _wish_.  There are numerous
occasions when such a set-up is not convenient:

 * Installation of external software is not allowed unless the IT
   department at the client's site consents - a very reasonable
   approach to the uncountable problems that occur due to conflicting
   software in modern computing environments.

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
    application using one of the commercial tools that are available
    for this arcane job, we ran into a bizarre limitation: text
    replacement was possible for the so-called Windows INI-files only,
    but not for other types of files.  The text to be replaced was the
    name of the installation directory.  After several trials with the
    programming constructs the tool allowed, we chose a much better
    solution: a small Tcl script wrapped into a stand-alone program
    using Freewrap.  (The application itself now actually uses another
    stand-alone Tcl script to take care of the file management that
    was too complicated for ordinary DOS batch files.)

 2. The second example involves a small program that proves the
    usefulness of Tcl/Tk in on-line visualisation.  The idea there is
    that large computational programs can send their data at regular
    steps during the computation to a separate program that plots
    these results in some meaningful way.  To achieve this the program
    exports the results to the Tcl interpreter which uses the socket
    command to send them to a (primitive) viewer.  For demonstration
    purposes you must be able to copy the program along with some
    files it needs on an arbitrary computer and, later, remove it with
    just a little effort.

Applications that use Tcl/Tk as an embedded library to achieve their
goals, rather than exist as extensions or applications written in Tcl,
can be quite useful.  Examples include on-line visualisation in large







|

|







|







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
    application using one of the commercial tools that are available
    for this arcane job, we ran into a bizarre limitation: text
    replacement was possible for the so-called Windows INI-files only,
    but not for other types of files.  The text to be replaced was the
    name of the installation directory.  After several trials with the
    programming constructs the tool allowed, we chose a much better
    solution: a small Tcl script wrapped into a stand-alone program
    using Freewrap.  \(The application itself now actually uses another
    stand-alone Tcl script to take care of the file management that
    was too complicated for ordinary DOS batch files.\)

 2. The second example involves a small program that proves the
    usefulness of Tcl/Tk in on-line visualisation.  The idea there is
    that large computational programs can send their data at regular
    steps during the computation to a separate program that plots
    these results in some meaningful way.  To achieve this the program
    exports the results to the Tcl interpreter which uses the socket
    command to send them to a \(primitive\) viewer.  For demonstration
    purposes you must be able to copy the program along with some
    files it needs on an arbitrary computer and, later, remove it with
    just a little effort.

Applications that use Tcl/Tk as an embedded library to achieve their
goals, rather than exist as extensions or applications written in Tcl,
can be quite useful.  Examples include on-line visualisation in large
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
   environment?

 * What you can and can not do with a bare interpreter?

 * How to enhance its capabilities, such that it works as in an
   ordinary Tcl shell?

 * What (binary and script) libraries are required?

 * How to deal with other programming languages than C/C++?

 * How to create applications that can be installed without an
   independent Tcl installation?

~ Related TIPs and Discussions

The are several TIPs at the moment of this writing that are in some way
related to the subject:

 * [4] proposes to outline the release and distribution philosophy, so
   that it becomes easy to include generally useful extensions - the
   so-called "batteries included".

 * [12] focuses completely on the "batteries included" aspect of the
   source distribution.

 * [34] is intended to solve some of the more awkward issues of TEA,
   as the current build system actually requires separate versions for
   UNIX and Windows.

 * [55] defines the set-up of packages that can be automatically
   installed into an existing installation.

 * Postings on the news:comp.lang.tcl newsgroup frequently involve how
   to embed Tcl into a C application, with an emphasis on loading
   packages and the use of the ''Tcl_Init()'' function.

 * Recently discussions have been held about supporting programming
   languages other than C.  Notably: Pascal, FORTRAN, Visual Basic.

~ Contents of the Planned Document

The document that should help programmers with the issues discussed here
will have the following (tentative) table of contents:

 * Introduction, outlining its purpose.

 * Tcl's bootstrap procedure, describing how the usual shells work.

 * Creating interpreters, what a bare interpreter can and can not do,
   how to enrich it via start-up scripts like ''init.tcl''.

 * Compiling and linking, the usual issues surrounding the making of a
   binary executable.

 * Interfacing to other programming languages, though possibly a huge
   subject, it will present some guidelines, both practical
   implementation and design issues.

 * Installation and deployment, should inform about the external
   resources (environment variables, libraries, etc) for the
   application.

 * Overview, provide a checklist of the various possibilities and how
   to achieve them, with pointers for further information.

 * Literature, all the good books and other references.

----

~ Discussion

Issues that arise are:

 * what is the simplest way to embed Tcl,

 * what resources are needed (in terms of script and binary libraries)
   by such an application,

 * how can the application find everything it needs?

This TIP is meant to be a document that enables programmers who do not
have intimate knowledge of the Tcl core to build such application and
deploy them in the way they want.

Should it turn out that some automated tool would be nice to help the
programmers, then this TIP will also cover such a tool.

----

~ Using the Tcl library

There are numerous ways an application written mainly in a language like
C can use the Tcl and Tk libraries (in short: Tcl):

   * The application can simply use Tcl as a convenient library of
     C routines. In that case, Tcl would provide such facilities as
     regular expressions or channels.

   * The application can use Tcl as a scripting tool, that is, it
     will call Tcl to evaluate scripts and import the results.

   * The application can use Tcl in a more complicated mixture:
     Tcl scripts get evaluated that require binary extensions
     (both defined outside the application and as an integral
     part of the application).

   * An application that uses Tcl need not be written in C, but
     could be written in any programming language that allows
     calls to and from C routines directly or indirectly.

''Note:'' due to the fact that the author is mostly familiar with the
UNIX/LINUX and Windows platforms, no comments will be made about the
Macintosh. This is completely due to ignorance, not to arrogance.

In principle, using the Tcl/Tk libraries is very simple: just create
a Tcl interpreter, fill it with variables, commands and so on and
feed it scripts, either as a file or as a string. It gets
more complicated in the following situations:

   * The interpreter must be able to handle packages and interact
     with the environment in much the same way as tclsh or wish.

   * The application needs to intermix its own processing with Tcl
     event loops (such as continuing a calculation while a Tk window
     shows the progress).

   * It must be possible to use the application independently from
     a full Tcl installation.

The key to a successful implementation is: understanding how to
properly initialise Tcl.








|

|




|




|



|


|



|




|




|


|






|









|









|





|













|


|










|
|





|












|
|







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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
   environment?

 * What you can and can not do with a bare interpreter?

 * How to enhance its capabilities, such that it works as in an
   ordinary Tcl shell?

 * What \(binary and script\) libraries are required?

 * How to deal with other programming languages than C/C\+\+?

 * How to create applications that can be installed without an
   independent Tcl installation?

# Related TIPs and Discussions

The are several TIPs at the moment of this writing that are in some way
related to the subject:

 * [[4]](4.md) proposes to outline the release and distribution philosophy, so
   that it becomes easy to include generally useful extensions - the
   so-called "batteries included".

 * [[12]](12.md) focuses completely on the "batteries included" aspect of the
   source distribution.

 * [[34]](34.md) is intended to solve some of the more awkward issues of TEA,
   as the current build system actually requires separate versions for
   UNIX and Windows.

 * [[55]](55.md) defines the set-up of packages that can be automatically
   installed into an existing installation.

 * Postings on the news:comp.lang.tcl newsgroup frequently involve how
   to embed Tcl into a C application, with an emphasis on loading
   packages and the use of the _Tcl\_Init\(\)_ function.

 * Recently discussions have been held about supporting programming
   languages other than C.  Notably: Pascal, FORTRAN, Visual Basic.

# Contents of the Planned Document

The document that should help programmers with the issues discussed here
will have the following \(tentative\) table of contents:

 * Introduction, outlining its purpose.

 * Tcl's bootstrap procedure, describing how the usual shells work.

 * Creating interpreters, what a bare interpreter can and can not do,
   how to enrich it via start-up scripts like _init.tcl_.

 * Compiling and linking, the usual issues surrounding the making of a
   binary executable.

 * Interfacing to other programming languages, though possibly a huge
   subject, it will present some guidelines, both practical
   implementation and design issues.

 * Installation and deployment, should inform about the external
   resources \(environment variables, libraries, etc\) for the
   application.

 * Overview, provide a checklist of the various possibilities and how
   to achieve them, with pointers for further information.

 * Literature, all the good books and other references.

----

# Discussion

Issues that arise are:

 * what is the simplest way to embed Tcl,

 * what resources are needed \(in terms of script and binary libraries\)
   by such an application,

 * how can the application find everything it needs?

This TIP is meant to be a document that enables programmers who do not
have intimate knowledge of the Tcl core to build such application and
deploy them in the way they want.

Should it turn out that some automated tool would be nice to help the
programmers, then this TIP will also cover such a tool.

----

# Using the Tcl library

There are numerous ways an application written mainly in a language like
C can use the Tcl and Tk libraries \(in short: Tcl\):

   * The application can simply use Tcl as a convenient library of
     C routines. In that case, Tcl would provide such facilities as
     regular expressions or channels.

   * The application can use Tcl as a scripting tool, that is, it
     will call Tcl to evaluate scripts and import the results.

   * The application can use Tcl in a more complicated mixture:
     Tcl scripts get evaluated that require binary extensions
     \(both defined outside the application and as an integral
     part of the application\).

   * An application that uses Tcl need not be written in C, but
     could be written in any programming language that allows
     calls to and from C routines directly or indirectly.

_Note:_ due to the fact that the author is mostly familiar with the
UNIX/LINUX and Windows platforms, no comments will be made about the
Macintosh. This is completely due to ignorance, not to arrogance.

In principle, using the Tcl/Tk libraries is very simple: just create
a Tcl interpreter, fill it with variables, commands and so on and
feed it scripts, either as a file or as a string. It gets
more complicated in the following situations:

   * The interpreter must be able to handle packages and interact
     with the environment in much the same way as tclsh or wish.

   * The application needs to intermix its own processing with Tcl
     event loops \(such as continuing a calculation while a Tk window
     shows the progress\).

   * It must be possible to use the application independently from
     a full Tcl installation.

The key to a successful implementation is: understanding how to
properly initialise Tcl.

225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306


307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381

382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590

591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652

and the output.

Let us assume that the application is written in some convenient
programming language like C. The reasons for using Tcl are:

   * Flexible input routines

   > By using the scripting capabilities of Tcl one can easily
     adapt the program to the input file or files that it should
     read.

   * Flexible output routines

   > Again, the scripting capabilities allow adapting the output
     to the customer's wishes, without having to recompile and
     link it. This can be done for simple files on disk, but
     also graphical output or storage in a database is possible,
     ''without changing the program itself''.

~ The simplest way: create a bare interpreter

With the Tcl routine Tcl_CreateInterp() you can create an interpreter
that is capable of all the basic commands:

|  Tcl_Interp * interp         ;
|  char       * input_filename ;
|  char       * buffer         ;
|  double       x, y, z        ;
|
|  /* Create the interp, use it to read the given input file,
|     Note:
|     Using the string API for simplicity, no error checking
|  */
|  interp = Tcl_CreateInterp() ;
|  Tcl_SetVar( interp, "input_file", input_filename, TCL_GLOBAL_ONLY ) ;
|  Tcl_EvalFile( interp, startup_script ) ;
|
|  /* Extract the input data
|  */
|  buffer = Tcl_GetVar( interp, "x", TCL_GLOBAL_ONLY ) ;
|  Tcl_GetDouble( interp, buffer, &x ) ;
|  buffer = Tcl_GetVar( interp, "y", TCL_GLOBAL_ONLY ) ;
|  Tcl_GetDouble( interp, buffer, &y ) ;
|  buffer = Tcl_GetVar( interp, "z", TCL_GLOBAL_ONLY ) ;
|  Tcl_GetDouble( interp, buffer, &z ) ;
|
|  /* Destroy the interp - if you do not need it any longer
|  */
|  Tcl_DestroyInterp( interp ) ;

The output routine contains a similar fragment (note, we assume
the Tcl interpreter was stored somewhere):

|  Tcl_Interp * interp                   ;
|  char       * output_filename          ;
|  char         buffer[TCL_DOUBLE_SPACE] ;
|  double       a, b                     ;
|
|  /* Export the results to the interpreter
|  */
|  Tcl_PrintDouble( interp, a, buffer ) ;
|  Tcl_SetVar( interp, "a", buffer, TCL_GLOBAL_ONLY ) ;
|  Tcl_PrintDouble( interp, b, buffer ) ;
|  Tcl_SetVar( interp, "b", buffer, TCL_GLOBAL_ONLY ) ;
|
|  Tcl_SetVar( interp, "output_file", input_filename, TCL_GLOBAL_ONLY ) ;
|  Tcl_EvalFile( interp, report_script ) ;
|

To add error checking (always do!), use code like this:

|
|  Tcl_Channel errChannel ;
|
|  if ( Tcl_EvalFile( ... ) != TCL_OK ) {
|     errChannel = Tcl_GetStdChannel( TCL_STDERR ) ;
|     if ( errChannel != NULL ) {
|        TclWriteObj( errChannel, Tcl_GetObjResult(interp) ) ;
|        TclWriteChars( errChannel, "\n", -1 ) ;
|        ... /* Quit the program or other error handling? */
|     }
|  }


|

With this approach you need only to worry about the Tcl binary
libraries: if the dynamic versions are linked to your application,
then distribution of your application should include these binaries.
If, on the other hand the static versions are used, your application
already contains all of Tcl it needs all by itself.

The limitations of this approach are:

   * The utilities ordinarily defined via the Tcl initialisation
     script ''init.tcl'' are not available. (Note that these
     include such procedures as ''tclPkgSetup'' and ''unknown'')

   * The Tcl variables ''argc'', ''argv'' and ''argv0'' are not set.
     This may be problematic if you want to use these variables to
     communicate with the user, e.g. provide an initial script file
     on the command-line.

   * Character encodings are not available. This will limit your
     application to ASCII characters.

~ Complete initialisation: the role of init.tcl

The next section outlines the full initialisation procedure that is used
in the standard ''tclsh'' shell. This section concentrates instead on
some practical observations:

   * The routine Tcl_FindExecutable() does a lot more than its name
     suggests: it is responsible for initialising the various subsystems
     in a controlled way, it will find all the character encodings.

   > It has to be called very early, before creating an interpreter.
     The results are stored in private variables that are used for
     all threads.

   > If it can not find the executable, no harm is done: it will
     have initialised the subsystems anyway.

   * The routine Tcl_Init() is responsible for setting up the
     script library by evaluating the script ''init.tcl''. It should be
     called after the creation of an interpreter, to add the various
     commands to it.

   > If it can not find this script, it will return with an error.

   > (The routine actually has two additional hooks to allow
     customisation, but these will probably be used in unusual
     circumstances only.)

The script ''init.tcl'' and any it sources (directly or indirectly
via auto_load) must be found via the ''tcl_library'' variable.
On UNIX this variable is initialised via the ''TCL_LIBRARY'' environment
variable is used, whereas on MS Windows the pathname of the Tcl DLLs
is used as well.

As long as these scripts can be found, they can actually reside in a
large number of directories with names related to the Tcl library path.

This leads to the following code to create a full-fledged interpreter:

|  Tcl_Interp * interp         ;
|
|  /* Initialise the Tcl library thouroughly
|  */
|  Tcl_FindExecutable( argv[0] ) ;
|
|  /* Create the interp, evaluate "init.tcl" for the script
|     level initialisation.
|  */
|  interp = Tcl_CreateInterp() ;
|
|  if ( Tcl_Init( interp ) != TCL_OK ) {
|     ... Report the error
|  }

|

With ''init.tcl'' loaded, we have a number of additional commands and
global variables:

   * tclLog, unknown, auto_load, auto_execok are the most important
     ones.

   * auto_path, errorInfo, errorCode

To create an interpreter that can handle Tk as well, you should be
aware of the following:

   * Tk-able interpreters always need to be initialised via Tk_Init()
     and therefore require the start-up scripts: these scripts contain
     the default bindings and resource definitions and are therefore
     indispensable for Tk.

   * An application written using Tk needs to process events in a
     well-defined event loop.

TODO: how to write the event loop, what choices are available?

~ Initialisation via the standard shell

The details of the initialisation done in the standard tclsh shell
are quite intricate. They involve, in addition to the initialisation via
Tcl_FindExecutable() and Tcl_Init() also:

   * processing the command-line arguments

   * customisation via various hooks

   * preparing the Tcl parser by setting the locale to "C", as only
     this guarantees everything works as expected.

A summary of the steps found in the initialisation code is given below:

   * main() is a system-dependent routine which:

   > * sets the locale (Windows version)

   > * parses the command-line according to the UNIX rules (Windows
       version)

   > * calls Tcl_Main(), which is not supposed to return

   * Tcl_Main() takes as arguments the well-known ''argc/argv''
     command-line arguments and a pointer to the initialisation routine,
     which in the case of ''tclsh'' is Tcl_AppInit():

   > * After calling Tcl_FindExecutable(), processing the
       command-line arguments and calling the initialisation routine,
       it can do either of two things:

   > > * Evaluate the script file, if the first argument does not
         start with a minus sign

   > > * Or go into an interactive loop to read the commands from
         the prompt. The preparation in that case is to evaluate
         the start-up script (such as ~/.tclshrc or ~/tclshrc.tcl)

   > * It exits by evaluating the Tcl "exit" command, not by calling
       the C routine ''exit()'' directly

   * The standard initialisation routine Tcl_AppInit() is meant to
     initialise the various application-specific commands and static
     packages via routines like Tcl_CreateCommand(). It also sets the
     Tcl variable "tcl_rcFile" to the user's start-up script.

   > (Curiously, the standard routine is found in a platform-dependent
     source file, tclXXXInit.c)

   * Tcl_Init() by the way provides two hooks for customisation:

   > * A pre-initialisation script that gets evaluated when the
       static variable "tclPreInitScript" has been set.

   > * The initScript variable that defines a Tcl procedure that
       looks up the ''init.tcl'' script.

Thus, before the shell is ready for processing, a lot of initialisation
is done. Much of this process can be customised without the need to
change the standard source files.

~ Overview

This section provides an overview of the resources that an application
requires, given the type of usage:

''Bare Tcl only interpreter:''

   * Just the Tcl dynamic libraries

''Complete initialisation for Tcl only:''

   * The Tcl dynamic libraries

   * The environment variable TCL_LIBRARY

   * The initialisation script file ''init.tcl''

   * The character encoding tables (optional)

''Customised Tcl shell (adapted Tcl_AppInit()):''

   * The Tcl dynamic libraries

   * The environment variable TCL_LIBRARY

   * The initialisation script file ''init.tcl''

   * The character encoding tables (optional)

   * Possibly a so-called RC file to define the initialisation for
     interactive use

''Customised Tk shell (wish; adapted Tk_AppInit()):''

   * The Tcl and Tk dynamic libraries

   * The environment variables TCL_LIBRARY and TK_LIBRARY

   * The initialisation script file ''init.tcl'', and the Tk specific
     bindings (in ''tk.tcl'' and others)

   * The character encoding tables (optional)

   * Possibly a so-called RC file to define the initialisation for
     interactive use

Equally important are the limitations:

''Bare Tcl only interpreter:''

   * No customisable initialisation (not automatically)

   * No access to the command-line arguments or the directory
     that contains the executable

   * No alternative character encodings

   * Possibly problems loading packages, as the auxiliary procedures
     for this are defined in ''init.tcl'' and others.

   * Possibly problems with the locale (best to explicitly set it to
     "C")

   * No interactive use

''Complete initialisation for Tcl only:''

   * Possibly problems with the locale (best to explicitly set it to
     "C")

   * No interactive use

''Customised Tcl shell (adapted Tcl_AppInit()):''

   * None

''Customised Tk shell (wish; adapted Tk_AppInit()):''

   * None

----

~ Compiling and linking

Nowadays, it seems the default to use dynamic or shared libraries. So,
with many installations, there will exist dynamic versions of the
libraries and sometimes there will be no static versions. This has a
number of advantages:

   * The executables are much smaller, the memory usage can be smaller
     as well, as the code will be shared.

   * The libraries can be replaced without the need to rebuild the
     application. This is especially true if you enable the use of
     ''stubs'' for your binary packages (see below).

However, as the Tcl libraries now reside outside your application, they
will have to be shipped with the application and the dynamic loader must
somehow be able to find the libraries. The latter certainly has
consequences: each system tends to have its own method.

When you have the Tcl/Tk sources, you can decide to create your own
libraries. Of special interest are the following two situations:

   * You want to be able to use the ''stubs'' facility, as this makes
     it possible to run with different versions of Tcl/Tk with the same
     binary.

   * You want to get rid of as much extra stuff outside your application
     as possible, so you want to use the static version of the Tcl
     libraries.

''Stubs'' were introduced to make binary extensions and applications
independent of the specific Tcl version. They are enabled by defining
the macro ''TCL_USE_STUBS'' during the compilation and linking
of the Tcl/Tk library and especially your own extension.

In the initialisation procedure for your pacakge or application you need
to initialise the stubs jump table via ''Tcl_InitStubs()'':

| #ifdef USE_TCL_STUBS
|    if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
|       return TCL_ERROR;
|    }

| #endif

(details: [http://mini.net/tcl/1687.html])

The technique, as Brent Welch explains, is simple in principle:

   > By enabling stubs, all calls to Tcl routines are turned into
     function pointers. These pointers are kept in a large table that
     is filled with the correct pointer values via the Tcl_InitStubs()
     routine.

Linking your application or extension should then be done against the
"stub version" of the Tcl/Tk libraries.

If you do not want dynamic libraries, then perhaps a build with the
option ''STATIC_BUILD'' is a solution. With this option, static
libraries are built. The libraries are then incorporated into the
executable itself.

''Note:'' On some platforms, notably Windows, the specific
calling convention is then turned to standard C (with dynamic libraries,
the calling convention exports the various routines explicitly).

When you do not care about the dynamic libraries having to be present,
at least be aware of the way the various systems want to define their
position.

The information above is summarised as follows:

''Using dynamic libraries:''

   * Most UNIX versions and LINUX use the environment
     variable LD_LIBRARY_PATH, colon-separated just like ''PATH''
     to indicate the position of dynamic libraries.

   * Some use the variable SHLIB_PATH instead (notably: HPUX).

   * Under Windows (all flavours) the PATH variable is used and a
     predefined sequence of directories to find the DLL's. One important
     case is that the libraries are found in the same directory as
     the executable.

''Building for general Tcl versions:''

   * Compile your sources with the macro ''TCL_USE_STUBS''

   * Use the proper call to Tcl_InitStubs() to initialise the
     jump table.

   * Link against the stub versions of the Tcl/Tk libraries.

''Building statically:''

   * Use the flag STATIC_BUILD to build the static Tcl/Tk libraries.

   * Use this flag for your own sources as well

   * Link against the static versions.

~ Copyright

This document is placed in the public domain.








|





|



|

|

|


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
<
<
>
>
|










|
|

|







|


|


|



|



|


|
|



|

|

|

|
|
|








|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|

|


|


|




|









|



|










|

|

|
|

|

|

|

|



|


|

|

|
|

|

|
|

|
|

|

|


|
|





|




|



|



|

|

|

|



|

|

|




|



|

|
|

|






|

|







|

|
|



|

|
|



|



|





|











|









|







|

|



|

|
|
|
<
>
|

|





|






|



|
|
|







|


|


|

|




|

|

|




|

|





|


>
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303


304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379

380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588

589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
and the output.

Let us assume that the application is written in some convenient
programming language like C. The reasons for using Tcl are:

   * Flexible input routines

	   > By using the scripting capabilities of Tcl one can easily
     adapt the program to the input file or files that it should
     read.

   * Flexible output routines

	   > Again, the scripting capabilities allow adapting the output
     to the customer's wishes, without having to recompile and
     link it. This can be done for simple files on disk, but
     also graphical output or storage in a database is possible,
     _without changing the program itself_.

# The simplest way: create a bare interpreter

With the Tcl routine Tcl\_CreateInterp\(\) you can create an interpreter
that is capable of all the basic commands:

	  Tcl_Interp * interp         ;
	  char       * input_filename ;
	  char       * buffer         ;
	  double       x, y, z        ;
	
	  /* Create the interp, use it to read the given input file,
	     Note:
	     Using the string API for simplicity, no error checking
	  */
	  interp = Tcl_CreateInterp() ;
	  Tcl_SetVar( interp, "input_file", input_filename, TCL_GLOBAL_ONLY ) ;
	  Tcl_EvalFile( interp, startup_script ) ;
	
	  /* Extract the input data
	  */
	  buffer = Tcl_GetVar( interp, "x", TCL_GLOBAL_ONLY ) ;
	  Tcl_GetDouble( interp, buffer, &x ) ;
	  buffer = Tcl_GetVar( interp, "y", TCL_GLOBAL_ONLY ) ;
	  Tcl_GetDouble( interp, buffer, &y ) ;
	  buffer = Tcl_GetVar( interp, "z", TCL_GLOBAL_ONLY ) ;
	  Tcl_GetDouble( interp, buffer, &z ) ;
	
	  /* Destroy the interp - if you do not need it any longer
	  */
	  Tcl_DestroyInterp( interp ) ;

The output routine contains a similar fragment \(note, we assume
the Tcl interpreter was stored somewhere\):

	  Tcl_Interp * interp                   ;
	  char       * output_filename          ;
	  char         buffer[TCL_DOUBLE_SPACE] ;
	  double       a, b                     ;
	
	  /* Export the results to the interpreter
	  */
	  Tcl_PrintDouble( interp, a, buffer ) ;
	  Tcl_SetVar( interp, "a", buffer, TCL_GLOBAL_ONLY ) ;
	  Tcl_PrintDouble( interp, b, buffer ) ;
	  Tcl_SetVar( interp, "b", buffer, TCL_GLOBAL_ONLY ) ;
	
	  Tcl_SetVar( interp, "output_file", input_filename, TCL_GLOBAL_ONLY ) ;
	  Tcl_EvalFile( interp, report_script ) ;
	

To add error checking \(always do!\), use code like this:

	
	  Tcl_Channel errChannel ;
	
	  if ( Tcl_EvalFile( ... ) != TCL_OK ) {
	     errChannel = Tcl_GetStdChannel( TCL_STDERR ) ;
	     if ( errChannel != NULL ) {
	        TclWriteObj( errChannel, Tcl_GetObjResult(interp) ) ;
	        TclWriteChars( errChannel, "\n", -1 ) ;
	        ... /* Quit the program or other error handling? */


	     }
	  }
	

With this approach you need only to worry about the Tcl binary
libraries: if the dynamic versions are linked to your application,
then distribution of your application should include these binaries.
If, on the other hand the static versions are used, your application
already contains all of Tcl it needs all by itself.

The limitations of this approach are:

   * The utilities ordinarily defined via the Tcl initialisation
     script _init.tcl_ are not available. \(Note that these
     include such procedures as _tclPkgSetup_ and _unknown_\)

   * The Tcl variables _argc_, _argv_ and _argv0_ are not set.
     This may be problematic if you want to use these variables to
     communicate with the user, e.g. provide an initial script file
     on the command-line.

   * Character encodings are not available. This will limit your
     application to ASCII characters.

# Complete initialisation: the role of init.tcl

The next section outlines the full initialisation procedure that is used
in the standard _tclsh_ shell. This section concentrates instead on
some practical observations:

   * The routine Tcl\_FindExecutable\(\) does a lot more than its name
     suggests: it is responsible for initialising the various subsystems
     in a controlled way, it will find all the character encodings.

	   > It has to be called very early, before creating an interpreter.
     The results are stored in private variables that are used for
     all threads.

	   > If it can not find the executable, no harm is done: it will
     have initialised the subsystems anyway.

   * The routine Tcl\_Init\(\) is responsible for setting up the
     script library by evaluating the script _init.tcl_. It should be
     called after the creation of an interpreter, to add the various
     commands to it.

	   > If it can not find this script, it will return with an error.

	   > \(The routine actually has two additional hooks to allow
     customisation, but these will probably be used in unusual
     circumstances only.\)

The script _init.tcl_ and any it sources \(directly or indirectly
via auto\_load\) must be found via the _tcl\_library_ variable.
On UNIX this variable is initialised via the _TCL\_LIBRARY_ environment
variable is used, whereas on MS Windows the pathname of the Tcl DLLs
is used as well.

As long as these scripts can be found, they can actually reside in a
large number of directories with names related to the Tcl library path.

This leads to the following code to create a full-fledged interpreter:

	  Tcl_Interp * interp         ;
	
	  /* Initialise the Tcl library thouroughly
	  */
	  Tcl_FindExecutable( argv[0] ) ;
	
	  /* Create the interp, evaluate "init.tcl" for the script
	     level initialisation.
	  */
	  interp = Tcl_CreateInterp() ;
	
	  if ( Tcl_Init( interp ) != TCL_OK ) {
	     ... Report the error

	  }
	

With _init.tcl_ loaded, we have a number of additional commands and
global variables:

   * tclLog, unknown, auto\_load, auto\_execok are the most important
     ones.

   * auto\_path, errorInfo, errorCode

To create an interpreter that can handle Tk as well, you should be
aware of the following:

   * Tk-able interpreters always need to be initialised via Tk\_Init\(\)
     and therefore require the start-up scripts: these scripts contain
     the default bindings and resource definitions and are therefore
     indispensable for Tk.

   * An application written using Tk needs to process events in a
     well-defined event loop.

TODO: how to write the event loop, what choices are available?

# Initialisation via the standard shell

The details of the initialisation done in the standard tclsh shell
are quite intricate. They involve, in addition to the initialisation via
Tcl\_FindExecutable\(\) and Tcl\_Init\(\) also:

   * processing the command-line arguments

   * customisation via various hooks

   * preparing the Tcl parser by setting the locale to "C", as only
     this guarantees everything works as expected.

A summary of the steps found in the initialisation code is given below:

   * main\(\) is a system-dependent routine which:

	   > \* sets the locale \(Windows version\)

	   > \* parses the command-line according to the UNIX rules \(Windows
       version\)

	   > \* calls Tcl\_Main\(\), which is not supposed to return

   * Tcl\_Main\(\) takes as arguments the well-known _argc/argv_
     command-line arguments and a pointer to the initialisation routine,
     which in the case of _tclsh_ is Tcl\_AppInit\(\):

	   > \* After calling Tcl\_FindExecutable\(\), processing the
       command-line arguments and calling the initialisation routine,
       it can do either of two things:

	   > > \* Evaluate the script file, if the first argument does not
         start with a minus sign

	   > > \* Or go into an interactive loop to read the commands from
         the prompt. The preparation in that case is to evaluate
         the start-up script \(such as ~/.tclshrc or ~/tclshrc.tcl\)

	   > \* It exits by evaluating the Tcl "exit" command, not by calling
       the C routine _exit\(\)_ directly

   * The standard initialisation routine Tcl\_AppInit\(\) is meant to
     initialise the various application-specific commands and static
     packages via routines like Tcl\_CreateCommand\(\). It also sets the
     Tcl variable "tcl\_rcFile" to the user's start-up script.

	   > \(Curiously, the standard routine is found in a platform-dependent
     source file, tclXXXInit.c\)

   * Tcl\_Init\(\) by the way provides two hooks for customisation:

	   > \* A pre-initialisation script that gets evaluated when the
       static variable "tclPreInitScript" has been set.

	   > \* The initScript variable that defines a Tcl procedure that
       looks up the _init.tcl_ script.

Thus, before the shell is ready for processing, a lot of initialisation
is done. Much of this process can be customised without the need to
change the standard source files.

# Overview

This section provides an overview of the resources that an application
requires, given the type of usage:

_Bare Tcl only interpreter:_

   * Just the Tcl dynamic libraries

_Complete initialisation for Tcl only:_

   * The Tcl dynamic libraries

   * The environment variable TCL\_LIBRARY

   * The initialisation script file _init.tcl_

   * The character encoding tables \(optional\)

_Customised Tcl shell \(adapted Tcl\_AppInit\(\)\):_

   * The Tcl dynamic libraries

   * The environment variable TCL\_LIBRARY

   * The initialisation script file _init.tcl_

   * The character encoding tables \(optional\)

   * Possibly a so-called RC file to define the initialisation for
     interactive use

_Customised Tk shell \(wish; adapted Tk\_AppInit\(\)\):_

   * The Tcl and Tk dynamic libraries

   * The environment variables TCL\_LIBRARY and TK\_LIBRARY

   * The initialisation script file _init.tcl_, and the Tk specific
     bindings \(in _tk.tcl_ and others\)

   * The character encoding tables \(optional\)

   * Possibly a so-called RC file to define the initialisation for
     interactive use

Equally important are the limitations:

_Bare Tcl only interpreter:_

   * No customisable initialisation \(not automatically\)

   * No access to the command-line arguments or the directory
     that contains the executable

   * No alternative character encodings

   * Possibly problems loading packages, as the auxiliary procedures
     for this are defined in _init.tcl_ and others.

   * Possibly problems with the locale \(best to explicitly set it to
     "C"\)

   * No interactive use

_Complete initialisation for Tcl only:_

   * Possibly problems with the locale \(best to explicitly set it to
     "C"\)

   * No interactive use

_Customised Tcl shell \(adapted Tcl\_AppInit\(\)\):_

   * None

_Customised Tk shell \(wish; adapted Tk\_AppInit\(\)\):_

   * None

----

# Compiling and linking

Nowadays, it seems the default to use dynamic or shared libraries. So,
with many installations, there will exist dynamic versions of the
libraries and sometimes there will be no static versions. This has a
number of advantages:

   * The executables are much smaller, the memory usage can be smaller
     as well, as the code will be shared.

   * The libraries can be replaced without the need to rebuild the
     application. This is especially true if you enable the use of
     _stubs_ for your binary packages \(see below\).

However, as the Tcl libraries now reside outside your application, they
will have to be shipped with the application and the dynamic loader must
somehow be able to find the libraries. The latter certainly has
consequences: each system tends to have its own method.

When you have the Tcl/Tk sources, you can decide to create your own
libraries. Of special interest are the following two situations:

   * You want to be able to use the _stubs_ facility, as this makes
     it possible to run with different versions of Tcl/Tk with the same
     binary.

   * You want to get rid of as much extra stuff outside your application
     as possible, so you want to use the static version of the Tcl
     libraries.

_Stubs_ were introduced to make binary extensions and applications
independent of the specific Tcl version. They are enabled by defining
the macro _TCL\_USE\_STUBS_ during the compilation and linking
of the Tcl/Tk library and especially your own extension.

In the initialisation procedure for your pacakge or application you need
to initialise the stubs jump table via _Tcl\_InitStubs\(\)_:

	 #ifdef USE_TCL_STUBS
	    if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
	       return TCL_ERROR;

	    }
	 #endif

\(details: <http://mini.net/tcl/1687.html> \)

The technique, as Brent Welch explains, is simple in principle:

   > By enabling stubs, all calls to Tcl routines are turned into
     function pointers. These pointers are kept in a large table that
     is filled with the correct pointer values via the Tcl\_InitStubs\(\)
     routine.

Linking your application or extension should then be done against the
"stub version" of the Tcl/Tk libraries.

If you do not want dynamic libraries, then perhaps a build with the
option _STATIC\_BUILD_ is a solution. With this option, static
libraries are built. The libraries are then incorporated into the
executable itself.

_Note:_ On some platforms, notably Windows, the specific
calling convention is then turned to standard C \(with dynamic libraries,
the calling convention exports the various routines explicitly\).

When you do not care about the dynamic libraries having to be present,
at least be aware of the way the various systems want to define their
position.

The information above is summarised as follows:

_Using dynamic libraries:_

   * Most UNIX versions and LINUX use the environment
     variable LD\_LIBRARY\_PATH, colon-separated just like _PATH_
     to indicate the position of dynamic libraries.

   * Some use the variable SHLIB\_PATH instead \(notably: HPUX\).

   * Under Windows \(all flavours\) the PATH variable is used and a
     predefined sequence of directories to find the DLL's. One important
     case is that the libraries are found in the same directory as
     the executable.

_Building for general Tcl versions:_

   * Compile your sources with the macro _TCL\_USE\_STUBS_

   * Use the proper call to Tcl\_InitStubs\(\) to initialise the
     jump table.

   * Link against the stub versions of the Tcl/Tk libraries.

_Building statically:_

   * Use the flag STATIC\_BUILD to build the static Tcl/Tk libraries.

   * Use this flag for your own sources as well

   * Link against the static versions.

# Copyright

This document is placed in the public domain.

Name change from tip/67.tip to tip/67.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
136
137
138
139
140

141
142
143
144

145
146
147
148
149
150
151
152
153
154
155
156
157
158

TIP:           67
Title:         Allow Subclassing of tk_getOpenFile, tk_getSaveFile on UNIX
Version:       $Revision: 1.5 $
Author:        Chris Nelson <[email protected]>
Author:        Al Zielaskowski <[email protected]>
State:         Withdrawn
Type:          Project
Tcl-Version:   8.5
Vote:          Pending
Created:       09-Oct-2001
Post-History:


~ Abstract

On Microsoft Windows it is possible to "subclass" a standard dialog
and add controls to it.  This TIP proposes adding that feature to the
''tk_getOpenFile'' and ''tk_getSaveFile'' dialogs for non-Windows
systems (wherever ''tkfbox.tcl'' and ''xmfbox.tcl'' are used for these
dialogs).

~ Rationale

In our work with Tk, we have need to save files in various formats and
give the user control over more than just the file name when saving.
While it is possible to have two separate dialogs - one for specifying
the file name and location and another for other attributes - this is
unwieldy and not very user friendly: all the related information
should be in one dialog

On Microsoft Windows, it is possible to add controls to standard
dialogs (indeed any window) via "subclassing" (cf
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/commdlg_4qlv.asp).
(This requires C programming but it is, at least, possible.)

On UNIX, no generic technique like subclassing exists.  Even if we
wished to invade the "standard dialog," - learning about the window's
organization, adding widgets here and there - calling
''tk_getSaveFile'' blocks the caller and then returns a value after
the dialog is destroyed so we have no opportunity to manipulate the
dialog.  To work around this, we need to have ''tk_getSaveFile'' call
back into user code to add controls when the dialog is built.

~ Specification

We add a ''-subclass'' option to ''tk_getSaveFile'' and
''tk_getOpenFile'' (on UNIX only).  The value of the ''-subclass''
option is a Tcl command to evaluate to fill an extra frame near the
bottom of the dialog.  When the dialog is constructed, the subclass
command, if any, is evaluated with the path to the frame appended as
an additional argument.  The subclass command can then fill the frame
as needed.

No additional semantic changes are needed for these additional
controls to communicate with the program as such communication can be
done through side effects.  For example, user interaction with a
checkbox created by the subclass command can be detected after the
''tk_getSaveFile'' dialog is closed by examining the value of the
checkbox's global variable.

~ Reference Implementation

This proposal has been implemented by Al Zielaskowski.  A patch
relative to Tk 8.4a3 follows:

|Index: tkfbox.tcl
|===================================================================
|RCS file: /pti/prod/mrd/CvsRepository/tcl/tk/library/tkfbox.tcl,v
|retrieving revision 1.1.1.1
|diff -u -w -r1.1.1.1 tkfbox.tcl
|--- tkfbox.tcl  2001/09/04 23:51:12     1.1.1.1
|+++ tkfbox.tcl  2001/10/09 19:47:50
|@@ -898,6 +898,7 @@
|        {-initialfile "" "" ""}
|        {-parent "" "" "."}
|        {-title "" "" ""}
|+       {-subclass "" "" ""}
|     }

| 
|     # The "-multiple" option is only available for the "open" file dialog.
|@@ -1087,9 +1088,22 @@
|     # Pack all the frames together. We are done with widget construction.
|     #

|     pack $f1 -side top -fill x -pady 4
|+

|+    #
|+    # Add the user's subclass frame if one was specified
|+    #
|+    if {[string length $data(-subclass)]} {
|+       frame $w.subclass -bd 0
|+       pack $w.subclass -side bottom -fill x \
|+                -padx [list [expr [winfo reqwidth $data(typeMenuLab)] + 8] \
|+               [expr [winfo reqwidth $data(okBtn)] + 8]]
|+       eval $data(-subclass) $w.subclass
|+    }
|+

|     pack $f3 -side bottom -fill x
|     pack $f2 -side bottom -fill x
|     pack $data(icons) -expand yes -fill both -padx 4 -pady 1
|+

| 
|     # Set up the event handlers that are common to Directory and File Dialogs
|     #

|Index: xmfbox.tcl
|===================================================================
|RCS file: /pti/prod/mrd/CvsRepository/tcl/tk/library/xmfbox.tcl,v
|retrieving revision 1.1.1.1
|diff -u -w -r1.1.1.1 xmfbox.tcl
|--- xmfbox.tcl  2001/09/04 23:51:12     1.1.1.1
|+++ xmfbox.tcl  2001/10/09 19:05:57
|@@ -216,6 +216,7 @@
|        {-initialfile "" "" ""}
|        {-parent "" "" "."}
|        {-title "" "" ""}
|+       {-subclass "" "" ""}
|     }

|     if { [string equal $type "open"] } {
|        lappend specs {-multiple "" "" "0"}
|@@ -277,6 +278,7 @@
|     if {![winfo exists $data(-parent)]} {
|        error "bad window path name \"$data(-parent)\""
|     }
|+
| }



| 
| # ::tk::MotifFDialog_BuildUI --
|@@ -360,6 +362,17 @@
| 
|     pack $bot.ok $bot.filter $bot.cancel -padx 10 -pady 10 -expand yes \
|        -side left
|+
|+


|+    #
|+    # Add the user's subclass frame if one was specified
|+    #
|+    if {[string length $data(-subclass)]} {
|+       frame $f3.subclass -bd 0
|+       pack $f3.subclass -side bottom -fill x -padx 4 -pady 4
|+       eval $data(-subclass) $f3.subclass
|+    }
|+

| 
|     # Create the bindings:
|     #


~ Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > This would make porting code between platforms obscenely difficult
   as there is no way for the subclassing to work the same way on all
   platforms.  Better for people to roll their own, perhaps starting
   from the foundations of the UNIX file browsing code if they wish.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|



|
|
|

|









|
|
|




|

|


|

|
|










|


|




|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
<
>
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
<
<
>
>
>
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
<
>
|
|
<
|
>
|










|


>

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
136
137
138

139
140
141

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

# TIP 67: Allow Subclassing of tk_getOpenFile, tk_getSaveFile on UNIX

	Author:        Chris Nelson <[email protected]>
	Author:        Al Zielaskowski <[email protected]>
	State:         Withdrawn
	Type:          Project
	Tcl-Version:   8.5
	Vote:          Pending
	Created:       09-Oct-2001
	Post-History:
-----

# Abstract

On Microsoft Windows it is possible to "subclass" a standard dialog
and add controls to it.  This TIP proposes adding that feature to the
_tk\_getOpenFile_ and _tk\_getSaveFile_ dialogs for non-Windows
systems \(wherever _tkfbox.tcl_ and _xmfbox.tcl_ are used for these
dialogs\).

# Rationale

In our work with Tk, we have need to save files in various formats and
give the user control over more than just the file name when saving.
While it is possible to have two separate dialogs - one for specifying
the file name and location and another for other attributes - this is
unwieldy and not very user friendly: all the related information
should be in one dialog

On Microsoft Windows, it is possible to add controls to standard
dialogs \(indeed any window\) via "subclassing" \(cf
<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/commdlg\_4qlv.asp\).>
\(This requires C programming but it is, at least, possible.\)

On UNIX, no generic technique like subclassing exists.  Even if we
wished to invade the "standard dialog," - learning about the window's
organization, adding widgets here and there - calling
_tk\_getSaveFile_ blocks the caller and then returns a value after
the dialog is destroyed so we have no opportunity to manipulate the
dialog.  To work around this, we need to have _tk\_getSaveFile_ call
back into user code to add controls when the dialog is built.

# Specification

We add a _-subclass_ option to _tk\_getSaveFile_ and
_tk\_getOpenFile_ \(on UNIX only\).  The value of the _-subclass_
option is a Tcl command to evaluate to fill an extra frame near the
bottom of the dialog.  When the dialog is constructed, the subclass
command, if any, is evaluated with the path to the frame appended as
an additional argument.  The subclass command can then fill the frame
as needed.

No additional semantic changes are needed for these additional
controls to communicate with the program as such communication can be
done through side effects.  For example, user interaction with a
checkbox created by the subclass command can be detected after the
_tk\_getSaveFile_ dialog is closed by examining the value of the
checkbox's global variable.

# Reference Implementation

This proposal has been implemented by Al Zielaskowski.  A patch
relative to Tk 8.4a3 follows:

	Index: tkfbox.tcl
	===================================================================
	RCS file: /pti/prod/mrd/CvsRepository/tcl/tk/library/tkfbox.tcl,v
	retrieving revision 1.1.1.1
	diff -u -w -r1.1.1.1 tkfbox.tcl
	--- tkfbox.tcl  2001/09/04 23:51:12     1.1.1.1
	+++ tkfbox.tcl  2001/10/09 19:47:50
	@@ -898,6 +898,7 @@
	        {-initialfile "" "" ""}
	        {-parent "" "" "."}
	        {-title "" "" ""}
	+       {-subclass "" "" ""}

	     }
	 
	     # The "-multiple" option is only available for the "open" file dialog.
	@@ -1087,9 +1088,22 @@
	     # Pack all the frames together. We are done with widget construction.

	     #
	     pack $f1 -side top -fill x -pady 4

	+
	+    #
	+    # Add the user's subclass frame if one was specified
	+    #
	+    if {[string length $data(-subclass)]} {
	+       frame $w.subclass -bd 0
	+       pack $w.subclass -side bottom -fill x \
	+                -padx [list [expr [winfo reqwidth $data(typeMenuLab)] + 8] \
	+               [expr [winfo reqwidth $data(okBtn)] + 8]]
	+       eval $data(-subclass) $w.subclass
	+    }

	+
	     pack $f3 -side bottom -fill x
	     pack $f2 -side bottom -fill x
	     pack $data(icons) -expand yes -fill both -padx 4 -pady 1

	+
	 
	     # Set up the event handlers that are common to Directory and File Dialogs

	     #
	Index: xmfbox.tcl
	===================================================================
	RCS file: /pti/prod/mrd/CvsRepository/tcl/tk/library/xmfbox.tcl,v
	retrieving revision 1.1.1.1
	diff -u -w -r1.1.1.1 xmfbox.tcl
	--- xmfbox.tcl  2001/09/04 23:51:12     1.1.1.1
	+++ xmfbox.tcl  2001/10/09 19:05:57
	@@ -216,6 +216,7 @@
	        {-initialfile "" "" ""}
	        {-parent "" "" "."}
	        {-title "" "" ""}
	+       {-subclass "" "" ""}

	     }
	     if { [string equal $type "open"] } {
	        lappend specs {-multiple "" "" "0"}
	@@ -277,6 +278,7 @@
	     if {![winfo exists $data(-parent)]} {
	        error "bad window path name \"$data(-parent)\""



	     }
	+
	 }
	 
	 # ::tk::MotifFDialog_BuildUI --
	@@ -360,6 +362,17 @@
	 
	     pack $bot.ok $bot.filter $bot.cancel -padx 10 -pady 10 -expand yes \
	        -side left


	+
	+
	+    #
	+    # Add the user's subclass frame if one was specified
	+    #
	+    if {[string length $data(-subclass)]} {
	+       frame $f3.subclass -bd 0
	+       pack $f3.subclass -side bottom -fill x -padx 4 -pady 4
	+       eval $data(-subclass) $f3.subclass
	+    }

	+
	 
	     # Create the bindings:

	     #

# Notice of Withdrawal

This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list.  The following is a summary of reasons for
withdrawal:

 > This would make porting code between platforms obscenely difficult
   as there is no way for the subclassing to work the same way on all
   platforms.  Better for people to roll their own, perhaps starting
   from the foundations of the UNIX file browsing code if they wish.

# Copyright

This document has been placed in the public domain.

Name change from tip/68.tip to tip/68.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

TIP:		68
Title:		Dynamic Trace Result Handling
Version:	$Revision: 1.5 $
Author:		Donal K. Fellows <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.4
Vote:		Done
Created:	16-Oct-2001
Post-History:	


~ Abstract

This TIP proposes an extension to the ''Tcl_TraceVar'' API to cope
with dynamically allocated results.

~ Rationale

The current API for handling errors during variable accesses is based
on static strings, which is perfectly adequate for the errors that Tcl
generates of its own accord, but which is substantially at odds with
the setting of traces on variables which may produce errors.  The
problem is that as those errors come from a Tcl script, they are
allocated dynamically and fail to satisfy the static allocation rule
mentioned previously.  Normally this does not cause a problem, but
under some circumstances (as set out in Bug #219393
http://sf.net/tracker/?func=detail&aid=219393&group_id=10894&atid=110894)
it is possible for this to cause a memory fault or even memory
corruption.  This is because it can sometimes happen that the pointer
to the supposedly static string winds up dangling as the string it was
pointing to gets deleted out from underneath it (the storage area used
to static-ify the string is part of the trace structure, but the trace
is permitted to delete that structure...)  Obviously this is not
desirable!

There are several possible fixes, but the two main ones are to:

 1. use the ''Tcl_Preserve'' mechanism to postpone deletion of the
    allocated memory block until it has been copied into something
    more permanent.

 2. add special handling so as to mark the error result coming back
    from the trace mechanism as something other than a static string.
    The main alternatives here are:

 > * A dynamically-allocated C string, to be disposed of with
     ''ckfree''.

 > * A dynamically-allocated ''Tcl_Obj'' reference, to be disposed of
     with a single call to ''Tcl_DecrRefCount''.

Although option 1 is the easiest to implement, it has the disadvantage
of putting a new ''non-obvious'' requirement on all variable traces,
and that is that their results are all ''Tcl_Preserve''d before the
end of the trace.  This is feasible for the Tcl core, but unreasonable
to ask of extension writers.

Instead I prefer option 2, and it is possible to introduce this change
in such a way that existing software does not see an API change (i.e.
there are no serious backward-compatibility issues) and both styles of
result listed above are supported.  The advantage of supporting both
of these is that dynamically allocated strings are a very easy
interface for extension writers to use though not particularly
efficient, and objects are a very efficient interface well-suited to
the core itself but are not as easy to use.  (It is far easier to
adapt existing code to use dynamic strings as no understanding of
lifespan management is required.)

~ Changes

To achieve this, the following new flags will be defined:

|#define TCL_TRACE_RESULT_DYNAMIC  0x2000
|#define TCL_TRACE_RESULT_OBJECT   0x4000

These flags, when passed to the ''flags'' argument of ''Tcl_TraceVar''
(and related functions) alter the interpretation of the value returned
by the call to the ''proc'' parameter from the default behaviour (a
static string) to be either a string to be deallocated by Tcl as and
when it sees fit using ''ckfree'' (when ''TCL_TRACE_RESULT_DYNAMIC''
is specified) or to be a ''Tcl_Obj'' (which must be cast to a ''char
*'' for type compatibility) to be disposed of when the error message
is no longer required (when ''TCL_TRACE_RESULT_OBJECT'' is specified.)
It is an error to specify both flags on the same call.

The core will then be modified to use this mechanism for variable
traces as set up by the ''trace'' command.

~ Copyright

This TIP is placed in the public domain.

~ Reference

For reference, the pre-TIP definition of the ''Tcl_TraceVar'' function
is as follows:

|     int
|     Tcl_TraceVar(Tcl_Interp *interp, char *varName, int flags,
|                  Tcl_VarTraceProc *proc, ClientData clientData)

(There is a corresponding function that takes the variable name as a
pair of strings.)  All parameters have the usual obvious
interpretations, with the ''flags'' being an OR-ed combination of the
following flags:

  TCL_TRACE_READS: Invoke the callback when the variable is read.

  TCL_TRACE_WRITES: Invoke the callback when the variable is written.

  TCL_TRACE_UNSETS: Invoke the callback when the variable is unset.

  TCL_TRACE_ARRAY: Invoke the callback when the variable is accessed
     as an array.

  TCL_GLOBAL_ONLY: Force the lookup of the variable in the global
     scope, and not the current one.

<
|
<
|
|
|
|
|
|
|
>

|

|


|








|
|



|

|




|







|
|

|
|


|
|




|
|




|

|

|



|
|

|
|
|
|
|
|
|
|



|

|



|

|


|
|
|

|
|
|


|

|

|

|


|

>

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

# TIP 68: Dynamic Trace Result Handling

	Author:		Donal K. Fellows <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.4
	Vote:		Done
	Created:	16-Oct-2001
	Post-History:	
-----

# Abstract

This TIP proposes an extension to the _Tcl\_TraceVar_ API to cope
with dynamically allocated results.

# Rationale

The current API for handling errors during variable accesses is based
on static strings, which is perfectly adequate for the errors that Tcl
generates of its own accord, but which is substantially at odds with
the setting of traces on variables which may produce errors.  The
problem is that as those errors come from a Tcl script, they are
allocated dynamically and fail to satisfy the static allocation rule
mentioned previously.  Normally this does not cause a problem, but
under some circumstances \(as set out in Bug \#219393
<http://sf.net/tracker/?func=detail&aid=219393&group\_id=10894&atid=110894\)>
it is possible for this to cause a memory fault or even memory
corruption.  This is because it can sometimes happen that the pointer
to the supposedly static string winds up dangling as the string it was
pointing to gets deleted out from underneath it \(the storage area used
to static-ify the string is part of the trace structure, but the trace
is permitted to delete that structure...\)  Obviously this is not
desirable!

There are several possible fixes, but the two main ones are to:

 1. use the _Tcl\_Preserve_ mechanism to postpone deletion of the
    allocated memory block until it has been copied into something
    more permanent.

 2. add special handling so as to mark the error result coming back
    from the trace mechanism as something other than a static string.
    The main alternatives here are:

	 > \* A dynamically-allocated C string, to be disposed of with
     _ckfree_.

	 > \* A dynamically-allocated _Tcl\_Obj_ reference, to be disposed of
     with a single call to _Tcl\_DecrRefCount_.

Although option 1 is the easiest to implement, it has the disadvantage
of putting a new _non-obvious_ requirement on all variable traces,
and that is that their results are all _Tcl\_Preserve_d before the
end of the trace.  This is feasible for the Tcl core, but unreasonable
to ask of extension writers.

Instead I prefer option 2, and it is possible to introduce this change
in such a way that existing software does not see an API change \(i.e.
there are no serious backward-compatibility issues\) and both styles of
result listed above are supported.  The advantage of supporting both
of these is that dynamically allocated strings are a very easy
interface for extension writers to use though not particularly
efficient, and objects are a very efficient interface well-suited to
the core itself but are not as easy to use.  \(It is far easier to
adapt existing code to use dynamic strings as no understanding of
lifespan management is required.\)

# Changes

To achieve this, the following new flags will be defined:

	#define TCL_TRACE_RESULT_DYNAMIC  0x2000
	#define TCL_TRACE_RESULT_OBJECT   0x4000

These flags, when passed to the _flags_ argument of _Tcl\_TraceVar_
\(and related functions\) alter the interpretation of the value returned
by the call to the _proc_ parameter from the default behaviour \(a
static string\) to be either a string to be deallocated by Tcl as and
when it sees fit using _ckfree_ \(when _TCL\_TRACE\_RESULT\_DYNAMIC_
is specified\) or to be a _Tcl\_Obj_ \(which must be cast to a _char
*_ for type compatibility\) to be disposed of when the error message
is no longer required \(when _TCL\_TRACE\_RESULT\_OBJECT_ is specified.\)
It is an error to specify both flags on the same call.

The core will then be modified to use this mechanism for variable
traces as set up by the _trace_ command.

# Copyright

This TIP is placed in the public domain.

# Reference

For reference, the pre-TIP definition of the _Tcl\_TraceVar_ function
is as follows:

	     int
	     Tcl_TraceVar(Tcl_Interp *interp, char *varName, int flags,
	                  Tcl_VarTraceProc *proc, ClientData clientData)

\(There is a corresponding function that takes the variable name as a
pair of strings.\)  All parameters have the usual obvious
interpretations, with the _flags_ being an OR-ed combination of the
following flags:

  TCL\_TRACE\_READS: Invoke the callback when the variable is read.

  TCL\_TRACE\_WRITES: Invoke the callback when the variable is written.

  TCL\_TRACE\_UNSETS: Invoke the callback when the variable is unset.

  TCL\_TRACE\_ARRAY: Invoke the callback when the variable is accessed
     as an array.

  TCL\_GLOBAL\_ONLY: Force the lookup of the variable in the global
     scope, and not the current one.

Name change from tip/69.tip to tip/69.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
136
137
138
139
140
141
142
143
144
145
146
147
148

149
150
151
152
153

154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179

180
181
182
183
184


185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

200
201
202
203
204


205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

228
229
230
231
232
233
234




235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396

397
398
399
400
401

402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474

TIP:            69
Title:          Improvements for the Tcl Hash Table
Version:        $Revision: 1.10 $
Author:         George A. Howlett <[email protected]>
Author:         Don Porter <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        16-Oct-2001
Post-History:   
Discussions-To: news:comp.lang.tcl
Tcl-Version:    9.0


~ Abstract

This document describes various improvements to the existing Tcl hash
table.  They include support for 64 bit platforms, better memory
performance, and improved array hashing.  The goal is a hash table
that improves Tcl/Tk, but also can be used in industrial strength
applications.

~ Introduction

A strength of Tcl that has not diminished in the advance of other
scripting languages (Perl, Python, Ruby, etc.) is the easy way its
command language can be extended with C/C++ code.  For example, the
prominence of Tcl in Electronic Design Automation (EDA) tools is
striking.  It's hard to find EDA tools that do not use Tcl to some
degree.  At the same time, there is a current trend toward 64-bit
computing platforms.  The impetus has been from industry (like EDA)
rather than office or home users, wanting to solve bigger problems,
faster.  If Tcl applications are to operate on 64-bit platforms, a big
first step towards this goal will be a 64-bit version of the Tcl hash
table.

The current Tcl hash table performs well on 32-bit platforms.  It has
been tuned and wrung out handling internal Tcl/Tk code.  But its one
word hash function

| #define RANDOM_INDEX(tablePtr, i) \
|    (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask)

can not hash the longer 64-bit addresses properly.  

Example:

|    Tcl_HashTable t;
|    unsigned long i;
|    char *base, *addr;	
|    int isNew;
|    char *mesg;
|
|    Tcl_InitHashTable(&t, TCL_ONE_WORD_KEYS);
|    base = 0xFFFFFF000000000UL;
|    for (i = 0; i < 100; i++) {
|        addr = base + i * 0x100000000;
|        hPtr = Tcl_CreateHashEntry(&t, addr, &isNew);
|    }

|    mesg = Tcl_HashStats(&t);
|    fprintf(stderr, "Stats\n%s\n", mesg);
|    free((char *)mesg;

Note that the keys all have zeros in the lower 32 bits.  All 100
entries will hash to the same value.  Driving the need for 64-bit
systems is the ability to address more memory.  So it's imperative
that Tcl hash table be able to hash large virtual addresses.

Building upon the current hash table implementation, the following
sections describe specific areas for improvement:

	* improved array/structure hashing

	* better memory performance 

	* support for 64-bit platforms

The goal is an improved Tcl hash table for internal Tcl and Tk code,
but also high performance applications.

~ Improved Array/Structure Hashing

The Tcl hash table handles three types of hash keys: string keys, one
word keys, and multi-word keys.  Each key type has its own hash
function associated with it.  The benefit of this approach is that
better hash functions can be used for the specific types, than one
general function for all types.  The string and one word hash
functions are very good for typical keys.  The multi-word or array
hash is not as good.

The array hash sums the each word of the array and then randomizes
the result.  

|    for (index = 0, count = tablePtr->keyType, iPtr1 = arrayPtr;
|	    count > 0; count--, iPtr1++) {
|	index += *iPtr1;
|    }

|    index = RANDOM_INDEX(tablePtr, index);

This works poorly for many types of hash keys.  For an contrived
example of hashing 1 million 3D coordinates,

|    typedef struct {
|       double x, y, z;
|    }  Double3;
|    double d3;
|
|    Tcl_InitHashTable(&t, sizeof(Double3) / sizeof(int));
|	
|    for (i = 0; i < 100; i++) {
|	for (j = 0; j < 100; j++) {
|	    for (k = 0; k < 100; k++) {
|		d3.x = (double)i;
|		d3.y = (double)j;
|		d3.z = (double)k;
|		hPtr = Tcl_CreateHashEntry(&t, (char *)&d3, &isNew);
|	    }
|	}
|    }




we get a hash table with an average search distance of 1082.3.  The
maximum distance is 3324!  Replacing the hash function with Bob
Jenkins' [http://burtleburtle.net/bob] 32-bit mixing function

|   #define MIX32(a,b,c) \
|	a -= b, a -= c, a ^= (c >> 13), \
|	b -= c, b -= a, b ^= (a <<  8), \
|	c -= a, c -= b, c ^= (b >> 13), \
|	a -= b, a -= c, a ^= (c >> 12), \
|	b -= c, b -= a, b ^= (a << 16), \
|	c -= a, c -= b, c ^= (b >>  5), \
|	a -= b, a -= c, a ^= (c >>  3), \
|	b -= c, b -= a, b ^= (a << 10), \
|	c -= a, c -= b, c ^= (b >> 15)
|
|   int a, b, c, len;
|
|   len = length;
|   a = b = GOLDEN_RATIO32;	/* An arbitrary value */
|   c = 0;			/* Previous hash value */
|
|   while (len >= 3) {		/* Handle most of the key */
|	a += key[0];
|	b += key[1];
|	c += key[2];
|	MIX32(a, b, c);
|	key += 3; len -= 3;
|    }

|    c += length;		
|    switch(len) {
|    case 2 : b += key[1];
|    case 1 : a += key[0];
|    }

|    MIX32(a, b, c);
|    return c;

yields a table with an average search distance of 1.48.  The maximum
distance is 8.  The Jenkins' hash function provides good results for
many different types of arrays and structures.  The disadvantage is
that the hash function is slightly more expensive to compute.  

~ Improving RebuildTable.

The cost of computing a hash function is especially felt each time
table is rebuilt as new entries are added.  The ''RebuildTable'' function
calls the hash function of each entry to recompute its new location in
the bigger table.

|    for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) {
|	for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) {
|	    *oldChainPtr = hPtr->nextPtr;
|	    if (tablePtr->keyType == TCL_STRING_KEYS) {
|		index = HashString(hPtr->key.string) & tablePtr->mask;
|	    } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
|		index = RANDOM_INDEX(tablePtr, hPtr->key.oneWordValue);
|	    } else {
|		index = HashArray(hPtr->key.words, tablePtr->keyType) &
|			tablePtr->mask;
|	    }

|	    hPtr->bucketPtr = &(tablePtr->buckets[index]);
|	    hPtr->nextPtr = *hPtr->bucketPtr;
|	    *hPtr->bucketPtr = hPtr;
|	}
|    }



The new bucket location is then stored in the hash entry.

Except for one word keys, the hash value is invariant of the table
size.  If the hash value was stored with each entry, then it would not
need to be recomputed each time the table is rebuilt.

|    for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) {
|	for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) {
|	    *oldChainPtr = hPtr->nextPtr;
|	    if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
|		index = RANDOM_INDEX(tablePtr, hPtr->key.oneWordValue);
|	    } else {
|		index = hPtr->hval & tablePtr->mask;
|	    }

|	    hPtr->bucketPtr = &(tablePtr->buckets[index]);
|	    hPtr->nextPtr = *hPtr->bucketPtr;
|	    *hPtr->bucketPtr = hPtr;
|	}
|    }



This would increase size of an hash entry, except that the pointer to
the hash bucket is now redundant, since it can cheaply be computed.

|    bucketPtr = tablePtr->buckets + (hPtr->hval & tablePtr->mask);

An added benefit is that hash table lookups become faster and easier
to perform.  If there is more than one hash entry in a bucket, you
don't need to examine the key unless the entry has the same hash
value.

|    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
|	    hPtr = hPtr->nextPtr) {
|       /* Don't look at entry unless the hash value is the same. */
|	if (hPtr->hval == hval) { 
|	    register int *iPtr1, *iPtr2;
|	    int count;
|
|	    for (iPtr1 = arrayPtr, iPtr2 = (int *)hPtr->key.words,
|		     count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) {
|		if (count == 0) {
|		    return hPtr;
|		}

|		if (*iPtr1 != *iPtr2) {
|		    break;
|		}
|	    }
|	}
|    }





''Don Porter <[email protected]>''

 > ''It appears that the recommendations of this section have already
   been implemented in Tcl 8.4.  In particular, when the symbol
   TCL_HASH_KEY_STORE_HASH == 1 (as it does by default), then the
   hash value is stored in each entry instead of the bucketPtr.''

 > ''If that is correct, then I recommend this section of the TIP be
   removed.  If not, more detail about how this proposal differs
   from the 8.4 implementation, and an argument why the proposal
   is superior are in order.''

~ Better Memory Performance 

One enduring complaint of the Tcl hash table on comp.lang.tcl is its
unexpected memory costs.  A table of 1 million one word key entries
uses over 36 Megabytes.

A hash entry is 20 bytes long.

| typedef struct Tcl_HashEntry {
|    struct Tcl_HashEntry *nextPtr;	/* Pointer to next entry in this
|					 * hash bucket, or NULL for end of
|					 * chain. */
|    struct Tcl_HashTable *tablePtr;	/* Pointer to table containing entry. */
|    struct Tcl_HashEntry **bucketPtr;	/* Pointer to bucket that points to
|					 * first entry in this entry's chain:
|					 * used for deleting the entry. */
|    ClientData clientData;		/* Application stores something here
|					 * with Tcl_SetHashValue. */
|    union {				/* Key has one of these forms: */
|	char *oneWordValue;		/* One-word value for key. */
|	int words[1];			/* Multiple integer words for key.
|					 * The actual size will be as large
|					 * as necessary for this table's
|					 * keys. */
|	char string[4];			/* String for key.  The actual size
|					 * will be as large as needed to hold
|					 * the key. */
|    } key;				/* MUST BE LAST FIELD IN RECORD!! */
| } Tcl_HashEntry;

Each entry stores a pointer to its hash table.  This field is used
only for deleting a hash entry.  But if the hash table is passed to
''Tcl_DeleteHashEntry'', the hash entry can be reduced to 16 bytes.
Inspecting Tcl/Tk code, I could not find a case where the hash table
was not easily available to pass as a parameter.

Each hash entry is allocated using ''malloc''.  System memory
allocators typically add 8-16 bytes overhead for each allocation.
Worse, calls to ''malloc'' and ''free'' tend to dominate the cost of
large hash tables.  ''Tcl_DeleteHashTable'' becomes very slow, freeing
hash entries scattered across pages of virtual memory.

For large hash tables, a pool allocation scheme can improve both
reduce the amount of memory used and improve memory performance.  By
allocating memory in larger chunks, the number of ''malloc'' and
''free'' calls is dramatically reduced.  Fixed size allocators (one
word keys and array keys) can also reclaim and reuse memory from
deleted entries.

The disadvantage of pool allocation is that memory is not released
until the hash table is deleted.  This is less of an issue for large
tables which tend to grow to a steady-state size.  Both Tcl and Tk use
hash tables to keep track of small amounts of information that
probably don't pool allocation.

So to retain compatibility, a new specialized initialization routine
can be used to indicate when to use pool-based allocation.

|    Tcl_InitHashTableWithPool(&table, TCL_ONE_WORD_KEYS);

The standard ''Tcl_InitHashTable'' call

|    Tcl_InitHashTable(&table, TCL_ONE_WORD_KEYS);

will still use ''malloc'' and ''free''.

~ Support for 64-bit Platforms.

While the C language makes no guarantees of a type's size or its
relation to other types, current programming practice assumes that
integers, longs, and pointers are all 32 bits long.  This, of course,
changes with 64-bit systems where pointers are 64-bits wide.
Depending upon the programming model, longs and ints may or may not be
64 bits too.

| Datatype      LP64    ILP64   LLP64   ILP32   LP32
|  char           8       8       8       8       8
|  short         16      16      16      16      16
|  _int32                        32
| int            32      64      32      32      16
| long           64      64      32      32      32
| long long                      64
| pointer        64      64      64      32      32

ILP32 is typical for 32 bit systems.  Windows 3.1 was a LP32 model.

In the LP64 model, pointers and longs are 64 bits, but ints remain 32
bits wide.  The LLP model retains the 32-bits for ints and longs, but
adds a 64-bit "long long" type.  Most 64-bit Unix systems (Solaris,
HP-UX, Tru64, AIX) are LP64.  I believe that Win64 is LLP.

The first problem is that addresses are now 64-bits, not 32.  This
means that existing code such as

|    Tcl_InitHashTable(&table, TCL_ONE_WORD_KEYS);
|
|    ptr = CreateSomeObject();
|    hPtr = Tcl_CreateHashEntry(&table, (void *)ptr, &isNew);

can possibly fail because the 32-bit one word hash function can't
properly hash the 64-bit pointer address.

''Don Porter <[email protected]>''

 > ''Pardon the interruption, but I do not understand what is meant
   by the assertion that hashing of 64-bit pointers "can possibly
   fail".  I've used Tcl on a 64-bit Alpha system for years, hashing
   64-bit pointers the whole time.  What failures should I be seeing?''

| #define RANDOM_INDEX(tablePtr, i) \
|    (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask)

The above one word hash function can be replaced with a 64-bit version
of Donald Knuth's multiplicative hash function.

|    ((key * GOLDEN_RATIO64) >> downShift) & tablePtr->mask)

where downShift is 64 - log2(tableSize) and the GOLDEN_RATION64 is a
prime approximately equal to (sqrt(64) - 1) / 2.  

The 64-bit array function is again from Bob Jenkins.  This time it's a
64-bit mixing function.

| #define MIX64(a,b,c) \
| 	a -= b, a -= c, a ^= (c >> 43), \
| 	b -= c, b -= a, b ^= (a <<  9), \
| 	c -= a, c -= b, c ^= (b >>  8), \
| 	a -= b, a -= c, a ^= (c >> 38), \
| 	b -= c, b -= a, b ^= (a << 23), \
| 	c -= a, c -= b, c ^= (b >>  5), \
| 	a -= b, a -= c, a ^= (c >> 35), \
| 	b -= c, b -= a, b ^= (a << 49), \
| 	c -= a, c -= b, c ^= (b >> 11), \
| 	a -= b, a -= c, a ^= (c >> 12), \
| 	b -= c, b -= a, b ^= (a << 18), \
| 	c -= a, c -= b, c ^= (b >> 22)
| 
|     uint64_t a, b, c, len;
| 
|     len = length;
|     a = b = GOLDEN_RATIO64;	/* An arbitrary value */
|     c = 0;			/* Previous hash value */
| 
|     while (len >= 3) {	/* Handle most of the key */
| 	a += key[0];
| 	b += key[1];
| 	c += key[2];
| 	MIX64(a,b,c);
| 	key += 3; len -= 3;
|     }

|     c += length;		
|     switch(len) {
|     case 2 : b += key[1];
|     case 1 : a += key[0];
|     }

|     MIX64(a,b,c);
|     return c;

Note that it also takes advantage of the 64-bit word size.

~ Summary

The following improvements to the current Tcl hash table have been
suggested.  

 * Replace the current array hash function.

 * Replace the bucket pointer in the hash entry with its hash value.
   This allows the table to be rebuilt without rehashing each entry.
   It also speeds bucket searches.

 * Remove the tablePtr from the hash entry, a 20% savings.  This
   requires that callers of ''Tcl_DeleteHashEntry'' pass the hash
   table as a parameter.

 * Allow the hash table to use fixed or variable size pool allocation
   since ''malloc'' and ''free'' costs dominate large tables.  Pool
   allocation substantial speeds large tables while also saving 8-16
   bytes per entry.  This can be done while still providing the normal
   ''malloc''/''free'' versions.

 * Support 64-bit platforms.  This requires 64-bit versions of one
   word and array hash functions.

The suggested changes are nothing new and can be found in most hash
table implementations.  This work builds on the already solid
foundation of the current hash table.  With the above improvements,
the Tcl hash table can be used in high performance applications.  It
also adds a useful piece to the 64-bit Tcl/Tk port.

I've created and tested a new hash table implementation under the
following systems.

|	System			32     64
|	linux-ix86-gcc		x	
|	Solaris-v9-cc		x	x
|	Solaris-v9-gcc		x	x
|	HPUX-11-cc		x	x
| 	HPUX-11-gcc		x
|	Win2k			x

It will be made publicly available on SourceForge.

~ Hashing of Malicious Strings

''Donal K. Fellows adds:''

In 2003 a possible denial-of-service attack on hash tables was published
that operated by making a majority of keys map to the same bucket.  While
this would not make the hashes function incorrectly - there would be no
extra memory consumed or incorrect accesses to memory - it still permits
an attacker to escalate the cost of hash accesses from O(1) to O(n) in
the normal case (and with obvious knock-on effects for the order of other
algorithms) and so mount an attack out-of-scale with the effort required
to set the attack up.

The way to fix this is to use a different hashing function for string
hashing that varies the exact hashing algorithm on a table-by-table
basis, and to base that algorithm on a hashing function with better
spectral properties than Tcl's current (extremely simple) one.  An
algorithm that might be suitable for such uses is described online
[http://burtleburtle.net/bob/hash/evahash.html] though the code would
need substantial adaption (including the addition of a fairly strong
random number generator) before being placed in the core.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|







|


|
|
|


|









|
|





|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|


















|












|
|
|
<
>
|




|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<
>
>
>



|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|






|


|



|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
<
<
>
>







|
|
|
|
|
|
|
<
>
|
|
|
<
<
>
>




|






|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
<
<
<
<
|
>
>
>
>
|

|

|
|

|


|

|







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|



|



|

|
|




|
|
|











|

|

|

|

|








|
|
|
|
|
|
|
|





|
|




|
|
|
|




|

|


|

|
|




|

|
|




|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|



|











|



|


|













|
|
|
|
|
|
|



|

|





|
|
|





|

|
|
|

|


>

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
136
137
138
139
140
141
142
143
144
145
146

147
148
149
150
151

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

178
179
180
181


182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197

198
199
200
201


202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225

226
227
228




229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394

395
396
397
398
399

400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474

# TIP 69: Improvements for the Tcl Hash Table

	Author:         George A. Howlett <[email protected]>
	Author:         Don Porter <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        16-Oct-2001
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Tcl-Version:    9.0
-----

# Abstract

This document describes various improvements to the existing Tcl hash
table.  They include support for 64 bit platforms, better memory
performance, and improved array hashing.  The goal is a hash table
that improves Tcl/Tk, but also can be used in industrial strength
applications.

# Introduction

A strength of Tcl that has not diminished in the advance of other
scripting languages \(Perl, Python, Ruby, etc.\) is the easy way its
command language can be extended with C/C\+\+ code.  For example, the
prominence of Tcl in Electronic Design Automation \(EDA\) tools is
striking.  It's hard to find EDA tools that do not use Tcl to some
degree.  At the same time, there is a current trend toward 64-bit
computing platforms.  The impetus has been from industry \(like EDA\)
rather than office or home users, wanting to solve bigger problems,
faster.  If Tcl applications are to operate on 64-bit platforms, a big
first step towards this goal will be a 64-bit version of the Tcl hash
table.

The current Tcl hash table performs well on 32-bit platforms.  It has
been tuned and wrung out handling internal Tcl/Tk code.  But its one
word hash function

	 #define RANDOM_INDEX(tablePtr, i) \
	    (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask)

can not hash the longer 64-bit addresses properly.  

Example:

	    Tcl_HashTable t;
	    unsigned long i;
	    char *base, *addr;	
	    int isNew;
	    char *mesg;
	
	    Tcl_InitHashTable(&t, TCL_ONE_WORD_KEYS);
	    base = 0xFFFFFF000000000UL;
	    for (i = 0; i < 100; i++) {
	        addr = base + i * 0x100000000;
	        hPtr = Tcl_CreateHashEntry(&t, addr, &isNew);

	    }
	    mesg = Tcl_HashStats(&t);
	    fprintf(stderr, "Stats\n%s\n", mesg);
	    free((char *)mesg;

Note that the keys all have zeros in the lower 32 bits.  All 100
entries will hash to the same value.  Driving the need for 64-bit
systems is the ability to address more memory.  So it's imperative
that Tcl hash table be able to hash large virtual addresses.

Building upon the current hash table implementation, the following
sections describe specific areas for improvement:

	* improved array/structure hashing

	* better memory performance 

	* support for 64-bit platforms

The goal is an improved Tcl hash table for internal Tcl and Tk code,
but also high performance applications.

# Improved Array/Structure Hashing

The Tcl hash table handles three types of hash keys: string keys, one
word keys, and multi-word keys.  Each key type has its own hash
function associated with it.  The benefit of this approach is that
better hash functions can be used for the specific types, than one
general function for all types.  The string and one word hash
functions are very good for typical keys.  The multi-word or array
hash is not as good.

The array hash sums the each word of the array and then randomizes
the result.  

	    for (index = 0, count = tablePtr->keyType, iPtr1 = arrayPtr;
		    count > 0; count--, iPtr1++) {
		index += *iPtr1;

	    }
	    index = RANDOM_INDEX(tablePtr, index);

This works poorly for many types of hash keys.  For an contrived
example of hashing 1 million 3D coordinates,

	    typedef struct {
	       double x, y, z;
	    }  Double3;
	    double d3;
	
	    Tcl_InitHashTable(&t, sizeof(Double3) / sizeof(int));
		
	    for (i = 0; i < 100; i++) {
		for (j = 0; j < 100; j++) {
		    for (k = 0; k < 100; k++) {
			d3.x = (double)i;
			d3.y = (double)j;
			d3.z = (double)k;
			hPtr = Tcl_CreateHashEntry(&t, (char *)&d3, &isNew);



		    }
		}
	    }

we get a hash table with an average search distance of 1082.3.  The
maximum distance is 3324!  Replacing the hash function with Bob
Jenkins' <http://burtleburtle.net/bob>  32-bit mixing function

	   #define MIX32(a,b,c) \
		a -= b, a -= c, a ^= (c >> 13), \
		b -= c, b -= a, b ^= (a <<  8), \
		c -= a, c -= b, c ^= (b >> 13), \
		a -= b, a -= c, a ^= (c >> 12), \
		b -= c, b -= a, b ^= (a << 16), \
		c -= a, c -= b, c ^= (b >>  5), \
		a -= b, a -= c, a ^= (c >>  3), \
		b -= c, b -= a, b ^= (a << 10), \
		c -= a, c -= b, c ^= (b >> 15)
	
	   int a, b, c, len;
	
	   len = length;
	   a = b = GOLDEN_RATIO32;	/* An arbitrary value */
	   c = 0;			/* Previous hash value */
	
	   while (len >= 3) {		/* Handle most of the key */
		a += key[0];
		b += key[1];
		c += key[2];
		MIX32(a, b, c);
		key += 3; len -= 3;

	    }
	    c += length;		
	    switch(len) {
	    case 2 : b += key[1];
	    case 1 : a += key[0];

	    }
	    MIX32(a, b, c);
	    return c;

yields a table with an average search distance of 1.48.  The maximum
distance is 8.  The Jenkins' hash function provides good results for
many different types of arrays and structures.  The disadvantage is
that the hash function is slightly more expensive to compute.  

# Improving RebuildTable.

The cost of computing a hash function is especially felt each time
table is rebuilt as new entries are added.  The _RebuildTable_ function
calls the hash function of each entry to recompute its new location in
the bigger table.

	    for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) {
		for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) {
		    *oldChainPtr = hPtr->nextPtr;
		    if (tablePtr->keyType == TCL_STRING_KEYS) {
			index = HashString(hPtr->key.string) & tablePtr->mask;
		    } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
			index = RANDOM_INDEX(tablePtr, hPtr->key.oneWordValue);
		    } else {
			index = HashArray(hPtr->key.words, tablePtr->keyType) &
				tablePtr->mask;

		    }
		    hPtr->bucketPtr = &(tablePtr->buckets[index]);
		    hPtr->nextPtr = *hPtr->bucketPtr;
		    *hPtr->bucketPtr = hPtr;


		}
	    }

The new bucket location is then stored in the hash entry.

Except for one word keys, the hash value is invariant of the table
size.  If the hash value was stored with each entry, then it would not
need to be recomputed each time the table is rebuilt.

	    for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) {
		for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) {
		    *oldChainPtr = hPtr->nextPtr;
		    if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
			index = RANDOM_INDEX(tablePtr, hPtr->key.oneWordValue);
		    } else {
			index = hPtr->hval & tablePtr->mask;

		    }
		    hPtr->bucketPtr = &(tablePtr->buckets[index]);
		    hPtr->nextPtr = *hPtr->bucketPtr;
		    *hPtr->bucketPtr = hPtr;


		}
	    }

This would increase size of an hash entry, except that the pointer to
the hash bucket is now redundant, since it can cheaply be computed.

	    bucketPtr = tablePtr->buckets + (hPtr->hval & tablePtr->mask);

An added benefit is that hash table lookups become faster and easier
to perform.  If there is more than one hash entry in a bucket, you
don't need to examine the key unless the entry has the same hash
value.

	    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
		    hPtr = hPtr->nextPtr) {
	       /* Don't look at entry unless the hash value is the same. */
		if (hPtr->hval == hval) { 
		    register int *iPtr1, *iPtr2;
		    int count;
	
		    for (iPtr1 = arrayPtr, iPtr2 = (int *)hPtr->key.words,
			     count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) {
			if (count == 0) {
			    return hPtr;

			}
			if (*iPtr1 != *iPtr2) {
			    break;




			}
		    }
		}
	    }

_Don Porter <[email protected]>_

 > _It appears that the recommendations of this section have already
   been implemented in Tcl 8.4.  In particular, when the symbol
   TCL\_HASH\_KEY\_STORE\_HASH == 1 \(as it does by default\), then the
   hash value is stored in each entry instead of the bucketPtr._

 > _If that is correct, then I recommend this section of the TIP be
   removed.  If not, more detail about how this proposal differs
   from the 8.4 implementation, and an argument why the proposal
   is superior are in order._

# Better Memory Performance 

One enduring complaint of the Tcl hash table on comp.lang.tcl is its
unexpected memory costs.  A table of 1 million one word key entries
uses over 36 Megabytes.

A hash entry is 20 bytes long.

	 typedef struct Tcl_HashEntry {
	    struct Tcl_HashEntry *nextPtr;	/* Pointer to next entry in this
						 * hash bucket, or NULL for end of
						 * chain. */
	    struct Tcl_HashTable *tablePtr;	/* Pointer to table containing entry. */
	    struct Tcl_HashEntry **bucketPtr;	/* Pointer to bucket that points to
						 * first entry in this entry's chain:
						 * used for deleting the entry. */
	    ClientData clientData;		/* Application stores something here
						 * with Tcl_SetHashValue. */
	    union {				/* Key has one of these forms: */
		char *oneWordValue;		/* One-word value for key. */
		int words[1];			/* Multiple integer words for key.
						 * The actual size will be as large
						 * as necessary for this table's
						 * keys. */
		char string[4];			/* String for key.  The actual size
						 * will be as large as needed to hold
						 * the key. */
	    } key;				/* MUST BE LAST FIELD IN RECORD!! */
	 } Tcl_HashEntry;

Each entry stores a pointer to its hash table.  This field is used
only for deleting a hash entry.  But if the hash table is passed to
_Tcl\_DeleteHashEntry_, the hash entry can be reduced to 16 bytes.
Inspecting Tcl/Tk code, I could not find a case where the hash table
was not easily available to pass as a parameter.

Each hash entry is allocated using _malloc_.  System memory
allocators typically add 8-16 bytes overhead for each allocation.
Worse, calls to _malloc_ and _free_ tend to dominate the cost of
large hash tables.  _Tcl\_DeleteHashTable_ becomes very slow, freeing
hash entries scattered across pages of virtual memory.

For large hash tables, a pool allocation scheme can improve both
reduce the amount of memory used and improve memory performance.  By
allocating memory in larger chunks, the number of _malloc_ and
_free_ calls is dramatically reduced.  Fixed size allocators \(one
word keys and array keys\) can also reclaim and reuse memory from
deleted entries.

The disadvantage of pool allocation is that memory is not released
until the hash table is deleted.  This is less of an issue for large
tables which tend to grow to a steady-state size.  Both Tcl and Tk use
hash tables to keep track of small amounts of information that
probably don't pool allocation.

So to retain compatibility, a new specialized initialization routine
can be used to indicate when to use pool-based allocation.

	    Tcl_InitHashTableWithPool(&table, TCL_ONE_WORD_KEYS);

The standard _Tcl\_InitHashTable_ call

	    Tcl_InitHashTable(&table, TCL_ONE_WORD_KEYS);

will still use _malloc_ and _free_.

# Support for 64-bit Platforms.

While the C language makes no guarantees of a type's size or its
relation to other types, current programming practice assumes that
integers, longs, and pointers are all 32 bits long.  This, of course,
changes with 64-bit systems where pointers are 64-bits wide.
Depending upon the programming model, longs and ints may or may not be
64 bits too.

		 Datatype      LP64    ILP64   LLP64   ILP32   LP32
		  char           8       8       8       8       8
		  short         16      16      16      16      16
		  _int32                        32
		 int            32      64      32      32      16
		 long           64      64      32      32      32
		 long long                      64
		 pointer        64      64      64      32      32

ILP32 is typical for 32 bit systems.  Windows 3.1 was a LP32 model.

In the LP64 model, pointers and longs are 64 bits, but ints remain 32
bits wide.  The LLP model retains the 32-bits for ints and longs, but
adds a 64-bit "long long" type.  Most 64-bit Unix systems \(Solaris,
HP-UX, Tru64, AIX\) are LP64.  I believe that Win64 is LLP.

The first problem is that addresses are now 64-bits, not 32.  This
means that existing code such as

	    Tcl_InitHashTable(&table, TCL_ONE_WORD_KEYS);
	
	    ptr = CreateSomeObject();
	    hPtr = Tcl_CreateHashEntry(&table, (void *)ptr, &isNew);

can possibly fail because the 32-bit one word hash function can't
properly hash the 64-bit pointer address.

_Don Porter <[email protected]>_

 > _Pardon the interruption, but I do not understand what is meant
   by the assertion that hashing of 64-bit pointers "can possibly
   fail".  I've used Tcl on a 64-bit Alpha system for years, hashing
   64-bit pointers the whole time.  What failures should I be seeing?_

	 #define RANDOM_INDEX(tablePtr, i) \
	    (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask)

The above one word hash function can be replaced with a 64-bit version
of Donald Knuth's multiplicative hash function.

	    ((key * GOLDEN_RATIO64) >> downShift) & tablePtr->mask)

where downShift is 64 - log2\(tableSize\) and the GOLDEN\_RATION64 is a
prime approximately equal to \(sqrt\(64\) - 1\) / 2.  

The 64-bit array function is again from Bob Jenkins.  This time it's a
64-bit mixing function.

	 #define MIX64(a,b,c) \
	 	a -= b, a -= c, a ^= (c >> 43), \
	 	b -= c, b -= a, b ^= (a <<  9), \
	 	c -= a, c -= b, c ^= (b >>  8), \
	 	a -= b, a -= c, a ^= (c >> 38), \
	 	b -= c, b -= a, b ^= (a << 23), \
	 	c -= a, c -= b, c ^= (b >>  5), \
	 	a -= b, a -= c, a ^= (c >> 35), \
	 	b -= c, b -= a, b ^= (a << 49), \
	 	c -= a, c -= b, c ^= (b >> 11), \
	 	a -= b, a -= c, a ^= (c >> 12), \
	 	b -= c, b -= a, b ^= (a << 18), \
	 	c -= a, c -= b, c ^= (b >> 22)
	 
	     uint64_t a, b, c, len;
	 
	     len = length;
	     a = b = GOLDEN_RATIO64;	/* An arbitrary value */
	     c = 0;			/* Previous hash value */
	 
	     while (len >= 3) {	/* Handle most of the key */
	 	a += key[0];
	 	b += key[1];
	 	c += key[2];
	 	MIX64(a,b,c);
	 	key += 3; len -= 3;

	     }
	     c += length;		
	     switch(len) {
	     case 2 : b += key[1];
	     case 1 : a += key[0];

	     }
	     MIX64(a,b,c);
	     return c;

Note that it also takes advantage of the 64-bit word size.

# Summary

The following improvements to the current Tcl hash table have been
suggested.  

 * Replace the current array hash function.

 * Replace the bucket pointer in the hash entry with its hash value.
   This allows the table to be rebuilt without rehashing each entry.
   It also speeds bucket searches.

 * Remove the tablePtr from the hash entry, a 20% savings.  This
   requires that callers of _Tcl\_DeleteHashEntry_ pass the hash
   table as a parameter.

 * Allow the hash table to use fixed or variable size pool allocation
   since _malloc_ and _free_ costs dominate large tables.  Pool
   allocation substantial speeds large tables while also saving 8-16
   bytes per entry.  This can be done while still providing the normal
   _malloc_/_free_ versions.

 * Support 64-bit platforms.  This requires 64-bit versions of one
   word and array hash functions.

The suggested changes are nothing new and can be found in most hash
table implementations.  This work builds on the already solid
foundation of the current hash table.  With the above improvements,
the Tcl hash table can be used in high performance applications.  It
also adds a useful piece to the 64-bit Tcl/Tk port.

I've created and tested a new hash table implementation under the
following systems.

		System			32     64
		linux-ix86-gcc		x	
		Solaris-v9-cc		x	x
		Solaris-v9-gcc		x	x
		HPUX-11-cc		x	x
	 	HPUX-11-gcc		x
		Win2k			x

It will be made publicly available on SourceForge.

# Hashing of Malicious Strings

_Donal K. Fellows adds:_

In 2003 a possible denial-of-service attack on hash tables was published
that operated by making a majority of keys map to the same bucket.  While
this would not make the hashes function incorrectly - there would be no
extra memory consumed or incorrect accesses to memory - it still permits
an attacker to escalate the cost of hash accesses from O\(1\) to O\(n\) in
the normal case \(and with obvious knock-on effects for the order of other
algorithms\) and so mount an attack out-of-scale with the effort required
to set the attack up.

The way to fix this is to use a different hashing function for string
hashing that varies the exact hashing algorithm on a table-by-table
basis, and to base that algorithm on a hashing function with better
spectral properties than Tcl's current \(extremely simple\) one.  An
algorithm that might be suitable for such uses is described online
<http://burtleburtle.net/bob/hash/evahash.html>  though the code would
need substantial adaption \(including the addition of a fairly strong
random number generator\) before being placed in the core.

# Copyright

This document has been placed in the public domain.

Name change from tip/7.tip to tip/7.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236

237
238
239
240

241
242
243
244

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288

289
290

291
292
293
294

295
296
297
298
299
300
301
302
303
304

305
306
307
308

309
310
311
312
313
314
315
316

317
318
319
320
321
322
323
324
325
326
327
328
329
330


331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355

356
357
358
359
360
361
362
363
364

365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390

391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408

409
410
411
412
413

414
415
416
417
418
419
420
421

422
423
424
425
426
427
428
429
430

431
432
433
434
435
436
437
438
439
440
441
442
443












444
445

446
447
448

449
450



451
452
453
454

455
456

457
458
459

460
461
462

463
464
465

466
467
468
469
470

471
472
473
474
475
476
477
478
479

480
481
482
483

484
485
486
487
488

489
490
491
492
493
494
495
496

497
498

499
500
501
502

503
504

505
506
507
508
509
510

511
512

513
514
515
516
517
518
519
520
521

522
523

524
525
526
527
528
529

530
531
532
533

534
535
536
537
538
539
540

541
542

543
544
545
546
547
548

549
550
551
552
553

554
555
556

557
558
559
560

561

562
563
564
565
566
567

568
569
570

571
572
573
574
575

576
577
578
579
580
581
582
583
584

585
586
587
588
589
590
591

592
593
594
595
596
597

598
599
600
601
602
603
604


605
606
607
608

609
610
611
612
613

614
615
616
617
618
619

620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636

637
638
639
640
641
642

643
644
645
646
647

648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667

668
669

670
671
672
673
674

675
676
677

678
679
680
681

682
683
684
685

686
687
688

689
690

691
692
693
694
695
696
697
698
699
700

701
702
703


704
705

706
707

708
709
710
711
712

713
714
715
716
717
718

719
720
721
722

723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749

750
751




752
753
754
755
756

757
758
759
760
761
762

763
764

765
766
767

768
769
770
771
772

773
774

775
776

777
778

779
780
781

782
783
784

785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804

805
806













807
808
809
810
811
812
813
814
815
816
817
818
819
820

821
822
823
824

825
826
827

828
829
830
831

832
833

834
835
836

837
838

839
840

841
842

843
844
845
846
847

848
849

850
851
852
853
854
855

856
857
858
859
860
861

862
863
864
865
866

867
868
869
870
871
872
873
874

875
876
877
878
879
880

881
882
883

884
885
886
887

888
889
890
891
892

893
894
895

896
897
898
899
900
901
902
903
904
905

906
907
908

909
910

911
912
913
914
915
916

917
918
919

920
921
922
923

924
925
926
927
928
929
930

931
932
933


934
935
936
937
938
939
940
941
942
943
944
945

946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967

968
969
970

TIP:            7
Title:          Increased resolution for TclpGetTime on Windows
Version:        $Revision: 1.4 $
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        26-Oct-2000
Tcl-Version:    8.4
Discussions-To: news:comp.lang.tcl
Post-History: 


~ Abstract

Tcl users on the Windows platform have long been at a disadvantage in
attempting to do code timing studies, owing to the poor resolution of
the Windows system clock.  The ''time'' command, the ''clock clicks''
command, and all related functions are limited to a resolution of
(typically) 10 milliseconds.  This proposal offers a solution based on
the Windows performance counter.  It presents a means of disciplining
this counter to the system clock so that ''TclpGetTime'' (the
underlying call that the above commands use) can return times to
microsecond precision with accuracy in the tens of microseconds.

~ Change history

''2 November 2000:'' Modified the TIP to discuss the issues surrounding
the fact that some multiprocessor kernels on Windows NT use the CPU timestamp
counter as a performance counter.  Modified the proposed patch to test for
the two frequencies in common use on 8254-compatible real-time clocks, and
enable using the performance counter only if its frequency matches one of
them.  Included the proposed patch inline for review rather than as a
pointer off to dejanews.

~ Rationale

The Windows implementation of ''TclpGetTime'', as of Tcl 8.3.2, uses
the ''ftime'' call in the C library to extract the current system
clock in seconds and milliseconds.  While this time value has
millisecond precision, its actual resolution is limited by the tick
rate of the Windows system clock, normally 100 Hz.  Similarly,
''TclpGetClicks'' uses the ''GetTickCount'' function of
''kernel32.dll'' to get the number of milliseconds since bootload;
once again, the actual resolution of this call is limited to the tick
rate of the system clock.

The Windows Platform APIs offer several timers of different accuracy.
The most precise of these is ''QueryPerformanceCounter'', which
operates at an unspecified frequency (returned by
''QueryPerformanceFrequency'') that is typically about 1.19 MHz.
[http://support.microsoft.com/support/kb/articles/Q172/3/38.asp] has
details of the call, with sample code.

The documentation for Windows suggests that this function is available
only on certain versions of the operating system; in fact, it is
implemented in every extant version of Win32 with the exception of
Win32s and Windows CE 1.0.  Since Visual C++ 6, on which the Tcl
distribution depends, will no longer compile code for those two
platforms, I assert that they may be safely ignored.

The documentation for Windows also states that
''QueryPerformanceCounter'' is available only on certain hardware.  In
practice, this is not an issue; I have never encountered a Windows
implementation on an x86 platform that lacks it, and Alpha has it as
well.  In any case, the reference implementation tests for the success
or failure of the system calls in question, and falls back on the old
way of getting time should they return an error indication.  Users of
any platform on which the performance counter is not supported should
therefore be no worse off than they have ever been.

A worse problem with the performance counter is that its frequency is
poorly calibrated, and is frequently off by as much as 200 parts per
million.  Moreover, the frequency drifts over time, frequently having
a sensitive dependency to temperatures inside the computer's case.

This problem is not insurmountable.  The fix is to maintain the
observed frequency of the performance counter (calibrated against the
system clock) as a variable at run time, and use that variable
together with the value of the performance counter to derive Tcl's
concept of the time.  This technique is well known to electronic
engineers as the "phase locked loop" and is used in network protocols
such as NTP[http://www.eecis.udel.edu/~ntp/].

One problem that is apparently insurmountable is that certain
multiprocessor systems have hardware abstraction layers that derive
the performance counter from the CPU timestamp counter in place of a
real-time clock reference.  This implementation causes the performance
counter on one CPU to drift with respect to the other over time; if a
thread is moved from one processor to another, it cannot derive a
meaningful result from comparing two successive values of the counter.
Moreover, if the CPU clock uses a "gearshift" technique for power
management (as on Intel SpeedStep or Transmeta machines), the CPU
timestamp counter ticks at a non-constant rate.

The proposed implementation addresses the problem by using the
performance counter only if its nominal frequency is either 1.193182
MHz or 3.579545 MHz.  These two frquencies are the common rates when
8254-compatible real-time clock chips are used; virtually all PCI bus
controllers have such chips on board.  This solution therefore adapts
to the vast majority of workstation-class Windows boxes, and is
virtually certain to exclude implementations derived from the CPU
clock since no modern CPU is that slow.  

The patch has been tested on several desktop and laptop machines from
Compaq, Dell, Gateway, HP, Micron, and Packard Bell, with processors
ranging from a 50 MHz 486 to a 750 MHz Pentium III, including laptops
using SpeedStep technology.  It passes the clock-related test cases on
all these platforms; it falls back to the old clocks with 10-ms
precision on multiprocessor servers from Compaq and HP.  (Using the
performance counter actually would have worked on the HP server, which
apparently has some way of making sure that the results of
''QueryPerformanceCounter'' are consistent from one CPU to another.
The performance counter on the Compaq machine was observed to be
inconsistent between the two CPU's.)

~ Specification

This document proposes the following changes to the Tcl core:

   1.  (tclWinTime.c) Add to the static data a set of variables that
       manage the phase-locked techniques, including a
       ''CRITICAL_SECTION'' to guard them so that multi-threaded code
       is stable.

   2.  (tclWinTime.c) Modify ''TclpGetSeconds'' to call
       ''TclpGetTime'' and return the 'seconds' portion of the result.
       This change is necessary to make sure that the two times are
       consistent near the rollover from one second to another.

   3.  (tclWinTime.c) Modify ''TclpGetClicks'' to use
       TclpGetTime to determine the click count as a number of
       microseconds.

   4.  (tclWinTime.c) Modify ''TclpGetTime'' to return the time as
       M*Q+B, where Q is the result of ''QueryPerformanceCounter'',
       and M and B are variables maintained by the phase-locked loop
       to keep the result as close as possible to the system clock.
       The ''TclpGetTime'' call will also launch the phase-lock
       management in a separate thread the first time that it is
       invoked.  If the performance counter is unavailable,
       or if its frequency is not one of the two common 8254-compatible
       rates, then
       ''TclpGetTime'' will return the result of ''ftime'' as it does
       in Tcl 8.3.2.

   5.  (tclWinTime.c) Add the clock calibration procedure.  The
       calibration is somewhat complex; to save space, the reader is
       referred to the reference implementation for the details of how
       the time base and frequency are maintained.

   6.  (tclWinNotify.c) Modify ''Tcl_Sleep'' to test that the process
       has, in fact, slept for the requisite time by calling
       ''TclpGetTime'' and comparing with the desired time.
       Otherwise, roundoff errors may cause the process to awaken
       early.

   7.  (tclWinTest.c) Add a ''testwinclock'' command.  This command
       returns a four element list comprising the seconds and
       microseconds portions of the system clock and the seconds and
       microseconds portions of the Tcl clock.

   8.  (winTime.test) Add to the test suite a test that makes sure
       that the Tcl clock stays within 1.1 ms of the system clock over
       the duration of the test.

~ Reference implementation

This change was submitted as a patch to the old bug-tracking system at
Scriptics [http://www.deja.com/getdoc.xp?AN=666545441&fmt=text].  It
is being recycled as a TIP now that the Tcl Core Team is in place,
since the process for advancing the old patches to the Core is not
well defined.  The link above should not be used to retrieve
the current version of the patch, which appears below as an Appendix.

Tests on several Wintel boxes have shown that the initial startup
transient is less than about 10 seconds (during which time the Tcl
clock may be running 500 ppm fast or slow to bring it into step);
following this period, the motion of the Tcl clock is highly
repeatable and uniform.
    
If the system clock changes by more than 1 second during a run, as
when the operator sets it using the eyeball-and-wristwatch method, the
method of adjusting the performance frequency to preserve monotonicity
and accuracy of interval measurements is hopeless.  This is the only
case where the Tcl clock is allowed to jump.

The startup of the calibration loop does not introduce new
instabilities in the behavior of [[clock clocks]] or ''TclpGetTime''.

[[clock clicks]] and other times that derive from
''TclpGetTime'' also ought to be reliable from the beginning -
assuming that ''QueryPerformanceFrequency'' actually matches the
crystal.  The worst case while the initial calibration is going on
ought to be that the Tcl clock runs 0.1% fast or slow.  The point of
the calibration loop is to correct for long-term drift.

The problem, otherwise, is that ''QueryPerformanceFrequency'' may be
off by some tens of parts per million with respect to the system
clock.  Over a period of days, that would cause the Tcl clock to veer
off from the system clock.  For instance, once my machine is warmed up
(temperature is significant, believe it or not),
''QueryPerformanceFrequency'' is consistently 0.99985 of the correct
value; without calibration, the performance-counter-derived clock
drifts 13 seconds per day.

The ''capture transient'' of the calibration loop is a little
different every time, but the one shown below is typical.  The Tcl
time starts out 2 ms fast with respect to the system time, and the
initial estimate of performance frequency is off, too.  At 2 seconds
in, the calibration loop takes over and makes the clock run 0.1% slow
to bring it in line; by 5 seconds in, it's lined up.  There's some
phase noise over the next 40 seconds or so, by which time the
performance frequency is locked on quite closely. The outliers above
the line represent the fact that [[after]] events sometimes arrive
late because of various other things going on in Windows.

#image:7capture Typical capture transient

The script that gathered the raw data plotted above appears below.

|foreach { syssecs sysusec tclsecs tclusec } [testwinclock] {}
|set basesecs $syssecs
|set baseusec $sysusec
|set nTrials 10000
|for { set i 0 } { $i < $nTrials } { incr i } {
|    set values {}
|    for { set j 0 } { $j < 5 } { incr j } {
|	foreach { syssecs sysusec tclsecs tclusec } [testwinclock] {}
|	set systime [expr { ($syssecs - $basesecs)
|			    + 1.0e-6 * $sysusec - 1.0e-6 * $baseusec }]
|	set tcltime [expr { ($tclsecs - $basesecs)
|			    + 1.0e-6 * $tclusec - 1.0e-6 * $baseusec }]
|	set timediff [expr { $tcltime - $systime }]
|	lappend values [list $systime $timediff $tcltime]
|	after 1
|    }

|    foreach { elapsed timediff tcltime } \
|	[lindex [lsort -real -index 1 $values] 0] {}
|    lappend history $elapsed $timediff $tcltime
|}

|set f [open ~/test2.dat w]
|foreach { elapsed timediff tcltime} $history {
|    puts $f "$elapsed\t$timediff\t$tcltime"
|}

|close $f

To quantify how reproducible the measurements are, I threw a patched
tclsh the torture test of executing [[time {}]] ten million times, and
made a histogram of the results.  The figure below shows the results.
The dots represent individual sample bins, and the solid line is the
cumulative count of samples.  The vast majority of samples show either
five or six microseconds. 99.9% take fewer than nine.  There are many
samples that take longer, owing to either servicing interrupts or
losing the processor to other processes.

The lines at 21, 31 and 42 microseconds show up in repeated runs on my
machine; I suspect that they represent time spent servicing different
sorts of video interrupts.  It's less clear to me what the other
outliers might be; Windows has a tremendous amount of stuff going on
even when it's apparently idle.

#image:7histogram Histogram of results of [time {}].
    
All tests in the test suite continue to pass with the patch applied.

~ Notes

If you care about time to the absolute precision that this change can
achieve, it is of course necessary to discipline the Windows system
clock as well.  Perhaps the best way is to use one of the available
NTP packages ([http://www.eecis.udel.edu/~ntp/] for further
information).

~ Copyright

This document has been placed in the public domain.

~ Appendix

The proposed set of patches to the Tcl 8.3.2 code base appears here.

|*** ../tcl8.3.2base/src/tcl8.3.2/win/tclWinNotify.c Fri Jul  2 18:08:30 1999
|--- ./src/tcl8.3.2/win/tclWinNotify.c Thu Aug 24 23:29:12 2000
|***************
|*** 510,514 ****
|  Tcl_Sleep(ms)
|      int ms;			/* Number of milliseconds to sleep. */
|  {

|!     Sleep(ms);
|  }

|--- 510,548 ----
|  Tcl_Sleep(ms)
|      int ms;			/* Number of milliseconds to sleep. */
|  {

|!     /*
|!      * Simply calling 'Sleep' for the requisite number of milliseconds
|!      * can make the process appear to wake up early because it isn't
|!      * synchronized with the CPU performance counter that is used in
|!      * tclWinTime.c.  This behavior is probably benign, but messes
|!      * up some of the corner cases in the test suite.  We get around
|!      * this problem by repeating the 'Sleep' call as many times
|!      * as necessary to make the clock advance by the requisite amount.
|!      */
|! 

|!     Tcl_Time now;		/* Current wall clock time */
|!     Tcl_Time desired;		/* Desired wakeup time */
|!     int sleepTime = ms;		/* Time to sleep */
|! 

|!     TclpGetTime( &now );
|!     desired.sec = now.sec + ( ms / 1000 );
|!     desired.usec = now.usec + 1000 * ( ms % 1000 );
|!     if ( desired.usec > 1000000 ) {
|! 	++desired.sec;
|! 	desired.usec -= 1000000;
|!     }
|! 	

|!     for ( ; ; ) {
|! 	Sleep( sleepTime );
|! 	TclpGetTime( &now );
|! 	if ( now.sec > desired.sec ) {
|! 	    break;
|! 	} else if ( ( now.sec == desired.sec )
|! 	     && ( now.usec >= desired.usec ) ) {
|! 	    break;
|! 	}
|! 	sleepTime = ( ( 1000 * ( desired.sec - now.sec ) )
|! 		      + ( ( desired.usec - now.usec ) / 1000 ) );
|!     }
|! 
|  }


|*** ../tcl8.3.2base/src/tcl8.3.2/win/tclWinTest.c Thu Oct 28 23:05:14 1999
|--- ./src/tcl8.3.2/win/tclWinTest.c Mon Sep  4 22:45:56 2000
|***************
|*** 22,27 ****
|--- 22,31 ----
|  static int	TestvolumetypeCmd _ANSI_ARGS_((ClientData dummy,
|	 Tcl_Interp *interp, int objc,
|	 Tcl_Obj *CONST objv[]));
|+ static int      TestwinclockCmd _ANSI_ARGS_(( ClientData dummy,
|+ 					      Tcl_Interp* interp,
|+ 					      int objc,
|+ 					      Tcl_Obj *CONST objv[] ));
|  
|  /*
|   *----------------------------------------------------------------------
|***************
|*** 52,57 ****
|--- 56,63 ----
|	       (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
|      Tcl_CreateObjCommand(interp, "testvolumetype", TestvolumetypeCmd,
|	       (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
|+     Tcl_CreateObjCommand(interp, "testwinclock", TestwinclockCmd,
|+             (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
|      return TCL_OK;
|  }

|  
|***************
|*** 187,190 ****
|--- 193,267 ----
|      Tcl_SetResult(interp, volType, TCL_VOLATILE);
|      return TCL_OK;
|  #undef VOL_BUF_SIZE
|+ }
|+ 

|+ /*
|+  *----------------------------------------------------------------------
|+  *
|+  * TestclockCmd --
|+  *
|+  *	Command that returns the seconds and microseconds portions of
|+  *	the system clock and of the Tcl clock so that they can be
|+  *	compared to validate that the Tcl clock is staying in sync.
|+  *
|+  * Usage:
|+  *	testclock
|+  *
|+  * Parameters:
|+  *	None.
|+  *
|+  * Results:
|+  *	Returns a standard Tcl result comprising a four-element list:
|+  *	the seconds and microseconds portions of the system clock,
|+  *	and the seconds and microseconds portions of the Tcl clock.
|+  *
|+  * Side effects:
|+  *	None.
|+  *
|+  *----------------------------------------------------------------------
|+  */
|+ 

|+ static int
|+ TestwinclockCmd( ClientData dummy,
|+ 				/* Unused */
|+ 		 Tcl_Interp* interp,
|+ 				/* Tcl interpreter */
|+ 		 int objc,
|+ 				/* Argument count */
|+ 		 Tcl_Obj *CONST objv[] )
|+ 				/* Argument vector */
|+ {
|+     CONST static FILETIME posixEpoch = { 0xD53E8000, 0x019DB1DE };
|+ 				/* The Posix epoch, expressed as a
|+ 				 * Windows FILETIME */
|+     Tcl_Time tclTime;		/* Tcl clock */
|+     FILETIME sysTime;		/* System clock */
|+     Tcl_Obj* result;		/* Result of the command */
|+     LARGE_INTEGER t1, t2;
|+ 

|+     if ( objc != 1 ) {
|+ 	Tcl_WrongNumArgs( interp, 1, objv, "" );
|+ 	return TCL_ERROR;
|+     }
|+ 

|+     TclpGetTime( &tclTime );
|+     GetSystemTimeAsFileTime( &sysTime );
|+     t1.LowPart = posixEpoch.dwLowDateTime;
|+     t1.HighPart = posixEpoch.dwHighDateTime;
|+     t2.LowPart = sysTime.dwLowDateTime;
|+     t2.HighPart = sysTime.dwHighDateTime;
|+     t2.QuadPart -= t1.QuadPart;
|+ 

|+     result = Tcl_NewObj();
|+     Tcl_ListObjAppendElement
|+ 	( interp, result, Tcl_NewIntObj( (int) (t2.QuadPart / 10000000 ) ) );
|+     Tcl_ListObjAppendElement
|+ 	( interp, result,
|+ 	  Tcl_NewIntObj( (int) ( (t2.QuadPart / 10 ) % 1000000 ) ) );
|+     Tcl_ListObjAppendElement( interp, result, Tcl_NewIntObj( tclTime.sec ) );
|+     Tcl_ListObjAppendElement( interp, result, Tcl_NewIntObj( tclTime.usec ) );
|+ 

|+     Tcl_SetObjResult( interp, result );
|+ 
|+     return TCL_OK;
|  }
|*** ../tcl8.3.2base/src/tcl8.3.2/win/tclWinTime.c Tue Nov 30 19:08:44 1999
|--- ./src/tcl8.3.2/win/tclWinTime.c Thu Nov  2 14:25:56 2000
|***************
|*** 38,47 ****
|--- 38,114 ----
|  static Tcl_ThreadDataKey dataKey;
|  
|  /*
|+  * Calibration interval for the high-resolution timer, in msec












|+  */
|+ 

|+ static CONST unsigned long clockCalibrateWakeupInterval = 10000;
|+ 				/* FIXME: 10 s -- should be about 10 min! */
|+ 

|+ /*
|+  * Data for managing high-resolution timers.



|+  */
|+ 
|+ typedef struct TimeInfo {
|+ 

|+     CRITICAL_SECTION cs;	/* Mutex guarding this structure */
|+ 

|+     int initialized;		/* Flag == 1 if this structure is
|+ 				 * initialized. */
|+ 

|+     int perfCounterAvailable;	/* Flag == 1 if the hardware has a
|+ 				 * performance counter */
|+ 

|+     HANDLE calibrationThread;	/* Handle to the thread that keeps the
|+ 				 * virtual clock calibrated. */
|+ 

|+     HANDLE readyEvent;		/* System event used to
|+ 				 * trigger the requesting thread
|+ 				 * when the clock calibration procedure
|+ 				 * is initialized for the first time */
|+ 

|+     /*
|+      * The following values are used for calculating virtual time.
|+      * Virtual time is always equal to:
|+      *    lastFileTime + (current perf counter - lastCounter) 
|+      *				* 10000000 / curCounterFreq
|+      * and lastFileTime and lastCounter are updated any time that
|+      * virtual time is returned to a caller.
|+      */
|+ 

|+     ULARGE_INTEGER lastFileTime;
|+     LARGE_INTEGER lastCounter;
|+     LARGE_INTEGER curCounterFreq;
|+ 

|+     /* 
|+      * The next two values are used only in the calibration thread, to track
|+      * the frequency of the performance counter.
|+      */
|+ 

|+     LONGLONG lastPerfCounter;	/* Performance counter the last time
|+ 				 * that UpdateClockEachSecond was called */
|+     LONGLONG lastSysTime;	/* System clock at the last time
|+ 				 * that UpdateClockEachSecond was called */
|+     LONGLONG estPerfCounterFreq;
|+ 				/* Current estimate of the counter frequency
|+ 				 * using the system clock as the standard */
|+ 

|+ } TimeInfo;
|+ 

|+ static TimeInfo timeInfo = {
|+     NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0
|+ };
|+ 

|+ CONST static FILETIME posixEpoch = { 0xD53E8000, 0x019DB1DE };
|+     

|+ /*
|   * Declarations for functions defined later in this file.
|   */
|  
|  static struct tm *	ComputeGMT _ANSI_ARGS_((const time_t *tp));
|+ 

|+ static DWORD WINAPI     CalibrationThread _ANSI_ARGS_(( LPVOID arg ));
|+ 

|+ static void 		UpdateTimeEachSecond _ANSI_ARGS_(( void ));
|  
|  /*
|   *----------------------------------------------------------------------
|***************
|*** 63,69 ****
|  unsigned long
|  TclpGetSeconds()
|  {

|!     return (unsigned long) time((time_t *) NULL);
|  }

|  
|  /*
|--- 130,138 ----
|  unsigned long
|  TclpGetSeconds()
|  {

|!     Tcl_Time t;
|!     TclpGetTime( &t );
|!     return t.sec;
|  }

|  
|  /*
|***************
|*** 89,95 ****
|  unsigned long
|  TclpGetClicks()
|  {

|!     return GetTickCount();
|  }

|  
|  /*
|--- 158,175 ----
|  unsigned long
|  TclpGetClicks()
|  {

|!     /*
|!      * Use the TclpGetTime abstraction to get the time in microseconds,
|!      * as nearly as we can, and return it.
|!      */
|! 

|!     Tcl_Time now;		/* Current Tcl time */
|!     unsigned long retval;	/* Value to return */
|! 

|!     TclpGetTime( &now );
|!     retval = ( now.sec * 1000000 ) + now.usec;
|!     return retval;
|! 

|  }

|  
|  /*
|***************
|*** 134,140 ****
|   *	Returns the current time in timePtr.
|   *

|   * Side effects:
|!  *	None.
|   *

|   *----------------------------------------------------------------------
|   */
|--- 214,226 ----
|   *	Returns the current time in timePtr.
|   *

|   * Side effects:
|!  *	On the first call, initializes a set of static variables to
|!  *	keep track of the base value of the performance counter, the
|!  *	corresponding wall clock (obtained through ftime) and the
|!  *	frequency of the performance counter.  Also spins a thread
|!  *	whose function is to wake up periodically and monitor these
|!  *	values, adjusting them as necessary to correct for drift
|!  *	in the performance counter's oscillator.
|   *

|   *----------------------------------------------------------------------
|   */
|***************
|*** 143,153 ****
|  TclpGetTime(timePtr)
|      Tcl_Time *timePtr;		/* Location to store time information. */
|  {

|      struct timeb t;
|  
|!     ftime(&t);
|!     timePtr->sec = t.time;
|!     timePtr->usec = t.millitm * 1000;
|  }

|  
|  /*
|--- 229,342 ----
|  TclpGetTime(timePtr)
|      Tcl_Time *timePtr;		/* Location to store time information. */
|  {
|+ 	


|      struct timeb t;
|  
|!     /* Initialize static storage on the first trip through. */
|! 

|!     /*
|!      * Note: Outer check for 'initialized' is a performance win
|!      * since it avoids an extra mutex lock in the common case.
|!      */
|! 

|!     if ( !timeInfo.initialized ) { 
|! 	TclpInitLock();
|! 	if ( !timeInfo.initialized ) {
|! 	    timeInfo.perfCounterAvailable
|! 		= QueryPerformanceFrequency( &timeInfo.curCounterFreq );
|! 

|! 	    /*
|! 	     * Some hardware abstraction layers use the CPU clock
|! 	     * in place of the real-time clock as a performance counter
|! 	     * reference.  This results in:
|! 	     *    - inconsistent results among the processors on
|! 	     *      multi-processor systems.
|! 	     *    - unpredictable changes in performance counter frequency
|! 	     *      on "gearshift" processors such as Transmeta and
|! 	     *      SpeedStep.
|! 	     * There seems to be no way to test whether the performance
|! 	     * counter is reliable, but a useful heuristic is that
|! 	     * if its frequency is 1.193182 MHz or 3.579545 MHz, it's
|! 	     * derived from a colorburst crystal and is therefore
|! 	     * the RTC rather than the TSC.  If it's anything else, we
|! 	     * presume that the performance counter is unreliable.
|! 	     */
|! 

|! 	    if ( timeInfo.perfCounterAvailable
|! 		 && timeInfo.curCounterFreq.QuadPart != 1193182ui64
|! 		 && timeInfo.curCounterFreq.QuadPart != 3579545ui64 ) {
|! 		timeInfo.perfCounterAvailable = FALSE;
|! 	    }
|! 

|! 	    /*
|! 	     * If the performance counter is available, start a thread to
|! 	     * calibrate it.
|! 	     */
|! 

|! 	    if ( timeInfo.perfCounterAvailable ) {
|! 		DWORD id;
|! 		InitializeCriticalSection( &timeInfo.cs );
|! 		timeInfo.readyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|! 		timeInfo.calibrationThread = CreateThread( NULL,
|! 							   8192,
|! 							   CalibrationThread,
|! 							   (LPVOID) NULL,
|! 							   0,
|! 							   &id );
|! 		SetThreadPriority( timeInfo.calibrationThread,
|! 				   THREAD_PRIORITY_HIGHEST );
|! 		WaitForSingleObject( timeInfo.readyEvent, INFINITE );
|! 		CloseHandle( timeInfo.readyEvent );
|! 	    }
|! 	    timeInfo.initialized = TRUE;
|! 	}
|! 	TclpInitUnlock();
|!     }
|! 

|!     if ( timeInfo.perfCounterAvailable ) {
|! 	

|! 	/*
|! 	 * Query the performance counter and use it to calculate the
|! 	 * current time.
|! 	 */
|! 

|! 	LARGE_INTEGER curCounter;
|! 				/* Current performance counter */
|! 

|! 	LONGLONG curFileTime;
|! 				/* Current estimated time, expressed
|! 				 * as 100-ns ticks since the Windows epoch */
|! 

|! 	static const LARGE_INTEGER posixEpoch = { 0xD53E8000, 0x019DB1DE };
|! 				/* Posix epoch expressed as 100-ns ticks
|! 				 * since the windows epoch */
|! 

|! 	LONGLONG usecSincePosixEpoch;
|! 				/* Current microseconds since Posix epoch */
|! 

|! 	EnterCriticalSection( &timeInfo.cs );
|! 

|! 	QueryPerformanceCounter( &curCounter );
|! 	curFileTime = timeInfo.lastFileTime.QuadPart
|! 	    + ( ( curCounter.QuadPart - timeInfo.lastCounter.QuadPart )
|! 		* 10000000 / timeInfo.curCounterFreq.QuadPart );
|! 	timeInfo.lastFileTime.QuadPart = curFileTime;
|! 	timeInfo.lastCounter.QuadPart = curCounter.QuadPart;
|! 	usecSincePosixEpoch = ( curFileTime - posixEpoch.QuadPart ) / 10;
|! 	timePtr->sec = (time_t) ( usecSincePosixEpoch / 1000000 );
|! 	timePtr->usec = (unsigned long ) ( usecSincePosixEpoch % 1000000 );
|! 	

|! 	LeaveCriticalSection( &timeInfo.cs );
|! 
|! 	


|!     } else {
|! 	

|! 	/* High resolution timer is not available.  Just use ftime */
|! 	

|! 	ftime(&t);
|! 	timePtr->sec = t.time;
|! 	timePtr->usec = t.millitm * 1000;
|!     }
|  }

|  
|  /*
|***************
|*** 439,442 ****
|--- 628,843 ----
|      }

|  
|      return tmPtr;
|+ }
|+ 

|+ /*
|+  *----------------------------------------------------------------------
|+  *
|+  * CalibrationThread --
|+  *
|+  *	Thread that manages calibration of the hi-resolution time
|+  *	derived from the performance counter, to keep it synchronized
|+  *	with the system clock.
|+  *
|+  * Parameters:
|+  *	arg -- Client data from the CreateThread call.  This parameter
|+  *             points to the static TimeInfo structure.
|+  *
|+  * Return value:
|+  *	None.  This thread embeds an infinite loop.
|+  *
|+  * Side effects:
|+  *	At an interval of clockCalibrateWakeupInterval ms, this thread
|+  *	performs virtual time discipline.
|+  *
|+  * Note: When this thread is entered, TclpInitLock has been called
|+  * to safeguard the static storage.  There is therefore no synchronization
|+  * in the body of this procedure.
|+  *
|+  *----------------------------------------------------------------------
|+  */
|+ 

|+ static DWORD WINAPI
|+ CalibrationThread( LPVOID arg )




|+ {
|+     FILETIME curFileTime;
|+ 
|+     /* Get initial system time and performance counter */
|+ 

|+     GetSystemTimeAsFileTime( &curFileTime );
|+     QueryPerformanceCounter( &timeInfo.lastCounter );
|+     QueryPerformanceFrequency( &timeInfo.curCounterFreq );
|+     timeInfo.lastFileTime.LowPart = curFileTime.dwLowDateTime;
|+     timeInfo.lastFileTime.HighPart = curFileTime.dwHighDateTime;
|+ 

|+     /* Initialize the working storage for the calibration callback */
|+ 

|+     timeInfo.lastPerfCounter = timeInfo.lastCounter.QuadPart;
|+     timeInfo.estPerfCounterFreq = timeInfo.curCounterFreq.QuadPart;
|+ 

|+     /*
|+      * Wake up the calling thread.  When it wakes up, it will release the
|+      * initialization lock.
|+      */
|+ 

|+     SetEvent( timeInfo.readyEvent );
|+ 

|+     /* Run the calibration once a second */
|+ 

|+     for ( ; ; ) {
|+ 

|+ 	Sleep( 1000 );
|+ 	UpdateTimeEachSecond();
|+ 	

|+     }
|+ }
|+ 

|+ /*
|+  *----------------------------------------------------------------------
|+  *
|+  * UpdateTimeEachSecond --
|+  *
|+  *	Callback from the waitable timer in the clock calibration thread
|+  *	that updates system time.
|+  *
|+  * Parameters:
|+  *	info -- Pointer to the static TimeInfo structure
|+  *
|+  * Results:
|+  *	None.
|+  *
|+  * Side effects:
|+  *	Performs virtual time calibration discipline.
|+  *
|+  *----------------------------------------------------------------------
|+  */
|+ 

|+ static void
|+ UpdateTimeEachSecond()













|+ {
|+ 
|+     LARGE_INTEGER curPerfCounter;
|+ 				/* Current value returned from
|+ 				 * QueryPerformanceCounter */
|+ 
|+     LONGLONG perfCounterDiff;	/* Difference between the current value
|+ 				 * and the value of 1 second ago */
|+ 
|+     FILETIME curSysTime;	/* Current system time */
|+ 
|+     LARGE_INTEGER curFileTime;	/* File time at the time this callback
|+ 				 * was scheduled. */
|+ 

|+     LONGLONG fileTimeDiff;	/* Elapsed time on the system clock
|+ 				 * since the last time this procedure
|+ 				 * was called */
|+ 

|+     LONGLONG instantFreq;	/* Instantaneous estimate of the
|+ 				 * performance counter frequency */
|+ 

|+     LONGLONG delta;		/* Increment to add to the estimated
|+ 				 * performance counter frequency in the
|+ 				 * loop filter */
|+ 

|+     LONGLONG fuzz;		/* Tolerance for the perf counter frequency */
|+ 

|+     LONGLONG lowBound;		/* Lower bound for the frequency assuming
|+ 				 * 1000 ppm tolerance */
|+ 

|+     LONGLONG hiBound;		/* Upper bound for the frequency */
|+ 

|+     /*
|+      * Get current performance counter and system time.

|+      */
|+ 

|+     QueryPerformanceCounter( &curPerfCounter );
|+     GetSystemTimeAsFileTime( &curSysTime );
|+     curFileTime.LowPart = curSysTime.dwLowDateTime;
|+     curFileTime.HighPart = curSysTime.dwHighDateTime;
|+ 

|+     EnterCriticalSection( &timeInfo.cs );
|+ 

|+     /*
|+      * Find out how many ticks of the performance counter and the
|+      * system clock have elapsed since we got into this procedure.
|+      * Estimate the current frequency.
|+      */
|+ 

|+     perfCounterDiff = curPerfCounter.QuadPart - timeInfo.lastPerfCounter;
|+     timeInfo.lastPerfCounter = curPerfCounter.QuadPart;
|+     fileTimeDiff = curFileTime.QuadPart - timeInfo.lastSysTime;
|+     timeInfo.lastSysTime = curFileTime.QuadPart;
|+     instantFreq = ( 10000000 * perfCounterDiff / fileTimeDiff );
|+ 

|+     /*
|+      * Consider this a timing glitch if instant frequency varies
|+      * significantly from the current estimate.
|+      */
|+ 

|+     fuzz = timeInfo.estPerfCounterFreq >> 10;
|+     lowBound = timeInfo.estPerfCounterFreq - fuzz;
|+     hiBound = timeInfo.estPerfCounterFreq + fuzz;
|+     if ( instantFreq < lowBound || instantFreq > hiBound ) {
|+ 	LeaveCriticalSection( &timeInfo.cs );
|+ 	return;
|+     }
|+ 

|+     /*
|+      * Update the current estimate of performance counter frequency.
|+      * This code is equivalent to the loop filter of a phase locked
|+      * loop.
|+      */
|+ 

|+     delta = ( instantFreq - timeInfo.estPerfCounterFreq ) >> 6;
|+     timeInfo.estPerfCounterFreq += delta;
|+ 

|+     /*
|+      * Update the current virtual time.
|+      */
|+ 

|+     timeInfo.lastFileTime.QuadPart
|+ 	+= ( ( curPerfCounter.QuadPart - timeInfo.lastCounter.QuadPart )
|+ 	     * 10000000 / timeInfo.curCounterFreq.QuadPart );
|+     timeInfo.lastCounter.QuadPart = curPerfCounter.QuadPart;
|+ 

|+     delta = curFileTime.QuadPart - timeInfo.lastFileTime.QuadPart;
|+     if ( delta > 10000000 || delta < -10000000 ) {
|+ 

|+ 	/*
|+ 	 * If the virtual time slip exceeds one second, then adjusting
|+ 	 * the counter frequency is hopeless (it'll take over fifteen
|+ 	 * minutes to line up with the system clock).  The most likely
|+ 	 * cause of this large a slip is a sudden change to the system
|+ 	 * clock, perhaps because it was being corrected by wristwatch
|+ 	 * and eyeball.  Accept the system time, and set the performance
|+ 	 * counter frequency to the current estimate.
|+ 	 */
|+ 

|+ 	timeInfo.lastFileTime.QuadPart = curFileTime.QuadPart;
|+ 	timeInfo.curCounterFreq.QuadPart = timeInfo.estPerfCounterFreq;
|+ 

|+     } else {
|+ 

|+ 	/*
|+ 	 * Compute a counter frequency that will cause virtual time to line
|+ 	 * up with system time one second from now, assuming that the
|+ 	 * performance counter continues to tick at timeInfo.estPerfCounterFreq.
|+ 	 */
|+ 	

|+ 	timeInfo.curCounterFreq.QuadPart
|+ 	    = 10000000 * timeInfo.estPerfCounterFreq / ( delta + 10000000 );
|+ 

|+ 	/*
|+ 	 * Limit frequency excursions to 1000 ppm from estimate
|+ 	 */
|+ 	

|+ 	if ( timeInfo.curCounterFreq.QuadPart < lowBound ) {
|+ 	    timeInfo.curCounterFreq.QuadPart = lowBound;
|+ 	} else if ( timeInfo.curCounterFreq.QuadPart > hiBound ) {
|+ 	    timeInfo.curCounterFreq.QuadPart = hiBound;
|+ 	}
|+     }
|+ 

|+     LeaveCriticalSection( &timeInfo.cs );
|+ 
|  }


|*** ../tcl8.3.2base/src/tcl8.3.2/test/winTime.test Mon Apr 10 13:19:08 2000
|--- ./tcl8.3.2/src/tcl8.3.2/test/winTime.test Wed Sep  6 14:55:30 2000
|***************
|*** 33,38 ****
|--- 33,64 ----
|      set result
|  } {1969}
|  
|+ # Next test tries to make sure that the Tcl clock stays in step
|+ # with the Windows clock.  3000 iterations really isn't enough,
|+ # but how many does a tester have patience for?
|+ 

|+ test winTime-2.1 {Synchronization of Tcl and Windows clocks} {pcOnly} {
|+     set failed 0
|+     foreach { sys_sec sys_usec tcl_sec tcl_usec } [testwinclock] {}
|+     set olddiff [expr { abs ( $tcl_sec - $sys_sec
|+ 			   + 1.0e-6 * ( $tcl_usec - $sys_usec ) ) }]
|+     set ok 1
|+     for { set i 0 } { $i < 3000 } { incr i } {
|+ 	foreach { sys_sec sys_usec tcl_sec tcl_usec } [testwinclock] {}
|+ 	set diff [expr { abs ( $tcl_sec - $sys_sec
|+ 			       + 1.0e-6 * ( $tcl_usec - $sys_usec ) ) }]
|+ 	if { ( $diff > $olddiff + 1000 )
|+ 	     || ( $diff > 11000 ) } {
|+ 	    set failed 1
|+ 	    break
|+ 	} else {
|+ 	    set olddiff $diff
|+ 	    after 1
|+ 	}
|+     }
|+     set failed
|+ } {0}
|+ 

|  # cleanup
|  ::tcltest::cleanupTests
|  return

<
|
<
|
|
|
|
|
|
|
|
>

|



|

|

|
|


|

|







|

|
|



|
|




|
|
|
|





|




|














|
|



|









|
















|


|

|

|



|

|


|
|



|



|
|


|




|


|




|

|



|




|



|


|






|
|










|

|
|
|




|



|
|



|







|


|



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
<
>
|


|













|



|




|
|

|



|



|
|
|
|
|
|
<
>
|
<
>
|
|
|
<
>
|
|
|
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
<
>
|
<
<
<
<
<
<
<
<
<
<
<
<
>
>
>
>
>
>
>
>
>
>
>
>
|
<
>
|
|
<
>
|
|
>
>
>
<
<
<
<
>
|
<
>
|
|
<
>
|
|
<
>
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
<
>
|
|
|
<
>
|
<
>
|
|
|
|
|
<
>
|
<
>
|
|
|
|
|
|
|
|
<
>
|
<
>
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
|
|
<
>
|
<
>
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
<
>
|
|
|
<
>
<
>
|
|
|
|
|
<
>
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
<
<
>
>
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
<
>
|
|
|
|
<
>
|
|
<
>
|
|
|
<
>
|
|
|
<
>
|
|
<
>
|
<
>
|
|
|
|
|
|
|
|
|
<
>
|
<
<
>
>
|
<
>
|
<
>
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
>
>
>
>
<
<
<
<
<
>
|
|
|
|
|
<
>
|
<
>
|
|
<
>
|
|
|
|
<
>
|
<
>
|
<
>
|
<
>
|
|
<
>
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
|
|
|
<
>
|
|
<
>
|
|
|
<
>
|
<
>
|
|
<
>
|
<
>
|
|
>
<
<
>
|
|
|
|
<
>
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
<
>
|
|
|
<
>
|
|
|
|
<
>
|
|
<
>
|
|
|
|
|
|
|
|
|
<
>
|
|
<
>
|
<
>
|
|
|
|
|
<
>
|
|
<
>
|
|
|
<
>
|
|
|
|
|
|
<
>
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234

235
236
237
238

239
240
241
242

243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286

287
288

289
290
291
292

293
294
295
296
297
298
299
300
301
302

303
304
305
306

307
308
309
310
311
312
313
314

315
316
317
318
319
320
321
322
323
324
325
326
327


328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353

354
355
356
357
358
359
360
361
362

363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388

389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406

407
408
409
410
411

412
413
414
415
416
417
418
419

420
421
422
423
424
425
426
427
428

429
430












431
432
433
434
435
436
437
438
439
440
441
442
443

444
445
446

447
448
449
450
451
452




453
454

455
456
457

458
459
460

461
462
463

464
465
466
467
468

469
470
471
472
473
474
475
476
477

478
479
480
481

482
483
484
485
486

487
488
489
490
491
492
493
494

495
496

497
498
499
500

501
502

503
504
505
506
507
508

509
510

511
512
513
514
515
516
517
518
519

520
521

522
523
524
525
526
527

528
529
530
531

532
533
534
535
536
537
538

539
540

541
542
543
544
545
546

547
548
549
550
551

552
553
554

555
556
557
558

559

560
561
562
563
564
565

566
567
568

569
570
571
572
573

574
575
576
577
578
579
580
581
582

583
584
585
586
587
588
589

590
591
592
593
594
595

596
597
598
599
600
601


602
603
604
605
606

607
608
609
610
611

612
613
614
615
616
617

618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634

635
636
637
638
639
640

641
642
643
644
645

646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665

666
667

668
669
670
671
672

673
674
675

676
677
678
679

680
681
682
683

684
685
686

687
688

689
690
691
692
693
694
695
696
697
698

699
700


701
702
703

704
705

706
707
708
709
710

711
712
713
714
715
716

717
718
719
720

721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747

748
749
750
751
752
753
754





755
756
757
758
759
760

761
762

763
764
765

766
767
768
769
770

771
772

773
774

775
776

777
778
779

780
781
782

783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802

803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818














819
820
821
822

823
824
825

826
827
828
829

830
831

832
833
834

835
836

837
838
839
840


841
842
843
844
845

846
847

848
849
850
851
852
853

854
855
856
857
858
859

860
861
862
863
864

865
866
867
868
869
870
871
872

873
874
875
876
877
878

879
880
881

882
883
884
885

886
887
888
889
890

891
892
893

894
895
896
897
898
899
900
901
902
903

904
905
906

907
908

909
910
911
912
913
914

915
916
917

918
919
920
921

922
923
924
925
926
927
928

929
930


931
932
933
934
935
936
937
938
939
940
941
942
943

944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965

966
967
968
969
970

# TIP 7: Increased resolution for TclpGetTime on Windows

	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        26-Oct-2000
	Tcl-Version:    8.4
	Discussions-To: news:comp.lang.tcl
	Post-History: 
-----

# Abstract

Tcl users on the Windows platform have long been at a disadvantage in
attempting to do code timing studies, owing to the poor resolution of
the Windows system clock.  The _time_ command, the _clock clicks_
command, and all related functions are limited to a resolution of
\(typically\) 10 milliseconds.  This proposal offers a solution based on
the Windows performance counter.  It presents a means of disciplining
this counter to the system clock so that _TclpGetTime_ \(the
underlying call that the above commands use\) can return times to
microsecond precision with accuracy in the tens of microseconds.

# Change history

_2 November 2000:_ Modified the TIP to discuss the issues surrounding
the fact that some multiprocessor kernels on Windows NT use the CPU timestamp
counter as a performance counter.  Modified the proposed patch to test for
the two frequencies in common use on 8254-compatible real-time clocks, and
enable using the performance counter only if its frequency matches one of
them.  Included the proposed patch inline for review rather than as a
pointer off to dejanews.

# Rationale

The Windows implementation of _TclpGetTime_, as of Tcl 8.3.2, uses
the _ftime_ call in the C library to extract the current system
clock in seconds and milliseconds.  While this time value has
millisecond precision, its actual resolution is limited by the tick
rate of the Windows system clock, normally 100 Hz.  Similarly,
_TclpGetClicks_ uses the _GetTickCount_ function of
_kernel32.dll_ to get the number of milliseconds since bootload;
once again, the actual resolution of this call is limited to the tick
rate of the system clock.

The Windows Platform APIs offer several timers of different accuracy.
The most precise of these is _QueryPerformanceCounter_, which
operates at an unspecified frequency \(returned by
_QueryPerformanceFrequency_\) that is typically about 1.19 MHz.
<http://support.microsoft.com/support/kb/articles/Q172/3/38.asp>  has
details of the call, with sample code.

The documentation for Windows suggests that this function is available
only on certain versions of the operating system; in fact, it is
implemented in every extant version of Win32 with the exception of
Win32s and Windows CE 1.0.  Since Visual C\+\+ 6, on which the Tcl
distribution depends, will no longer compile code for those two
platforms, I assert that they may be safely ignored.

The documentation for Windows also states that
_QueryPerformanceCounter_ is available only on certain hardware.  In
practice, this is not an issue; I have never encountered a Windows
implementation on an x86 platform that lacks it, and Alpha has it as
well.  In any case, the reference implementation tests for the success
or failure of the system calls in question, and falls back on the old
way of getting time should they return an error indication.  Users of
any platform on which the performance counter is not supported should
therefore be no worse off than they have ever been.

A worse problem with the performance counter is that its frequency is
poorly calibrated, and is frequently off by as much as 200 parts per
million.  Moreover, the frequency drifts over time, frequently having
a sensitive dependency to temperatures inside the computer's case.

This problem is not insurmountable.  The fix is to maintain the
observed frequency of the performance counter \(calibrated against the
system clock\) as a variable at run time, and use that variable
together with the value of the performance counter to derive Tcl's
concept of the time.  This technique is well known to electronic
engineers as the "phase locked loop" and is used in network protocols
such as NTP<http://www.eecis.udel.edu/~ntp/> .

One problem that is apparently insurmountable is that certain
multiprocessor systems have hardware abstraction layers that derive
the performance counter from the CPU timestamp counter in place of a
real-time clock reference.  This implementation causes the performance
counter on one CPU to drift with respect to the other over time; if a
thread is moved from one processor to another, it cannot derive a
meaningful result from comparing two successive values of the counter.
Moreover, if the CPU clock uses a "gearshift" technique for power
management \(as on Intel SpeedStep or Transmeta machines\), the CPU
timestamp counter ticks at a non-constant rate.

The proposed implementation addresses the problem by using the
performance counter only if its nominal frequency is either 1.193182
MHz or 3.579545 MHz.  These two frquencies are the common rates when
8254-compatible real-time clock chips are used; virtually all PCI bus
controllers have such chips on board.  This solution therefore adapts
to the vast majority of workstation-class Windows boxes, and is
virtually certain to exclude implementations derived from the CPU
clock since no modern CPU is that slow.  

The patch has been tested on several desktop and laptop machines from
Compaq, Dell, Gateway, HP, Micron, and Packard Bell, with processors
ranging from a 50 MHz 486 to a 750 MHz Pentium III, including laptops
using SpeedStep technology.  It passes the clock-related test cases on
all these platforms; it falls back to the old clocks with 10-ms
precision on multiprocessor servers from Compaq and HP.  \(Using the
performance counter actually would have worked on the HP server, which
apparently has some way of making sure that the results of
_QueryPerformanceCounter_ are consistent from one CPU to another.
The performance counter on the Compaq machine was observed to be
inconsistent between the two CPU's.\)

# Specification

This document proposes the following changes to the Tcl core:

   1.  \(tclWinTime.c\) Add to the static data a set of variables that
       manage the phase-locked techniques, including a
       _CRITICAL\_SECTION_ to guard them so that multi-threaded code
       is stable.

   2.  \(tclWinTime.c\) Modify _TclpGetSeconds_ to call
       _TclpGetTime_ and return the 'seconds' portion of the result.
       This change is necessary to make sure that the two times are
       consistent near the rollover from one second to another.

   3.  \(tclWinTime.c\) Modify _TclpGetClicks_ to use
       TclpGetTime to determine the click count as a number of
       microseconds.

   4.  \(tclWinTime.c\) Modify _TclpGetTime_ to return the time as
       M\*Q\+B, where Q is the result of _QueryPerformanceCounter_,
       and M and B are variables maintained by the phase-locked loop
       to keep the result as close as possible to the system clock.
       The _TclpGetTime_ call will also launch the phase-lock
       management in a separate thread the first time that it is
       invoked.  If the performance counter is unavailable,
       or if its frequency is not one of the two common 8254-compatible
       rates, then
       _TclpGetTime_ will return the result of _ftime_ as it does
       in Tcl 8.3.2.

   5.  \(tclWinTime.c\) Add the clock calibration procedure.  The
       calibration is somewhat complex; to save space, the reader is
       referred to the reference implementation for the details of how
       the time base and frequency are maintained.

   6.  \(tclWinNotify.c\) Modify _Tcl\_Sleep_ to test that the process
       has, in fact, slept for the requisite time by calling
       _TclpGetTime_ and comparing with the desired time.
       Otherwise, roundoff errors may cause the process to awaken
       early.

   7.  \(tclWinTest.c\) Add a _testwinclock_ command.  This command
       returns a four element list comprising the seconds and
       microseconds portions of the system clock and the seconds and
       microseconds portions of the Tcl clock.

   8.  \(winTime.test\) Add to the test suite a test that makes sure
       that the Tcl clock stays within 1.1 ms of the system clock over
       the duration of the test.

# Reference implementation

This change was submitted as a patch to the old bug-tracking system at
Scriptics <http://www.deja.com/getdoc.xp?AN=666545441&fmt=text> .  It
is being recycled as a TIP now that the Tcl Core Team is in place,
since the process for advancing the old patches to the Core is not
well defined.  The link above should not be used to retrieve
the current version of the patch, which appears below as an Appendix.

Tests on several Wintel boxes have shown that the initial startup
transient is less than about 10 seconds \(during which time the Tcl
clock may be running 500 ppm fast or slow to bring it into step\);
following this period, the motion of the Tcl clock is highly
repeatable and uniform.
    
If the system clock changes by more than 1 second during a run, as
when the operator sets it using the eyeball-and-wristwatch method, the
method of adjusting the performance frequency to preserve monotonicity
and accuracy of interval measurements is hopeless.  This is the only
case where the Tcl clock is allowed to jump.

The startup of the calibration loop does not introduce new
instabilities in the behavior of [clock clocks] or _TclpGetTime_.

[clock clicks] and other times that derive from
_TclpGetTime_ also ought to be reliable from the beginning -
assuming that _QueryPerformanceFrequency_ actually matches the
crystal.  The worst case while the initial calibration is going on
ought to be that the Tcl clock runs 0.1% fast or slow.  The point of
the calibration loop is to correct for long-term drift.

The problem, otherwise, is that _QueryPerformanceFrequency_ may be
off by some tens of parts per million with respect to the system
clock.  Over a period of days, that would cause the Tcl clock to veer
off from the system clock.  For instance, once my machine is warmed up
\(temperature is significant, believe it or not\),
_QueryPerformanceFrequency_ is consistently 0.99985 of the correct
value; without calibration, the performance-counter-derived clock
drifts 13 seconds per day.

The _capture transient_ of the calibration loop is a little
different every time, but the one shown below is typical.  The Tcl
time starts out 2 ms fast with respect to the system time, and the
initial estimate of performance frequency is off, too.  At 2 seconds
in, the calibration loop takes over and makes the clock run 0.1% slow
to bring it in line; by 5 seconds in, it's lined up.  There's some
phase noise over the next 40 seconds or so, by which time the
performance frequency is locked on quite closely. The outliers above
the line represent the fact that [after] events sometimes arrive
late because of various other things going on in Windows.

![Typical capture transient](../assets/7capture.gif)

The script that gathered the raw data plotted above appears below.

	foreach { syssecs sysusec tclsecs tclusec } [testwinclock] {}
	set basesecs $syssecs
	set baseusec $sysusec
	set nTrials 10000
	for { set i 0 } { $i < $nTrials } { incr i } {
	    set values {}
	    for { set j 0 } { $j < 5 } { incr j } {
		foreach { syssecs sysusec tclsecs tclusec } [testwinclock] {}
		set systime [expr { ($syssecs - $basesecs)
				    + 1.0e-6 * $sysusec - 1.0e-6 * $baseusec }]
		set tcltime [expr { ($tclsecs - $basesecs)
				    + 1.0e-6 * $tclusec - 1.0e-6 * $baseusec }]
		set timediff [expr { $tcltime - $systime }]
		lappend values [list $systime $timediff $tcltime]
		after 1

	    }
	    foreach { elapsed timediff tcltime } \
		[lindex [lsort -real -index 1 $values] 0] {}
	    lappend history $elapsed $timediff $tcltime

	}
	set f [open ~/test2.dat w]
	foreach { elapsed timediff tcltime} $history {
	    puts $f "$elapsed\t$timediff\t$tcltime"

	}
	close $f

To quantify how reproducible the measurements are, I threw a patched
tclsh the torture test of executing [time {}] ten million times, and
made a histogram of the results.  The figure below shows the results.
The dots represent individual sample bins, and the solid line is the
cumulative count of samples.  The vast majority of samples show either
five or six microseconds. 99.9% take fewer than nine.  There are many
samples that take longer, owing to either servicing interrupts or
losing the processor to other processes.

The lines at 21, 31 and 42 microseconds show up in repeated runs on my
machine; I suspect that they represent time spent servicing different
sorts of video interrupts.  It's less clear to me what the other
outliers might be; Windows has a tremendous amount of stuff going on
even when it's apparently idle.

![Histogram of results of {[time} {{}].}](../assets/7histogram.gif)
    
All tests in the test suite continue to pass with the patch applied.

# Notes

If you care about time to the absolute precision that this change can
achieve, it is of course necessary to discipline the Windows system
clock as well.  Perhaps the best way is to use one of the available
NTP packages \(<http://www.eecis.udel.edu/~ntp/>  for further
information\).

# Copyright

This document has been placed in the public domain.

# Appendix

The proposed set of patches to the Tcl 8.3.2 code base appears here.

	*** ../tcl8.3.2base/src/tcl8.3.2/win/tclWinNotify.c Fri Jul  2 18:08:30 1999
	--- ./src/tcl8.3.2/win/tclWinNotify.c Thu Aug 24 23:29:12 2000
	***************
	*** 510,514 ****
	  Tcl_Sleep(ms)
	      int ms;			/* Number of milliseconds to sleep. */

	  {
	!     Sleep(ms);

	  }
	--- 510,548 ----
	  Tcl_Sleep(ms)
	      int ms;			/* Number of milliseconds to sleep. */

	  {
	!     /*
	!      * Simply calling 'Sleep' for the requisite number of milliseconds
	!      * can make the process appear to wake up early because it isn't
	!      * synchronized with the CPU performance counter that is used in
	!      * tclWinTime.c.  This behavior is probably benign, but messes
	!      * up some of the corner cases in the test suite.  We get around
	!      * this problem by repeating the 'Sleep' call as many times
	!      * as necessary to make the clock advance by the requisite amount.
	!      */

	! 
	!     Tcl_Time now;		/* Current wall clock time */
	!     Tcl_Time desired;		/* Desired wakeup time */
	!     int sleepTime = ms;		/* Time to sleep */

	! 
	!     TclpGetTime( &now );
	!     desired.sec = now.sec + ( ms / 1000 );
	!     desired.usec = now.usec + 1000 * ( ms % 1000 );
	!     if ( desired.usec > 1000000 ) {
	! 	++desired.sec;
	! 	desired.usec -= 1000000;
	!     }

	! 	
	!     for ( ; ; ) {
	! 	Sleep( sleepTime );
	! 	TclpGetTime( &now );
	! 	if ( now.sec > desired.sec ) {
	! 	    break;
	! 	} else if ( ( now.sec == desired.sec )
	! 	     && ( now.usec >= desired.usec ) ) {
	! 	    break;
	! 	}
	! 	sleepTime = ( ( 1000 * ( desired.sec - now.sec ) )
	! 		      + ( ( desired.usec - now.usec ) / 1000 ) );
	!     }


	! 
	  }
	*** ../tcl8.3.2base/src/tcl8.3.2/win/tclWinTest.c Thu Oct 28 23:05:14 1999
	--- ./src/tcl8.3.2/win/tclWinTest.c Mon Sep  4 22:45:56 2000
	***************
	*** 22,27 ****
	--- 22,31 ----
	  static int	TestvolumetypeCmd _ANSI_ARGS_((ClientData dummy,
		 Tcl_Interp *interp, int objc,
		 Tcl_Obj *CONST objv[]));
	+ static int      TestwinclockCmd _ANSI_ARGS_(( ClientData dummy,
	+ 					      Tcl_Interp* interp,
	+ 					      int objc,
	+ 					      Tcl_Obj *CONST objv[] ));
	  
	  /*
	   *----------------------------------------------------------------------
	***************
	*** 52,57 ****
	--- 56,63 ----
		       (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
	      Tcl_CreateObjCommand(interp, "testvolumetype", TestvolumetypeCmd,
		       (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
	+     Tcl_CreateObjCommand(interp, "testwinclock", TestwinclockCmd,
	+             (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
	      return TCL_OK;

	  }
	  
	***************
	*** 187,190 ****
	--- 193,267 ----
	      Tcl_SetResult(interp, volType, TCL_VOLATILE);
	      return TCL_OK;
	  #undef VOL_BUF_SIZE
	+ }

	+ 
	+ /*
	+  *----------------------------------------------------------------------
	+  *
	+  * TestclockCmd --
	+  *
	+  *	Command that returns the seconds and microseconds portions of
	+  *	the system clock and of the Tcl clock so that they can be
	+  *	compared to validate that the Tcl clock is staying in sync.
	+  *
	+  * Usage:
	+  *	testclock
	+  *
	+  * Parameters:
	+  *	None.
	+  *
	+  * Results:
	+  *	Returns a standard Tcl result comprising a four-element list:
	+  *	the seconds and microseconds portions of the system clock,
	+  *	and the seconds and microseconds portions of the Tcl clock.
	+  *
	+  * Side effects:
	+  *	None.
	+  *
	+  *----------------------------------------------------------------------
	+  */

	+ 
	+ static int
	+ TestwinclockCmd( ClientData dummy,
	+ 				/* Unused */
	+ 		 Tcl_Interp* interp,
	+ 				/* Tcl interpreter */
	+ 		 int objc,
	+ 				/* Argument count */
	+ 		 Tcl_Obj *CONST objv[] )
	+ 				/* Argument vector */
	+ {
	+     CONST static FILETIME posixEpoch = { 0xD53E8000, 0x019DB1DE };
	+ 				/* The Posix epoch, expressed as a
	+ 				 * Windows FILETIME */
	+     Tcl_Time tclTime;		/* Tcl clock */
	+     FILETIME sysTime;		/* System clock */
	+     Tcl_Obj* result;		/* Result of the command */
	+     LARGE_INTEGER t1, t2;

	+ 
	+     if ( objc != 1 ) {
	+ 	Tcl_WrongNumArgs( interp, 1, objv, "" );
	+ 	return TCL_ERROR;
	+     }

	+ 
	+     TclpGetTime( &tclTime );
	+     GetSystemTimeAsFileTime( &sysTime );
	+     t1.LowPart = posixEpoch.dwLowDateTime;
	+     t1.HighPart = posixEpoch.dwHighDateTime;
	+     t2.LowPart = sysTime.dwLowDateTime;
	+     t2.HighPart = sysTime.dwHighDateTime;
	+     t2.QuadPart -= t1.QuadPart;

	+ 
	+     result = Tcl_NewObj();
	+     Tcl_ListObjAppendElement
	+ 	( interp, result, Tcl_NewIntObj( (int) (t2.QuadPart / 10000000 ) ) );
	+     Tcl_ListObjAppendElement
	+ 	( interp, result,
	+ 	  Tcl_NewIntObj( (int) ( (t2.QuadPart / 10 ) % 1000000 ) ) );
	+     Tcl_ListObjAppendElement( interp, result, Tcl_NewIntObj( tclTime.sec ) );
	+     Tcl_ListObjAppendElement( interp, result, Tcl_NewIntObj( tclTime.usec ) );

	+ 
	+     Tcl_SetObjResult( interp, result );












	+ 
	+     return TCL_OK;
	  }
	*** ../tcl8.3.2base/src/tcl8.3.2/win/tclWinTime.c Tue Nov 30 19:08:44 1999
	--- ./src/tcl8.3.2/win/tclWinTime.c Thu Nov  2 14:25:56 2000
	***************
	*** 38,47 ****
	--- 38,114 ----
	  static Tcl_ThreadDataKey dataKey;
	  
	  /*
	+  * Calibration interval for the high-resolution timer, in msec
	+  */

	+ 
	+ static CONST unsigned long clockCalibrateWakeupInterval = 10000;
	+ 				/* FIXME: 10 s -- should be about 10 min! */

	+ 
	+ /*
	+  * Data for managing high-resolution timers.
	+  */
	+ 
	+ typedef struct TimeInfo {




	+ 
	+     CRITICAL_SECTION cs;	/* Mutex guarding this structure */

	+ 
	+     int initialized;		/* Flag == 1 if this structure is
	+ 				 * initialized. */

	+ 
	+     int perfCounterAvailable;	/* Flag == 1 if the hardware has a
	+ 				 * performance counter */

	+ 
	+     HANDLE calibrationThread;	/* Handle to the thread that keeps the
	+ 				 * virtual clock calibrated. */

	+ 
	+     HANDLE readyEvent;		/* System event used to
	+ 				 * trigger the requesting thread
	+ 				 * when the clock calibration procedure
	+ 				 * is initialized for the first time */

	+ 
	+     /*
	+      * The following values are used for calculating virtual time.
	+      * Virtual time is always equal to:
	+      *    lastFileTime + (current perf counter - lastCounter) 
	+      *				* 10000000 / curCounterFreq
	+      * and lastFileTime and lastCounter are updated any time that
	+      * virtual time is returned to a caller.
	+      */

	+ 
	+     ULARGE_INTEGER lastFileTime;
	+     LARGE_INTEGER lastCounter;
	+     LARGE_INTEGER curCounterFreq;

	+ 
	+     /* 
	+      * The next two values are used only in the calibration thread, to track
	+      * the frequency of the performance counter.
	+      */

	+ 
	+     LONGLONG lastPerfCounter;	/* Performance counter the last time
	+ 				 * that UpdateClockEachSecond was called */
	+     LONGLONG lastSysTime;	/* System clock at the last time
	+ 				 * that UpdateClockEachSecond was called */
	+     LONGLONG estPerfCounterFreq;
	+ 				/* Current estimate of the counter frequency
	+ 				 * using the system clock as the standard */

	+ 
	+ } TimeInfo;

	+ 
	+ static TimeInfo timeInfo = {
	+     NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0
	+ };

	+ 
	+ CONST static FILETIME posixEpoch = { 0xD53E8000, 0x019DB1DE };

	+     
	+ /*
	   * Declarations for functions defined later in this file.
	   */
	  
	  static struct tm *	ComputeGMT _ANSI_ARGS_((const time_t *tp));

	+ 
	+ static DWORD WINAPI     CalibrationThread _ANSI_ARGS_(( LPVOID arg ));

	+ 
	+ static void 		UpdateTimeEachSecond _ANSI_ARGS_(( void ));
	  
	  /*
	   *----------------------------------------------------------------------
	***************
	*** 63,69 ****
	  unsigned long
	  TclpGetSeconds()

	  {
	!     return (unsigned long) time((time_t *) NULL);

	  }
	  
	  /*
	--- 130,138 ----
	  unsigned long
	  TclpGetSeconds()

	  {
	!     Tcl_Time t;
	!     TclpGetTime( &t );
	!     return t.sec;

	  }
	  
	  /*
	***************
	*** 89,95 ****
	  unsigned long
	  TclpGetClicks()

	  {
	!     return GetTickCount();

	  }
	  
	  /*
	--- 158,175 ----
	  unsigned long
	  TclpGetClicks()

	  {
	!     /*
	!      * Use the TclpGetTime abstraction to get the time in microseconds,
	!      * as nearly as we can, and return it.
	!      */

	! 
	!     Tcl_Time now;		/* Current Tcl time */
	!     unsigned long retval;	/* Value to return */

	! 
	!     TclpGetTime( &now );
	!     retval = ( now.sec * 1000000 ) + now.usec;
	!     return retval;

	! 

	  }
	  
	  /*
	***************
	*** 134,140 ****
	   *	Returns the current time in timePtr.

	   *
	   * Side effects:
	!  *	None.

	   *
	   *----------------------------------------------------------------------
	   */
	--- 214,226 ----
	   *	Returns the current time in timePtr.

	   *
	   * Side effects:
	!  *	On the first call, initializes a set of static variables to
	!  *	keep track of the base value of the performance counter, the
	!  *	corresponding wall clock (obtained through ftime) and the
	!  *	frequency of the performance counter.  Also spins a thread
	!  *	whose function is to wake up periodically and monitor these
	!  *	values, adjusting them as necessary to correct for drift
	!  *	in the performance counter's oscillator.

	   *
	   *----------------------------------------------------------------------
	   */
	***************
	*** 143,153 ****
	  TclpGetTime(timePtr)
	      Tcl_Time *timePtr;		/* Location to store time information. */

	  {
	      struct timeb t;
	  
	!     ftime(&t);
	!     timePtr->sec = t.time;
	!     timePtr->usec = t.millitm * 1000;

	  }
	  
	  /*
	--- 229,342 ----
	  TclpGetTime(timePtr)
	      Tcl_Time *timePtr;		/* Location to store time information. */


	  {
	+ 	
	      struct timeb t;
	  
	!     /* Initialize static storage on the first trip through. */

	! 
	!     /*
	!      * Note: Outer check for 'initialized' is a performance win
	!      * since it avoids an extra mutex lock in the common case.
	!      */

	! 
	!     if ( !timeInfo.initialized ) { 
	! 	TclpInitLock();
	! 	if ( !timeInfo.initialized ) {
	! 	    timeInfo.perfCounterAvailable
	! 		= QueryPerformanceFrequency( &timeInfo.curCounterFreq );

	! 
	! 	    /*
	! 	     * Some hardware abstraction layers use the CPU clock
	! 	     * in place of the real-time clock as a performance counter
	! 	     * reference.  This results in:
	! 	     *    - inconsistent results among the processors on
	! 	     *      multi-processor systems.
	! 	     *    - unpredictable changes in performance counter frequency
	! 	     *      on "gearshift" processors such as Transmeta and
	! 	     *      SpeedStep.
	! 	     * There seems to be no way to test whether the performance
	! 	     * counter is reliable, but a useful heuristic is that
	! 	     * if its frequency is 1.193182 MHz or 3.579545 MHz, it's
	! 	     * derived from a colorburst crystal and is therefore
	! 	     * the RTC rather than the TSC.  If it's anything else, we
	! 	     * presume that the performance counter is unreliable.
	! 	     */

	! 
	! 	    if ( timeInfo.perfCounterAvailable
	! 		 && timeInfo.curCounterFreq.QuadPart != 1193182ui64
	! 		 && timeInfo.curCounterFreq.QuadPart != 3579545ui64 ) {
	! 		timeInfo.perfCounterAvailable = FALSE;
	! 	    }

	! 
	! 	    /*
	! 	     * If the performance counter is available, start a thread to
	! 	     * calibrate it.
	! 	     */

	! 
	! 	    if ( timeInfo.perfCounterAvailable ) {
	! 		DWORD id;
	! 		InitializeCriticalSection( &timeInfo.cs );
	! 		timeInfo.readyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
	! 		timeInfo.calibrationThread = CreateThread( NULL,
	! 							   8192,
	! 							   CalibrationThread,
	! 							   (LPVOID) NULL,
	! 							   0,
	! 							   &id );
	! 		SetThreadPriority( timeInfo.calibrationThread,
	! 				   THREAD_PRIORITY_HIGHEST );
	! 		WaitForSingleObject( timeInfo.readyEvent, INFINITE );
	! 		CloseHandle( timeInfo.readyEvent );
	! 	    }
	! 	    timeInfo.initialized = TRUE;
	! 	}
	! 	TclpInitUnlock();
	!     }

	! 
	!     if ( timeInfo.perfCounterAvailable ) {

	! 	
	! 	/*
	! 	 * Query the performance counter and use it to calculate the
	! 	 * current time.
	! 	 */

	! 
	! 	LARGE_INTEGER curCounter;
	! 				/* Current performance counter */

	! 
	! 	LONGLONG curFileTime;
	! 				/* Current estimated time, expressed
	! 				 * as 100-ns ticks since the Windows epoch */

	! 
	! 	static const LARGE_INTEGER posixEpoch = { 0xD53E8000, 0x019DB1DE };
	! 				/* Posix epoch expressed as 100-ns ticks
	! 				 * since the windows epoch */

	! 
	! 	LONGLONG usecSincePosixEpoch;
	! 				/* Current microseconds since Posix epoch */

	! 
	! 	EnterCriticalSection( &timeInfo.cs );

	! 
	! 	QueryPerformanceCounter( &curCounter );
	! 	curFileTime = timeInfo.lastFileTime.QuadPart
	! 	    + ( ( curCounter.QuadPart - timeInfo.lastCounter.QuadPart )
	! 		* 10000000 / timeInfo.curCounterFreq.QuadPart );
	! 	timeInfo.lastFileTime.QuadPart = curFileTime;
	! 	timeInfo.lastCounter.QuadPart = curCounter.QuadPart;
	! 	usecSincePosixEpoch = ( curFileTime - posixEpoch.QuadPart ) / 10;
	! 	timePtr->sec = (time_t) ( usecSincePosixEpoch / 1000000 );
	! 	timePtr->usec = (unsigned long ) ( usecSincePosixEpoch % 1000000 );

	! 	
	! 	LeaveCriticalSection( &timeInfo.cs );


	! 
	! 	
	!     } else {

	! 	
	! 	/* High resolution timer is not available.  Just use ftime */

	! 	
	! 	ftime(&t);
	! 	timePtr->sec = t.time;
	! 	timePtr->usec = t.millitm * 1000;
	!     }

	  }
	  
	  /*
	***************
	*** 439,442 ****
	--- 628,843 ----

	      }
	  
	      return tmPtr;
	+ }

	+ 
	+ /*
	+  *----------------------------------------------------------------------
	+  *
	+  * CalibrationThread --
	+  *
	+  *	Thread that manages calibration of the hi-resolution time
	+  *	derived from the performance counter, to keep it synchronized
	+  *	with the system clock.
	+  *
	+  * Parameters:
	+  *	arg -- Client data from the CreateThread call.  This parameter
	+  *             points to the static TimeInfo structure.
	+  *
	+  * Return value:
	+  *	None.  This thread embeds an infinite loop.
	+  *
	+  * Side effects:
	+  *	At an interval of clockCalibrateWakeupInterval ms, this thread
	+  *	performs virtual time discipline.
	+  *
	+  * Note: When this thread is entered, TclpInitLock has been called
	+  * to safeguard the static storage.  There is therefore no synchronization
	+  * in the body of this procedure.
	+  *
	+  *----------------------------------------------------------------------
	+  */

	+ 
	+ static DWORD WINAPI
	+ CalibrationThread( LPVOID arg )
	+ {
	+     FILETIME curFileTime;
	+ 
	+     /* Get initial system time and performance counter */





	+ 
	+     GetSystemTimeAsFileTime( &curFileTime );
	+     QueryPerformanceCounter( &timeInfo.lastCounter );
	+     QueryPerformanceFrequency( &timeInfo.curCounterFreq );
	+     timeInfo.lastFileTime.LowPart = curFileTime.dwLowDateTime;
	+     timeInfo.lastFileTime.HighPart = curFileTime.dwHighDateTime;

	+ 
	+     /* Initialize the working storage for the calibration callback */

	+ 
	+     timeInfo.lastPerfCounter = timeInfo.lastCounter.QuadPart;
	+     timeInfo.estPerfCounterFreq = timeInfo.curCounterFreq.QuadPart;

	+ 
	+     /*
	+      * Wake up the calling thread.  When it wakes up, it will release the
	+      * initialization lock.
	+      */

	+ 
	+     SetEvent( timeInfo.readyEvent );

	+ 
	+     /* Run the calibration once a second */

	+ 
	+     for ( ; ; ) {

	+ 
	+ 	Sleep( 1000 );
	+ 	UpdateTimeEachSecond();

	+ 	
	+     }
	+ }

	+ 
	+ /*
	+  *----------------------------------------------------------------------
	+  *
	+  * UpdateTimeEachSecond --
	+  *
	+  *	Callback from the waitable timer in the clock calibration thread
	+  *	that updates system time.
	+  *
	+  * Parameters:
	+  *	info -- Pointer to the static TimeInfo structure
	+  *
	+  * Results:
	+  *	None.
	+  *
	+  * Side effects:
	+  *	Performs virtual time calibration discipline.
	+  *
	+  *----------------------------------------------------------------------
	+  */

	+ 
	+ static void
	+ UpdateTimeEachSecond()
	+ {
	+ 
	+     LARGE_INTEGER curPerfCounter;
	+ 				/* Current value returned from
	+ 				 * QueryPerformanceCounter */
	+ 
	+     LONGLONG perfCounterDiff;	/* Difference between the current value
	+ 				 * and the value of 1 second ago */
	+ 
	+     FILETIME curSysTime;	/* Current system time */
	+ 
	+     LARGE_INTEGER curFileTime;	/* File time at the time this callback
	+ 				 * was scheduled. */














	+ 
	+     LONGLONG fileTimeDiff;	/* Elapsed time on the system clock
	+ 				 * since the last time this procedure
	+ 				 * was called */

	+ 
	+     LONGLONG instantFreq;	/* Instantaneous estimate of the
	+ 				 * performance counter frequency */

	+ 
	+     LONGLONG delta;		/* Increment to add to the estimated
	+ 				 * performance counter frequency in the
	+ 				 * loop filter */

	+ 
	+     LONGLONG fuzz;		/* Tolerance for the perf counter frequency */

	+ 
	+     LONGLONG lowBound;		/* Lower bound for the frequency assuming
	+ 				 * 1000 ppm tolerance */

	+ 
	+     LONGLONG hiBound;		/* Upper bound for the frequency */

	+ 
	+     /*
	+      * Get current performance counter and system time.
	+      */


	+ 
	+     QueryPerformanceCounter( &curPerfCounter );
	+     GetSystemTimeAsFileTime( &curSysTime );
	+     curFileTime.LowPart = curSysTime.dwLowDateTime;
	+     curFileTime.HighPart = curSysTime.dwHighDateTime;

	+ 
	+     EnterCriticalSection( &timeInfo.cs );

	+ 
	+     /*
	+      * Find out how many ticks of the performance counter and the
	+      * system clock have elapsed since we got into this procedure.
	+      * Estimate the current frequency.
	+      */

	+ 
	+     perfCounterDiff = curPerfCounter.QuadPart - timeInfo.lastPerfCounter;
	+     timeInfo.lastPerfCounter = curPerfCounter.QuadPart;
	+     fileTimeDiff = curFileTime.QuadPart - timeInfo.lastSysTime;
	+     timeInfo.lastSysTime = curFileTime.QuadPart;
	+     instantFreq = ( 10000000 * perfCounterDiff / fileTimeDiff );

	+ 
	+     /*
	+      * Consider this a timing glitch if instant frequency varies
	+      * significantly from the current estimate.
	+      */

	+ 
	+     fuzz = timeInfo.estPerfCounterFreq >> 10;
	+     lowBound = timeInfo.estPerfCounterFreq - fuzz;
	+     hiBound = timeInfo.estPerfCounterFreq + fuzz;
	+     if ( instantFreq < lowBound || instantFreq > hiBound ) {
	+ 	LeaveCriticalSection( &timeInfo.cs );
	+ 	return;
	+     }

	+ 
	+     /*
	+      * Update the current estimate of performance counter frequency.
	+      * This code is equivalent to the loop filter of a phase locked
	+      * loop.
	+      */

	+ 
	+     delta = ( instantFreq - timeInfo.estPerfCounterFreq ) >> 6;
	+     timeInfo.estPerfCounterFreq += delta;

	+ 
	+     /*
	+      * Update the current virtual time.
	+      */

	+ 
	+     timeInfo.lastFileTime.QuadPart
	+ 	+= ( ( curPerfCounter.QuadPart - timeInfo.lastCounter.QuadPart )
	+ 	     * 10000000 / timeInfo.curCounterFreq.QuadPart );
	+     timeInfo.lastCounter.QuadPart = curPerfCounter.QuadPart;

	+ 
	+     delta = curFileTime.QuadPart - timeInfo.lastFileTime.QuadPart;
	+     if ( delta > 10000000 || delta < -10000000 ) {

	+ 
	+ 	/*
	+ 	 * If the virtual time slip exceeds one second, then adjusting
	+ 	 * the counter frequency is hopeless (it'll take over fifteen
	+ 	 * minutes to line up with the system clock).  The most likely
	+ 	 * cause of this large a slip is a sudden change to the system
	+ 	 * clock, perhaps because it was being corrected by wristwatch
	+ 	 * and eyeball.  Accept the system time, and set the performance
	+ 	 * counter frequency to the current estimate.
	+ 	 */

	+ 
	+ 	timeInfo.lastFileTime.QuadPart = curFileTime.QuadPart;
	+ 	timeInfo.curCounterFreq.QuadPart = timeInfo.estPerfCounterFreq;

	+ 
	+     } else {

	+ 
	+ 	/*
	+ 	 * Compute a counter frequency that will cause virtual time to line
	+ 	 * up with system time one second from now, assuming that the
	+ 	 * performance counter continues to tick at timeInfo.estPerfCounterFreq.
	+ 	 */

	+ 	
	+ 	timeInfo.curCounterFreq.QuadPart
	+ 	    = 10000000 * timeInfo.estPerfCounterFreq / ( delta + 10000000 );

	+ 
	+ 	/*
	+ 	 * Limit frequency excursions to 1000 ppm from estimate
	+ 	 */

	+ 	
	+ 	if ( timeInfo.curCounterFreq.QuadPart < lowBound ) {
	+ 	    timeInfo.curCounterFreq.QuadPart = lowBound;
	+ 	} else if ( timeInfo.curCounterFreq.QuadPart > hiBound ) {
	+ 	    timeInfo.curCounterFreq.QuadPart = hiBound;
	+ 	}
	+     }

	+ 
	+     LeaveCriticalSection( &timeInfo.cs );


	+ 
	  }
	*** ../tcl8.3.2base/src/tcl8.3.2/test/winTime.test Mon Apr 10 13:19:08 2000
	--- ./tcl8.3.2/src/tcl8.3.2/test/winTime.test Wed Sep  6 14:55:30 2000
	***************
	*** 33,38 ****
	--- 33,64 ----
	      set result
	  } {1969}
	  
	+ # Next test tries to make sure that the Tcl clock stays in step
	+ # with the Windows clock.  3000 iterations really isn't enough,
	+ # but how many does a tester have patience for?

	+ 
	+ test winTime-2.1 {Synchronization of Tcl and Windows clocks} {pcOnly} {
	+     set failed 0
	+     foreach { sys_sec sys_usec tcl_sec tcl_usec } [testwinclock] {}
	+     set olddiff [expr { abs ( $tcl_sec - $sys_sec
	+ 			   + 1.0e-6 * ( $tcl_usec - $sys_usec ) ) }]
	+     set ok 1
	+     for { set i 0 } { $i < 3000 } { incr i } {
	+ 	foreach { sys_sec sys_usec tcl_sec tcl_usec } [testwinclock] {}
	+ 	set diff [expr { abs ( $tcl_sec - $sys_sec
	+ 			       + 1.0e-6 * ( $tcl_usec - $sys_usec ) ) }]
	+ 	if { ( $diff > $olddiff + 1000 )
	+ 	     || ( $diff > 11000 ) } {
	+ 	    set failed 1
	+ 	    break
	+ 	} else {
	+ 	    set olddiff $diff
	+ 	    after 1
	+ 	}
	+     }
	+     set failed
	+ } {0}

	+ 
	  # cleanup
	  ::tcltest::cleanupTests
	  return

Name change from tip/70.tip to tip/70.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149

150
151

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

187
188
189
190
191
192

193
194
195

196
197
198
199
200
201



202
203
204

205
206
207
208
209


210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231

232
233
234
235
236
237

238
239
240
241
242
243
244
245
TIP:            70
Title:          A Relational Switch Control Structure
Version:        $Revision: 1.8 $
Author:         Bhushit Joshipura <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        20-Oct-2001
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP proposes the introduction of a new control structure, ''rswitch'',
which is a relational parallel to switch-case control structure. It
consists of two lists: condition list and situation-reaction list. At
the maximum two conditions can be specified. Based on situation,
reaction is executed. The situation is selected on "first true and
only the first true" basis.

~Rationale

Theoretically only two controls - ''if'' and ''goto'' - are sufficient
to implement all algorithms. However, languages provide more control
structures for better representation of algorithms. To many structural
programmers like me, a ''switch'' statement gives much better picture of
the program than equivalent ''if''-''elseif''-...-''else'' chain. It
pronounces the course of decision of a big chunk of program in a single
statement, making understanding and maintaining software easier. It
also helps to optimize the software better if it is written in
''switch'' form. However, ''switch'' is strictly data based i.e.
''switch'' happens strictly on data value. 

The proposed ''rswitch'' command is a control structure similar to (and
more general than) ''switch''. (As a matter of fact, Tcl's ''foreach''
control structure is a special case of its for control structure.) Using
''rswitch'' it should be possible to take decisions based on relations
between entities.

In response to comments on Revision: 1.2 of the draft, Bhushit
Joshipura wrote [Re-edited]:

Why rswitch? [Re-written] 

 1. if..elseif..else contains elements of surprize spread in the code.
    From maintenance point of view, once the
    ''if''..''elseif''..''else'' code goes beyond horizon (one display
    length), burden of reference retention comes on human brain making
    maintenance bug-prone.

 2. In case of ''rswitch'', if a situation refers to one or more
    conditions, we had reduced this burden by stating upfront which
    variable is in the spotlight. The maintainer can then easily jump
    irrelavant cases. 

 3. In ''if''..''elseif''..''else'', a string of three conditions (with
    one of them being a `not' string) can mystify me for at least an
    hour. 

 4. In case of an ''rswitch'' (even in a situation which does not
    refer to any conditions):

 > 1. `and' is nested rswitch

 > 2. `or' is a fall through case

 > 3. `not' could be written as "default" case. `not' free from `and'
    and `or' is less confusing. We can write almost a `not-less' code
    using "default". 

 > Logical connectives result into visual presentation.

 5. Object Oriented Programming is trying to eliminate ''switch-case''
    statements by identifying localization of references and finding a
    heirarchy of data-actions. 

 6. In similar way one can think of ''rswitch'' cases (situations).
    Identifying localized references (w.r.t. situations) and a
    heirarchy of situations-reactions. However, this is a research
    issue.

Moreover, the writer does not need to be an artist to be able to write understandable code.

~Implementation in Other Languages

I queried about proposal of such a control structure in C to Dr. Dennis
M. Ritchie in February 2001. (At that time I thought only of
bi-conditional relational switch. See a few pages down for currently
proposed control structure.)

 >  Absence of relational switch I know this can be odd for other languages - but not for C.
    C is so near to machine and a relational switch could be ideal for many many
    machine-cycle saving situations.

 >  Apart from machine-orientedness, it could avoid many usages of not-so-structured ?:
    operator.

 >  It could simplify a lot of control and signal processing code too.

 >  Why did C become more data-biased for a control structure?

|    relational-switch(expr1,expr2){
|    case ==: statements;
|            break;
|    case > : statements;
|            break;
|    case < : statements;
|            break;
|    default: statements;
|            break;
|    }


TCL need not be so optimized, as C has to be. However, clarity and
maintainability remain formidable reasons for relational switch
implementation.

In a quick reply, Dr. Ritchie wrote back:

 >  The relational switch idea is (so far as I know) for C a new suggestion, although I have
    no idea of all things that were proposed for the 1989 or 1999 C standards. If seems to
    hark back to the old Fortran GOTO statement

|    IF (expression) 2, 3, 4

 >  which went to various places depending on whether the expression was -, 0 or +. It's
    also a bit strange syntactically (though it might work in the grammar) in that the case
    values aren't expressions, but just operators.

 >  Regards, Dennis"

Thus the structure is absent from C and its whole family. It is absent
from Pascal, PERL, BASIC, shell scripts - and of course, TCL.

Fortran's computed goto is near to bi-conditional rswitch. (That way
Chimpanzees are near to Homo sapiens too.) However, clarity of
presentation of default and fall through are not achievable through
computed goto. Mono-conditional rswitch, however, does not have a
parallel in languages of my knowledge (C, C++, Java, Pascal, BASIC,
Fortran, shell scripts). 

~Grammar and Behavior

Overall:

|rswitch {[condition(s)]} {
|    <situation-1> {
|        <reaction-block-1>
|    }

|    ...
|}


The condition list may have no, one or two variables.

A situation is legal if:

 1. It is a valid expression or

 2. If the condition list had at least one element 'x', {$x $situation} is a valid expression or

 > 1. If the condition list had exactly one element 'x', {$situation $x} is a valid expression or

 > 2. If the condition list had two elements 'x' and 'y', {$x $situation $y} is a valid expression or

 3. If the condition list had two elements 'x' and 'y' and {$situation $y} is a valid expression or

 4. If $situation == "default"

A reaction block is legal if:

 1. It is not the last block and $reactionBlock == "-" (fall through) or

 2. It is a valid TCL action block

Let us call a non-default extracted valid expression a SITUATION.

At execution, reaction block following or fell through by the first and only the first SITUATION that becomes true, is executed. In case no SITUATION becomes true and default situation is present, reaction block following or fell through by default statement is executed. Default situation is not necessary for operation of rswitch. An rswitch without any situation-reaction block is grammatically valid.

~Sample Invocations

|# Full length condition block. Second condition perhaps got redundant with maintenance.
|rswitch {$a $b} {
|   {> $c} -
|   {< $d} {
|      puts "$a is either > $c or < $d or both"
|   }

|   {< $c} {
|      # Full length condition block. Second condition is used.
|      rswitch {$a $d} {
|         > {
|            puts "$a is < $c AND > $d"
|         }

|         == {
|            puts "$a and $d are equal and they are < $c"
|         }

|         default {
|            puts "$a is < $c BUT <= $d"
|            puts "should never come here"
|         }
|      }
|   }



|   {3 > } {
|      puts "$a == $c, $a >= $d and $b <= 3"
|   }

|   default {
|      puts "$a == $c, $a >= $d and $b >= 3"
|   }
|}



~Contrast

Contrast above code with its if-elseif-else equivalent. Notice that:

 1. Both the examples have same effect.

 2. Both examples are indented with the same style.

|if {($a > $c) || ($a < $d)} {
|	# could you see a maintenance nightmare that could have arisen when
|	# reference to $b were eliminated?
|	puts "$a is either > $c or < $d or both"
|} elseif {$a < $c} {
|	if {$a > $d} {
|		puts "$a is < $c AND > $d"
|	} elseif {$a == $d} {
|		puts "$a and $d are equal and they are < $c"
|	} else {
|		puts "Pop-up question: What should we have here?
|		puts "$a is < $c BUT <= $d"
|		puts "should never come here"
|	}

|} elseif {3 > $b} {
|		puts "$a == $c, $a >= $d and $b <= 3"
|} else {
|		puts "$a == $c, $a >= $d and $b >= 3"
|}


~Responses to Revision 1.2

Revision 1.3 tries to reflect suggestions from various of the following contributors. Thanks.

John Ousterhaut wrote:

 > This is certainly a novel suggestion, but I'm not sure how useful it
   is. The proposed new command doesn't seem much clearer or much more
<
|
<
|
|
|
|
|
|
|
|
>

|

|






|

|


|
|



|
|

|
|
|
|









|
|


|




|
|


|
|

|

|

|
|


|

|



|
|





|


|

|












|
|
|
|
|
|
|
|
|
<
>







|



|

|
|







|
|


|
|

|



|
|
|
<
>
|
<
>







|

|

|

|





|







|

|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
<
>
|
|
|
<
<
<
>
>
>
|
|
<
>
|
|
<
<
|
>
>
|







|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
|
>
|








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
136
137
138
139
140
141
142
143
144
145
146
147

148
149

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

185
186
187
188
189
190

191
192
193

194
195
196
197



198
199
200
201
202

203
204
205


206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

230
231
232
233
234

235
236
237
238
239
240
241
242
243
244

# TIP 70: A Relational Switch Control Structure

	Author:         Bhushit Joshipura <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        20-Oct-2001
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP proposes the introduction of a new control structure, _rswitch_,
which is a relational parallel to switch-case control structure. It
consists of two lists: condition list and situation-reaction list. At
the maximum two conditions can be specified. Based on situation,
reaction is executed. The situation is selected on "first true and
only the first true" basis.

# Rationale

Theoretically only two controls - _if_ and _goto_ - are sufficient
to implement all algorithms. However, languages provide more control
structures for better representation of algorithms. To many structural
programmers like me, a _switch_ statement gives much better picture of
the program than equivalent _if_-_elseif_-...-_else_ chain. It
pronounces the course of decision of a big chunk of program in a single
statement, making understanding and maintaining software easier. It
also helps to optimize the software better if it is written in
_switch_ form. However, _switch_ is strictly data based i.e.
_switch_ happens strictly on data value. 

The proposed _rswitch_ command is a control structure similar to \(and
more general than\) _switch_. \(As a matter of fact, Tcl's _foreach_
control structure is a special case of its for control structure.\) Using
_rswitch_ it should be possible to take decisions based on relations
between entities.

In response to comments on Revision: 1.2 of the draft, Bhushit
Joshipura wrote [Re-edited]:

Why rswitch? [Re-written] 

 1. if..elseif..else contains elements of surprize spread in the code.
    From maintenance point of view, once the
    _if_.._elseif_.._else_ code goes beyond horizon \(one display
    length\), burden of reference retention comes on human brain making
    maintenance bug-prone.

 2. In case of _rswitch_, if a situation refers to one or more
    conditions, we had reduced this burden by stating upfront which
    variable is in the spotlight. The maintainer can then easily jump
    irrelavant cases. 

 3. In _if_.._elseif_.._else_, a string of three conditions \(with
    one of them being a \`not' string\) can mystify me for at least an
    hour. 

 4. In case of an _rswitch_ \(even in a situation which does not
    refer to any conditions\):

	 > 1. \`and' is nested rswitch

	 > 2. \`or' is a fall through case

	 > 3. \`not' could be written as "default" case. \`not' free from \`and'
    and \`or' is less confusing. We can write almost a \`not-less' code
    using "default". 

	 > Logical connectives result into visual presentation.

 5. Object Oriented Programming is trying to eliminate _switch-case_
    statements by identifying localization of references and finding a
    heirarchy of data-actions. 

 6. In similar way one can think of _rswitch_ cases \(situations\).
    Identifying localized references \(w.r.t. situations\) and a
    heirarchy of situations-reactions. However, this is a research
    issue.

Moreover, the writer does not need to be an artist to be able to write understandable code.

# Implementation in Other Languages

I queried about proposal of such a control structure in C to Dr. Dennis
M. Ritchie in February 2001. \(At that time I thought only of
bi-conditional relational switch. See a few pages down for currently
proposed control structure.\)

 >  Absence of relational switch I know this can be odd for other languages - but not for C.
    C is so near to machine and a relational switch could be ideal for many many
    machine-cycle saving situations.

 >  Apart from machine-orientedness, it could avoid many usages of not-so-structured ?:
    operator.

 >  It could simplify a lot of control and signal processing code too.

 >  Why did C become more data-biased for a control structure?

	    relational-switch(expr1,expr2){
	    case ==: statements;
	            break;
	    case > : statements;
	            break;
	    case < : statements;
	            break;
	    default: statements;
	            break;

	    }

TCL need not be so optimized, as C has to be. However, clarity and
maintainability remain formidable reasons for relational switch
implementation.

In a quick reply, Dr. Ritchie wrote back:

 >  The relational switch idea is \(so far as I know\) for C a new suggestion, although I have
    no idea of all things that were proposed for the 1989 or 1999 C standards. If seems to
    hark back to the old Fortran GOTO statement

	    IF (expression) 2, 3, 4

 >  which went to various places depending on whether the expression was -, 0 or \+. It's
    also a bit strange syntactically \(though it might work in the grammar\) in that the case
    values aren't expressions, but just operators.

 >  Regards, Dennis"

Thus the structure is absent from C and its whole family. It is absent
from Pascal, PERL, BASIC, shell scripts - and of course, TCL.

Fortran's computed goto is near to bi-conditional rswitch. \(That way
Chimpanzees are near to Homo sapiens too.\) However, clarity of
presentation of default and fall through are not achievable through
computed goto. Mono-conditional rswitch, however, does not have a
parallel in languages of my knowledge \(C, C\+\+, Java, Pascal, BASIC,
Fortran, shell scripts\). 

# Grammar and Behavior

Overall:

	rswitch {[condition(s)]} {
	    <situation-1> {
	        <reaction-block-1>

	    }
	    ...

	}

The condition list may have no, one or two variables.

A situation is legal if:

 1. It is a valid expression or

 2. If the condition list had at least one element 'x', \{$x $situation\} is a valid expression or

	 > 1. If the condition list had exactly one element 'x', \{$situation $x\} is a valid expression or

	 > 2. If the condition list had two elements 'x' and 'y', \{$x $situation $y\} is a valid expression or

 3. If the condition list had two elements 'x' and 'y' and \{$situation $y\} is a valid expression or

 4. If $situation == "default"

A reaction block is legal if:

 1. It is not the last block and $reactionBlock == "-" \(fall through\) or

 2. It is a valid TCL action block

Let us call a non-default extracted valid expression a SITUATION.

At execution, reaction block following or fell through by the first and only the first SITUATION that becomes true, is executed. In case no SITUATION becomes true and default situation is present, reaction block following or fell through by default statement is executed. Default situation is not necessary for operation of rswitch. An rswitch without any situation-reaction block is grammatically valid.

# Sample Invocations

	# Full length condition block. Second condition perhaps got redundant with maintenance.
	rswitch {$a $b} {
	   {> $c} -
	   {< $d} {
	      puts "$a is either > $c or < $d or both"

	   }
	   {< $c} {
	      # Full length condition block. Second condition is used.
	      rswitch {$a $d} {
	         > {
	            puts "$a is < $c AND > $d"

	         }
	         == {
	            puts "$a and $d are equal and they are < $c"

	         }
	         default {
	            puts "$a is < $c BUT <= $d"
	            puts "should never come here"



	         }
	      }
	   }
	   {3 > } {
	      puts "$a == $c, $a >= $d and $b <= 3"

	   }
	   default {
	      puts "$a == $c, $a >= $d and $b >= 3"


	   }
	}

# Contrast

Contrast above code with its if-elseif-else equivalent. Notice that:

 1. Both the examples have same effect.

 2. Both examples are indented with the same style.

		if {($a > $c) || ($a < $d)} {
			# could you see a maintenance nightmare that could have arisen when
			# reference to $b were eliminated?
			puts "$a is either > $c or < $d or both"
		} elseif {$a < $c} {
			if {$a > $d} {
				puts "$a is < $c AND > $d"
			} elseif {$a == $d} {
				puts "$a and $d are equal and they are < $c"
			} else {
				puts "Pop-up question: What should we have here?
				puts "$a is < $c BUT <= $d"
				puts "should never come here"

			}
		} elseif {3 > $b} {
				puts "$a == $c, $a >= $d and $b <= 3"
		} else {
				puts "$a == $c, $a >= $d and $b >= 3"

		}

# Responses to Revision 1.2

Revision 1.3 tries to reflect suggestions from various of the following contributors. Thanks.

John Ousterhaut wrote:

 > This is certainly a novel suggestion, but I'm not sure how useful it
   is. The proposed new command doesn't seem much clearer or much more
273
274
275
276
277
278
279
280
281
282
283
284
285

286
287
288
289
290
291
292
293
294
295
296
297
298
299

300
301
302
303
304
305
306
307
308
309
310
311
312
313

314
315
316
317
318
319
320
321
322
323

324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

348
349
350
351
352
353
354
355
356
357
358
359
360

   can accept multiple conditional relationships in a single statement.

 > I can also think of another usage of 'rswitch' which doesn't take
   any arguments at all. A vanilla version which is just replacement to
   if-elseif-elseif-..-else structure but only that code is more easier
   to read...

|rswitch { 
|	($a > 4): /* block 1 */ 
|	($b < 100): /* block 2 */
|	($c > 5 ): /* block 3 */ 
|	($d == 10): /*block 4 */ 
|}


Don Porter wrote:

 > Rather than defining two forms of the command, mono-conditional and
   bi-conditional, why not use the power of Tcl to allow for both and
   even more possibilities within a singleform? 

 > Consider:

|rswitch $formatString { 
|	$sub1 $body1
|	...
|	$subN $bodyN 
|} 


 > Then have [rswitch] construct the Tcl expressions to be tested 
   using [format]: 

|format $formatString $sub1 

 > So you could have: 

|rswitch {$a %s $b} { 
|	> {puts "$a is greater than $b"} 
|	< {puts "$a is less than $b"} 
|	== {puts "$a equals $b"} 
|} 


 > or

|rswitch {$a %s} {
|	1 {puts "$a > 1"}
|	5 {puts "$a > 5"}
|	15 {puts "$a > 15"}
|	{>$b} {puts "$a > $b"}
|	{<$b} - > {==$b} {puts "$a <= $b"} 
|} 


 > Extending this idea further, consider the possibility of using
   [[format]] to create the expression like so:

|eval [linsert $sub1 0 format $formatString] 

 > Then the substitutions could be lists of multiple values to
   substitute into multiple %-conversion specifiers in the format
   string, allowing for the construction of quite elaborate
   expressions.

Brent Welch wrote

 > I like Don's suggestion. I'm reminded of the switch statement in
   the tclhttpd state machine, crafted by Steve Uhler:

|set state [string compare $readCount 0],$data(state) 
|switch -glob -- $state {
|	1,start { # Read something in the start state } 
|	0,start { # Read empty line in the start state 
|	1,mime  { # Read something in the mime state }
|	0,mime  { # Read blank line in the mime state }
|	-1,*    { # Read error in any state }
|	default { # Unexpected condition }
|}


 > I had had a bunch of nested if-then-else's, of course. With an
   artful creation of the switch value and the power of things like
   glob, you can really create compact, expressive switch statements
   already.

~Sample Implementation

Will be provided later.

~Copyright

This document is placed in public domain.








|
|
|
|
|
<
>









|
|
|
|
<
>




|



|
|
|
|
<
|
>


|
|
|
|
|
|
<
|
>

|

|











|
|
|
|
|
|
|
|
<
>






|



|


>
272
273
274
275
276
277
278
279
280
281
282
283

284
285
286
287
288
289
290
291
292
293
294
295
296
297

298
299
300
301
302
303
304
305
306
307
308
309
310

311
312
313
314
315
316
317
318
319
320

321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345

346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
   can accept multiple conditional relationships in a single statement.

 > I can also think of another usage of 'rswitch' which doesn't take
   any arguments at all. A vanilla version which is just replacement to
   if-elseif-elseif-..-else structure but only that code is more easier
   to read...

	rswitch { 
		($a > 4): /* block 1 */ 
		($b < 100): /* block 2 */
		($c > 5 ): /* block 3 */ 
		($d == 10): /*block 4 */ 

	}

Don Porter wrote:

 > Rather than defining two forms of the command, mono-conditional and
   bi-conditional, why not use the power of Tcl to allow for both and
   even more possibilities within a singleform? 

 > Consider:

	rswitch $formatString { 
		$sub1 $body1
		...
		$subN $bodyN 

	} 

 > Then have [rswitch] construct the Tcl expressions to be tested 
   using [format]: 

	format $formatString $sub1 

 > So you could have: 

	rswitch {$a %s $b} { 
		> {puts "$a is greater than $b"} 
		< {puts "$a is less than $b"} 
		== {puts "$a equals $b"} 

	} 

 > or

	rswitch {$a %s} {
		1 {puts "$a > 1"}
		5 {puts "$a > 5"}
		15 {puts "$a > 15"}
		{>$b} {puts "$a > $b"}
		{<$b} - > {==$b} {puts "$a <= $b"} 

	} 

 > Extending this idea further, consider the possibility of using
   [format] to create the expression like so:

	eval [linsert $sub1 0 format $formatString] 

 > Then the substitutions could be lists of multiple values to
   substitute into multiple %-conversion specifiers in the format
   string, allowing for the construction of quite elaborate
   expressions.

Brent Welch wrote

 > I like Don's suggestion. I'm reminded of the switch statement in
   the tclhttpd state machine, crafted by Steve Uhler:

	set state [string compare $readCount 0],$data(state) 
	switch -glob -- $state {
		1,start { # Read something in the start state } 
		0,start { # Read empty line in the start state 
		1,mime  { # Read something in the mime state }
		0,mime  { # Read blank line in the mime state }
		-1,*    { # Read error in any state }
		default { # Unexpected condition }

	}

 > I had had a bunch of nested if-then-else's, of course. With an
   artful creation of the switch value and the power of things like
   glob, you can really create compact, expressive switch statements
   already.

# Sample Implementation

Will be provided later.

# Copyright

This document is placed in public domain.

Name change from tip/71.tip to tip/71.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

TIP:            71
Title:          Tk Bitmap Image Improvements
Version:        $Revision: 1.14 $
Author:         Chris Nelson <[email protected]>
Author:         Kevin Kenny <[email protected]>
Author:         Eric Melski <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        26-Oct-2001
Post-History:   
Tcl-Version:    8.5


~ Abstract

Tk has a number of pre-defined bitmaps (10 on all platforms) but it
lacks a number of bitmaps useful for creating GUI elements.  This TIP
adds several such bitmaps (as bitmap images).

~ New Bitmaps

Many complex widgets like comboboxes, spinboxes, etc. require arrows
pictures on buttons.  While newer releases of Tk have added more
widgets, there will always be some unforeseen need for new or
customized widgets.  One example is a menubutton which, according to
the Microsoft Windows User Experience
[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwue/html/welcome.asp],
should have a downward arrow on the right side.  With compound
buttons, it is not hard to do:

|   button .mb -text Tools -image downarrow -compound right

but there is no stock down-arrow image.  

I propose to add 12 bitmap images providing all four directions (up,
down, left, and right) in three sizes (3x2, 5x3, and 7x4) in black.
The down arrows would look something like:

|   @@@@@@@   @@@@@      @@@
|   .@@@@@.   .@@@.      .@.
|   ..@@@..   ..@..    
|   ...@...

I propose the following names:

|   arrow_u7x4      arrow_u5x3      arrow_u3x2
|   arrow_d7x4      arrow_d5x3      arrow_d3x2
|   arrow_l7x4      arrow_l5x3      arrow_l3x2
|   arrow_r7x4      arrow_r5x3      arrow_r3x2

I'm mindful of the fact that adding new predefined bitmap images has
the potential to collide with application-defined images or other
commands but I'm unsure of the workaround for that.

~ Reference Implementation

SourceForge patch 475332 provided a reference implementation of a
previous version of this proposal
[http://sf.net/tracker/?func=detail&aid=475332&group_id=12997&atid=312997].
This version is not implemented yet.

~ Commentary

''Donal K. Fellows <[email protected]> writes:''

 > Previous versions of this TIP proposed fixing the problem using
   bitmaps instead of bitmap images and added an infrastructure for
   tracking those bitmaps.  Since I think that ultimately we should be
   getting rid of bitmaps and instead using something based on the
   image infrastructure (which already has proper introspection
   support) those parts of this TIP have been removed.  However,
   making the changes to effect the switch to using bitmap images
   instead of bitmaps for things like stippes, cursors, etc. lies
   outside the scope of this TIP.

''Donal K. Fellows <[email protected]> writes:''

 > In the long period since this TIP was proposed, the world of GUIs
   has moved on somewhat.  Although the requirement for arrows remains
   the same, the solutions proposed in this TIP (both originally and
   as it now stands) do not permit the sort of graphical snazziness
   that modern users tend to expect.  Nor is there a sufficient range
   of sizes for a reasonable selection to be available for a modern
   display; even the largest of those arrows would look unusably tiny
   on my desktop!  This indicates that a completely different solution
   is required, which in turn would be better stated as a separate
   TIP.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|

|

|






|



|



|
|


|
|
|
|



|
|
|
|





|



|


|

|





|
|




|



|
|







|


>

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

# TIP 71: Tk Bitmap Image Improvements

	Author:         Chris Nelson <[email protected]>
	Author:         Kevin Kenny <[email protected]>
	Author:         Eric Melski <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        26-Oct-2001
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

Tk has a number of pre-defined bitmaps \(10 on all platforms\) but it
lacks a number of bitmaps useful for creating GUI elements.  This TIP
adds several such bitmaps \(as bitmap images\).

# New Bitmaps

Many complex widgets like comboboxes, spinboxes, etc. require arrows
pictures on buttons.  While newer releases of Tk have added more
widgets, there will always be some unforeseen need for new or
customized widgets.  One example is a menubutton which, according to
the Microsoft Windows User Experience
<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwue/html/welcome.asp> ,
should have a downward arrow on the right side.  With compound
buttons, it is not hard to do:

	   button .mb -text Tools -image downarrow -compound right

but there is no stock down-arrow image.  

I propose to add 12 bitmap images providing all four directions \(up,
down, left, and right\) in three sizes \(3x2, 5x3, and 7x4\) in black.
The down arrows would look something like:

	   @@@@@@@   @@@@@      @@@
	   .@@@@@.   .@@@.      .@.
	   ..@@@..   ..@..    
	   ...@...

I propose the following names:

	   arrow_u7x4      arrow_u5x3      arrow_u3x2
	   arrow_d7x4      arrow_d5x3      arrow_d3x2
	   arrow_l7x4      arrow_l5x3      arrow_l3x2
	   arrow_r7x4      arrow_r5x3      arrow_r3x2

I'm mindful of the fact that adding new predefined bitmap images has
the potential to collide with application-defined images or other
commands but I'm unsure of the workaround for that.

# Reference Implementation

SourceForge patch 475332 provided a reference implementation of a
previous version of this proposal
<http://sf.net/tracker/?func=detail&aid=475332&group_id=12997&atid=312997> .
This version is not implemented yet.

# Commentary

_Donal K. Fellows <[email protected]> writes:_

 > Previous versions of this TIP proposed fixing the problem using
   bitmaps instead of bitmap images and added an infrastructure for
   tracking those bitmaps.  Since I think that ultimately we should be
   getting rid of bitmaps and instead using something based on the
   image infrastructure \(which already has proper introspection
   support\) those parts of this TIP have been removed.  However,
   making the changes to effect the switch to using bitmap images
   instead of bitmaps for things like stippes, cursors, etc. lies
   outside the scope of this TIP.

_Donal K. Fellows <[email protected]> writes:_

 > In the long period since this TIP was proposed, the world of GUIs
   has moved on somewhat.  Although the requirement for arrows remains
   the same, the solutions proposed in this TIP \(both originally and
   as it now stands\) do not permit the sort of graphical snazziness
   that modern users tend to expect.  Nor is there a sufficient range
   of sizes for a reasonable selection to be available for a modern
   display; even the largest of those arrows would look unusably tiny
   on my desktop!  This indicates that a completely different solution
   is required, which in turn would be better stated as a separate
   TIP.

# Copyright

This document has been placed in the public domain.

Name change from tip/72.tip to tip/72.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

TIP:            72
Title:          64-Bit Value Support for Tcl on 32-Bit Platforms
Version:        $Revision: 1.10 $
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        05-Nov-2001
Post-History:   
Tcl-Version:    8.4


~ Abstract

This TIP adds the capability to perform computations on values that
are (at least) 64-bits wide even on 32-bit platforms.  It also adds
support for handling files that are larger than 2GB large on those
platforms (where supported by the underlying platform and filing
system).

~ Rationale

There have been a number of requests, and from a whole range of
application areas, for Tcl to be enhanced to handle 64-bit values even
on platforms where that is larger than the native word size, and the
vast majority of C compilers support a large enough arithmetic type
(often called ''long long'' though other names are common on the
Windows platform.)  Such areas include:

 * ''large-file support'' for people working with lots of data.  Note
   that at the moment Tcl cannot even report the file type for a file
   that is larger than 2GB in size.

 * ''large value support'' for people working with network addresses
   (this is likely to come up more in the future with IPv6.)

However, a number of existing algorithms assume that integer
arithmetic operations wrap at 32-bits (demonstrating the need for
''semantic backward-compatibility'' so termed because a recompile of
the C portions of the relevant code will not fix the problem) and
there are many existing extensions that assume a particular word-size
too (requiring ''syntactic backward-compatibility'' because
recompilation will probably cure the problem.)  Hence any upgrade of
Tcl's functionality must be done carefully so as to preserve as much
backward compatibility as possible.

~ Proposed for Changes

To resolve this problem, I will introduce:

 1. A new pair of types at the C level to represent signed and
    unsigned values with a width of at least 64-bits.  These types
    will be called ''Tcl_WideInt'' and ''Tcl_WideUInt'' respectively.
    On 64-bit platforms (and 32-bit platforms where there is no
    compiler support for arithmetic 64-bit types) these will be
    typedef'ed to ''long'' to preserve as much inter-platform
    compatibility as possible.

 >  The type names are based on the term ''Wide'' as opposed to either
    ''Long'' or ''LongLong'' because the first causes a problem with
    existing Tcl APIs (''Tcl_GetLongFromObj'' for example) and the
    second because it is both longer and less mnemonic.  Not all Tcl
    platforms are built with compilers that understand ''long long''
    in the first place, and the major factor in its favour at the C
    level was almost certainly the fact that it did not introduce any
    new reserved words into the C syntax which would have had a major
    backward-compatibility impact - we are not bound by such things
    and can choose to suit ourselves.

 2. A new field of type ''Tcl_WideInt'' in the internalRep union of
    the ''Tcl_Obj'' type.  Note that this is 100% backward compatible
    since the union already contains a field that is a pair of
    pointers (each of which I assume to be at least 32-bits wide.)  

 3. A new object type of 64-bit wide values together with accessor
    functions to create, modify and retrieve from objects of that type
    called ''Tcl_NewWideIntObj'', ''Tcl_SetWideIntObj'' and
    ''Tcl_GetWideIntFromObj'' (on platforms where ''Tcl_WideInt'' is
    not distinct from ''long'', these will be all redirected to the
    previously existing integer type.)

 4. The [[expr]] command shall be reworked so that:

 >  * If a constant looks like a signed integer (i.e. it lies between
      INT_MIN and INT_MAX inclusive) it is treated as such.  Otherwise
      if it looks like an integer of any size, an attempt will be made
      to treat it like a wide integer, and if that fails or it doesn't
      look like an integer at all, it will be treated as a double.
      ''Note'' that this will be a source of a potential backwards
      incompatibility with scripts that include values that are meant
      to be unsigned integers.

 >  * With arithmetic operations, the output will be a double if at
      least one of the operands is a double, a wide integer if at
      least one of the operands is a wide integer, and a normal
      integer otherwise.  (The main exception to this will be the left
      and right shift operations where the type of the second operand
      will not affect the type of the result.)

 >  * The ''int()'' pseudo-function will always return a non-wide
      integer (converting by dropping the high bits) and the new
      pseudo-function ''wide()'' will always return a wide integer
      (converting by sign-extending.)  On platforms without a distinct
      64-bit type, these operations will behave identically.

 >  * User-defined functions will be able to gain access to the wide
      integer through an extra ''wideValue'' field in the
      ''Tcl_Value'' structure and TCL_WIDE_INT (which will be the same
      as TCL_INT on platforms without a distinct 64-bit type) value in
      the ''Tcl_ValueType'' enumeration.

 5. The [[incr]] command will be able to increment variables
    containing 64-bit values correctly, but will only accept 32-bit
    values as amounts to increment by.

 6. ''Tcl_Seek'' and ''Tcl_Tell'' (together will all channel drivers)
    will be updated to use the new 64-bit type for offsets (which will
    reflect at the Tcl level in the [[seek]] and [[tell]] commands)
    though a compatibility interface for old extensions that do not
    supply a channel driver will be maintained (though the size of
    offset reportable through the interface will naturally be limited.)

 7. ''Tcl_FSStat'' and ''Tcl_FSLstat'' will all be
    updated to use a stat structure reference that can contain 64-bit
    wide values.  This will enable various [[file]] subcommands (and
    [[glob]] with some options) to work correctly with files over 2GB
    in size.  Note that there is no neat way to do this in a backward
    compatible way as there is currently no guarantee on which fields
    will actually be present in the structure, but those functions
    have never been available outside an alpha...

 >  Because the name of a suitable structure varies considerably
    between platforms, a new type, ''Tcl_StatBuf'', will be declared
    to be the type of the structure which a pointer to should be
    passed to the stat-related functions. A new function,
    ''Tcl_AllocStatBuf'', will be provided to allow extensions to
    allocate a buffer of the correct size whatever the platform.

 >  Note that ''Tcl_Stat'' will written to contain
    backward-compatability code so that code that references it will
    work unchanged.

 8. The ''format'' and ''scan'' commands will gain a significance to
    the ''l'' modifier to their integer-handling conversion specifiers
    (d, u, i, o and x) which will tell them to work with 64-bit values
    (if those are not the default for the platform anyway.)

 9. The ''binary'' command will gain new ''w'' and ''W'' specifiers
    for its ''format'' and ''scan'' subcommands.  These will operate
    on 64-bit wide values in a fashion analogous to the existing ''i''
    and ''I'' specifiers (i.e. smallest byte to largest, and largest
    byte to smallest respectively.)

 10. New compatibility functions will also be provided, because not
     all platforms have convenient equivalent functions to ''strtoll''
     and ''strtoull''.

 11. ''Tcl_LinkVar'' will be extended to be given the ability to link
     with a wide C variable (via a TCL_LINK_WIDE_INT flag).

 12. The ''tcl_platform'' array will gain a new member, ''wordSize'',
     which will give the native size of machine words on the host
     platform (actually whatever ''sizeof(long)'' returns.)

~ Summary of Incompatibilities and Fixes

The behaviour of expressions containing constants that appear positive
but which have a negative internal representation will change, as
these will now usually be interpreted as wide integers.  This is
always fixable by replacing the constant with ''int(''constant'')''.

Extensions creating new channel types will need
to be altered as different types are now in use in those areas.  The
change to the declaration of ''Tcl_FSStat'' and ''Tcl_FSLstat'' (which
are the new preferred API in any case) are less serious as no
non-alpha releases have been made yet with those API functions.

Scripts that are lax about the use of the ''l'' modifier in ''format''
and ''scan'' will probably need to be rewritten.  This should be very
uncommon though as previously it had absolutely no effect.

Extensions that create new math functions that take more than one
argument will need to be recompiled (the size of ''Tcl_Value''
changes), and functions that accept arguments of any type
(''TCL_EITHER'') will need to be rewritten to handle wide integer
values.  (I do not expect this to affect many extensions at all.)

~ Why Tcl_WideInt?

I chose the name ''Tcl_WideInt'' for the type because it represents a
wider-than-normal integer.  Alternatives that were considered and
rejected were:

 Tcl_LongLong: This takes its name from the name of the underlying C
    type used in many UNIX compilers, but that in turn was chosen
    because it meant that no new keywords would be added to the
    language, and not out of any feeling that the type name itself is
    of any wider merit. Seeing as Tcl is a keyword-less language, there
    is no particular reason for going down this route (which would
    lead to things like a ''longlong()'' type conversion function added
    to the [[expr]] command, which is really very ugly indeed...) It
    is also not universally the name of the underlying type; the Windows
    world is different (as usual.)

 Tcl_Int64: This name, by contrast, comes more from the Windows world.
    It's major problem is that it specifies eternally what the size of
    the type is, whereas at some point in the future (when 64-bit words
    are the norm) we may want to support something wider still (though
    I do not yet know what uses we would put 128-bit integers to.)  I
    believe that the name of a type is part of its specification, but
    that the size of the type is less so.  ''Tcl_Int64'' is also ugly
    when it comes to derivations of the name for things like the type
    converter in [[expr]] (again) and the names of variables containing
    values of the type (internally, as formal parameters, and as fields
    of structures) and may well clash on systems where the C compiler
    gives real meaning to ''int64'' by default.  By contrast,
    ''Tcl_WideInt'' lends itself well to generating variable names
    (''wideValue'', ''widePtr'', etc., and even just plain ''w'' in the
    implementation of the bytecode execution engine) which, as the
    person implementing the changes, was a major consideration.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|

|
|

|





|
|

|



|
|


|
|
|

|
|



|





|
|
|
|


|
|
|

|






|
|

|



|
|
|
|

|

|
|



|



|


|

|

|
|
|
|


|
|
|
|
|

|



|
|
|

|
|

|

|
|





|
|


|


|



|
|
|
|

|
|
|
|
|


|
|

|
|

|

|

|




|



|
|


|
|



|
|
|
|

|

|



|




|
|
|

|

|

|
|
|

|

|
|
|
|
|
|
|


|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

# TIP 72: 64-Bit Value Support for Tcl on 32-Bit Platforms

	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        05-Nov-2001
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

This TIP adds the capability to perform computations on values that
are \(at least\) 64-bits wide even on 32-bit platforms.  It also adds
support for handling files that are larger than 2GB large on those
platforms \(where supported by the underlying platform and filing
system\).

# Rationale

There have been a number of requests, and from a whole range of
application areas, for Tcl to be enhanced to handle 64-bit values even
on platforms where that is larger than the native word size, and the
vast majority of C compilers support a large enough arithmetic type
\(often called _long long_ though other names are common on the
Windows platform.\)  Such areas include:

 * _large-file support_ for people working with lots of data.  Note
   that at the moment Tcl cannot even report the file type for a file
   that is larger than 2GB in size.

 * _large value support_ for people working with network addresses
   \(this is likely to come up more in the future with IPv6.\)

However, a number of existing algorithms assume that integer
arithmetic operations wrap at 32-bits \(demonstrating the need for
_semantic backward-compatibility_ so termed because a recompile of
the C portions of the relevant code will not fix the problem\) and
there are many existing extensions that assume a particular word-size
too \(requiring _syntactic backward-compatibility_ because
recompilation will probably cure the problem.\)  Hence any upgrade of
Tcl's functionality must be done carefully so as to preserve as much
backward compatibility as possible.

# Proposed for Changes

To resolve this problem, I will introduce:

 1. A new pair of types at the C level to represent signed and
    unsigned values with a width of at least 64-bits.  These types
    will be called _Tcl\_WideInt_ and _Tcl\_WideUInt_ respectively.
    On 64-bit platforms \(and 32-bit platforms where there is no
    compiler support for arithmetic 64-bit types\) these will be
    typedef'ed to _long_ to preserve as much inter-platform
    compatibility as possible.

	 >  The type names are based on the term _Wide_ as opposed to either
    _Long_ or _LongLong_ because the first causes a problem with
    existing Tcl APIs \(_Tcl\_GetLongFromObj_ for example\) and the
    second because it is both longer and less mnemonic.  Not all Tcl
    platforms are built with compilers that understand _long long_
    in the first place, and the major factor in its favour at the C
    level was almost certainly the fact that it did not introduce any
    new reserved words into the C syntax which would have had a major
    backward-compatibility impact - we are not bound by such things
    and can choose to suit ourselves.

 2. A new field of type _Tcl\_WideInt_ in the internalRep union of
    the _Tcl\_Obj_ type.  Note that this is 100% backward compatible
    since the union already contains a field that is a pair of
    pointers \(each of which I assume to be at least 32-bits wide.\)  

 3. A new object type of 64-bit wide values together with accessor
    functions to create, modify and retrieve from objects of that type
    called _Tcl\_NewWideIntObj_, _Tcl\_SetWideIntObj_ and
    _Tcl\_GetWideIntFromObj_ \(on platforms where _Tcl\_WideInt_ is
    not distinct from _long_, these will be all redirected to the
    previously existing integer type.\)

 4. The [expr] command shall be reworked so that:

	 >  \* If a constant looks like a signed integer \(i.e. it lies between
      INT\_MIN and INT\_MAX inclusive\) it is treated as such.  Otherwise
      if it looks like an integer of any size, an attempt will be made
      to treat it like a wide integer, and if that fails or it doesn't
      look like an integer at all, it will be treated as a double.
      _Note_ that this will be a source of a potential backwards
      incompatibility with scripts that include values that are meant
      to be unsigned integers.

	 >  \* With arithmetic operations, the output will be a double if at
      least one of the operands is a double, a wide integer if at
      least one of the operands is a wide integer, and a normal
      integer otherwise.  \(The main exception to this will be the left
      and right shift operations where the type of the second operand
      will not affect the type of the result.\)

	 >  \* The _int\(\)_ pseudo-function will always return a non-wide
      integer \(converting by dropping the high bits\) and the new
      pseudo-function _wide\(\)_ will always return a wide integer
      \(converting by sign-extending.\)  On platforms without a distinct
      64-bit type, these operations will behave identically.

	 >  \* User-defined functions will be able to gain access to the wide
      integer through an extra _wideValue_ field in the
      _Tcl\_Value_ structure and TCL\_WIDE\_INT \(which will be the same
      as TCL\_INT on platforms without a distinct 64-bit type\) value in
      the _Tcl\_ValueType_ enumeration.

 5. The [incr] command will be able to increment variables
    containing 64-bit values correctly, but will only accept 32-bit
    values as amounts to increment by.

 6. _Tcl\_Seek_ and _Tcl\_Tell_ \(together will all channel drivers\)
    will be updated to use the new 64-bit type for offsets \(which will
    reflect at the Tcl level in the [seek] and [tell] commands\)
    though a compatibility interface for old extensions that do not
    supply a channel driver will be maintained \(though the size of
    offset reportable through the interface will naturally be limited.\)

 7. _Tcl\_FSStat_ and _Tcl\_FSLstat_ will all be
    updated to use a stat structure reference that can contain 64-bit
    wide values.  This will enable various [file] subcommands \(and
    [glob] with some options\) to work correctly with files over 2GB
    in size.  Note that there is no neat way to do this in a backward
    compatible way as there is currently no guarantee on which fields
    will actually be present in the structure, but those functions
    have never been available outside an alpha...

	 >  Because the name of a suitable structure varies considerably
    between platforms, a new type, _Tcl\_StatBuf_, will be declared
    to be the type of the structure which a pointer to should be
    passed to the stat-related functions. A new function,
    _Tcl\_AllocStatBuf_, will be provided to allow extensions to
    allocate a buffer of the correct size whatever the platform.

	 >  Note that _Tcl\_Stat_ will written to contain
    backward-compatability code so that code that references it will
    work unchanged.

 8. The _format_ and _scan_ commands will gain a significance to
    the _l_ modifier to their integer-handling conversion specifiers
    \(d, u, i, o and x\) which will tell them to work with 64-bit values
    \(if those are not the default for the platform anyway.\)

 9. The _binary_ command will gain new _w_ and _W_ specifiers
    for its _format_ and _scan_ subcommands.  These will operate
    on 64-bit wide values in a fashion analogous to the existing _i_
    and _I_ specifiers \(i.e. smallest byte to largest, and largest
    byte to smallest respectively.\)

 10. New compatibility functions will also be provided, because not
     all platforms have convenient equivalent functions to _strtoll_
     and _strtoull_.

 11. _Tcl\_LinkVar_ will be extended to be given the ability to link
     with a wide C variable \(via a TCL\_LINK\_WIDE\_INT flag\).

 12. The _tcl\_platform_ array will gain a new member, _wordSize_,
     which will give the native size of machine words on the host
     platform \(actually whatever _sizeof\(long\)_ returns.\)

# Summary of Incompatibilities and Fixes

The behaviour of expressions containing constants that appear positive
but which have a negative internal representation will change, as
these will now usually be interpreted as wide integers.  This is
always fixable by replacing the constant with _int\(_constant_\)_.

Extensions creating new channel types will need
to be altered as different types are now in use in those areas.  The
change to the declaration of _Tcl\_FSStat_ and _Tcl\_FSLstat_ \(which
are the new preferred API in any case\) are less serious as no
non-alpha releases have been made yet with those API functions.

Scripts that are lax about the use of the _l_ modifier in _format_
and _scan_ will probably need to be rewritten.  This should be very
uncommon though as previously it had absolutely no effect.

Extensions that create new math functions that take more than one
argument will need to be recompiled \(the size of _Tcl\_Value_
changes\), and functions that accept arguments of any type
\(_TCL\_EITHER_\) will need to be rewritten to handle wide integer
values.  \(I do not expect this to affect many extensions at all.\)

# Why Tcl\_WideInt?

I chose the name _Tcl\_WideInt_ for the type because it represents a
wider-than-normal integer.  Alternatives that were considered and
rejected were:

 Tcl\_LongLong: This takes its name from the name of the underlying C
    type used in many UNIX compilers, but that in turn was chosen
    because it meant that no new keywords would be added to the
    language, and not out of any feeling that the type name itself is
    of any wider merit. Seeing as Tcl is a keyword-less language, there
    is no particular reason for going down this route \(which would
    lead to things like a _longlong\(\)_ type conversion function added
    to the [expr] command, which is really very ugly indeed...\) It
    is also not universally the name of the underlying type; the Windows
    world is different \(as usual.\)

 Tcl\_Int64: This name, by contrast, comes more from the Windows world.
    It's major problem is that it specifies eternally what the size of
    the type is, whereas at some point in the future \(when 64-bit words
    are the norm\) we may want to support something wider still \(though
    I do not yet know what uses we would put 128-bit integers to.\)  I
    believe that the name of a type is part of its specification, but
    that the size of the type is less so.  _Tcl\_Int64_ is also ugly
    when it comes to derivations of the name for things like the type
    converter in [expr] \(again\) and the names of variables containing
    values of the type \(internally, as formal parameters, and as fields
    of structures\) and may well clash on systems where the C compiler
    gives real meaning to _int64_ by default.  By contrast,
    _Tcl\_WideInt_ lends itself well to generating variable names
    \(_wideValue_, _widePtr_, etc., and even just plain _w_ in the
    implementation of the bytecode execution engine\) which, as the
    person implementing the changes, was a major consideration.

# Copyright

This document has been placed in the public domain.

Name change from tip/73.tip to tip/73.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

TIP:		73
Title:          Export Tcl_GetTime in the Public API
State:          Final
Type:           Project
Tcl-Version:    8.4
Vote:           Done
Post-History:   
Version:	$Revision: 1.4 $
Author:		Kevin Kenny <[email protected]>
Created:	03-Nov-2001


~ Abstract

This TIP proposes that the existing ''TclpGetTime'' function be
renamed to be ''Tcl_GetTime'' and included in the published API.

~ Rationale

The Tcl library provides a uniform abstraction, ''TclpGetTime'' that
is implemented on each of the platforms to retrieve absolute time in a
''Tcl_Time'' object.  This function is highly useful outside the Tcl
library itself, since it hides a very complex set of interfaces,
particularly on Windows, where several hundred lines of code enable
its use for high-precision measurements.  For this reason, it ought to
be made part of the public API.

~ Proposed Change

The existing ''TclpGetTime'' procedure shall be renamed to be
''Tcl_GetTime'', and its declaration shall be added to
''tcl.decls''.

| void TclpGetTime( Tcl_Time* timePtr );

A definition of ''TclpGetTime'' as a stub procedure that simply
invokes ''Tcl_GetTime'' shall be retained in ''tclInt.decls'' for
compatibility with existing Stubs-enabled extensions that invoke it.

This change requires no other change to the public headers; the
''Tcl_Time'' structure is already exported in ''tcl.h''.

~ Copyright

Copyright � 2001 by Kevin B. Kenny.  Distribution in whole or part,
with or without annotations, is unlimited.

<
|
|
|
|
|
|
<
|
|
>

|

|
|

|

|

|





|

|
|
|

|

|
|



|

|

|

>

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

# TIP 73: Export Tcl_GetTime in the Public API
	State:          Final
	Type:           Project
	Tcl-Version:    8.4
	Vote:           Done
	Post-History:   

	Author:		Kevin Kenny <[email protected]>
	Created:	03-Nov-2001
-----

# Abstract

This TIP proposes that the existing _TclpGetTime_ function be
renamed to be _Tcl\_GetTime_ and included in the published API.

# Rationale

The Tcl library provides a uniform abstraction, _TclpGetTime_ that
is implemented on each of the platforms to retrieve absolute time in a
_Tcl\_Time_ object.  This function is highly useful outside the Tcl
library itself, since it hides a very complex set of interfaces,
particularly on Windows, where several hundred lines of code enable
its use for high-precision measurements.  For this reason, it ought to
be made part of the public API.

# Proposed Change

The existing _TclpGetTime_ procedure shall be renamed to be
_Tcl\_GetTime_, and its declaration shall be added to
_tcl.decls_.

	 void TclpGetTime( Tcl_Time* timePtr );

A definition of _TclpGetTime_ as a stub procedure that simply
invokes _Tcl\_GetTime_ shall be retained in _tclInt.decls_ for
compatibility with existing Stubs-enabled extensions that invoke it.

This change requires no other change to the public headers; the
_Tcl\_Time_ structure is already exported in _tcl.h_.

# Copyright

Copyright © 2001 by Kevin B. Kenny.  Distribution in whole or part,
with or without annotations, is unlimited.

Name change from tip/74.tip to tip/74.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

TIP:            74
Title:          wm stackorder command
Version:        $Revision: 1.6 $
Author:         Mo DeJong <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        12-Nov-2001
Post-History:   
Tcl-Version:    8.4


~ Abstract

Tk provides no means to query the stacking order of toplevel windows.
This functionality would be useful to applications that wished to save
and restore the state and relative order of each toplevel.  This
functionality would also make it possible to write test cases for window
manager related commands like focus, raise, and lower.  This document
suggests a new ''wm stackorder'' command to address this deficiency.

~ Specification

|wm stackorder window ?isabove|isbelow? ?window?

The following would return a list of all the toplevels
on the display:

|% wm stackorder .

The returned list would include the passed in window and its children.
Only those toplevel windows that are mapped would be returned.  The
stacking order is from lowest to highest, so the last element in the
list is the window on top of the display.

The ''wm stackorder'' command could also be used to compare the
relative position in the stackorder.  The following command would
return true if ''.a'' was higher in the stacking order compared to
''.b''.

|% wm stackorder .a isabove .b

The ''isbelow'' usage is analogous:

|% wm stackorder .b isbelow .a

One additional C API would be added.  It would accept a Tk window and
return an array of Tk windows in stacking order.  This function would
be implemented in the platform specific window manager code, such as
''tkUnixWm.c''.  This function signature is subject to change.

|TkWindow ** TkWmStackorderToplevel(TkWindow *parentPtr);

~ Rationale

Tk exposes a number of features related to toplevel windows through
the ''wm'' command.  While a user can set the relative position of a
toplevel in the stacking order, it is not currently possible to query
the stacking order for toplevel windows.

Users are frustrated by the lack of access to this information.  This
is a posting to news:comp.lang.tcl by Jim Ingham is typical:

 > ''This seems pretty basic, but for the life of me I can't figure
   out how to determine the stacking order of Tk toplevels.  I want to
   save away the currently open windows in my application, and I would
   like to preserve both positions ''and'' window stacking order.  I
   know how to get the positions of toplevels, but I can't figure out
   how to get the window manager's stacking order.  Should be in the
   ''wm'' commands, but nothing leaps out at me.  What am I missing?''

It is simply not logical to provide a means to manipulate the stacking
order of toplevel windows without also providing a way to query the
stacking order.  This functionality is needed, if only to help with
the authoring of test cases.  For example, one could verify that a
call to ''wm raise'' actually worked by checking to see if the
stacking order was changed.

The second form of the wm stackorder command provides an easy way to
compare the relative position of windows in the stacking order.  This
sort of boolean check is commonly needed in test cases.  One could
implement the same logic by querying the whole list, searching it
twice to find the indices, and then comparing the indices, but the
code would not be as easy to understand and it would not be as
efficient.

The ''wm stackorder'' command also has an extra benefit, it provides
an easy way to query the currently mapped toplevel windows.  It is not
difficult to write a procedure that recursively descends through each
window and filters out those windows that are not mapped toplevels.
This ''wm stackorder'' command would just make it easier to query this
list.

~ Reference Implementation

A reference implementation has been created for X windows and Win32
systems. The X version makes us of the ''XQueryTree()'' function
while the Windows version depends on the ''EnumWindows()'' Win32 API.
Both implementations query the stacking order of toplevel windows
in the root window.  The patch, test cases, and documentation changes
can be found in Tk patch 481148 at SourceForge.  Porting to MacOS
and MacOS X will require assistance from area maintainers.

~ Alternatives

Instead of adding a new ''wm stackorder'' command, one could
adjust the behavior of ''winfo children''. The
documentation currently reads:

 winfo children window:
    Returns a list containing the path names of all the children of
    window.  The list is in stacking order, with the lowest window
    first.  Top-level windows are returned as children of their
    logical parents.

A user would no doubt conclude that the stacking order was maintained
for both toplevels and contained widgets.  Unfortunately, the
implementation only tracks the stacking order for contained
widgets.

|% toplevel .t
|% pack [button .t.b1]
|% pack [button .t.b2]
|% winfo children .t
|.t.b1 .t.b2
|% raise .t.b1
|% winfo children .t
|.t.b2 .t.b1

Tk does not track stacking order changes for toplevels.

|% toplevel .t2
|% winfo children .
|.t .t2
|% raise .t
|% winfo children .
|.t .t2

There are two possible ways to "fix" the ''winfo children'' command
so that it would return toplevels in stacking order. One could call
the ''TkWmStackorderToplevel()'' function and use the results to
sort any toplevels that would be returned by ''winfo children''.
The other option would be to resort the ''TkWindow->childList''
as toplevels are moved up and down in the stacking order.

Both of these alternatives have some serious implementation issues.
The ''TkWmStackorderToplevel()'' function is very slow. The X based
implementation recurses through each window in the Tk hierarchy to
create a mapping of wrapper window ids to ''TkWindow''s. The function
then queries the X server to find each X window that is a child of
the root screen and checks to see if the window exists in the
mapping. When compared to ''winfo children'', which just loops
over an in-memory list, it is easy to see why ''wm stackorder''
is so much slower.

|% for {set i 0} {$i < 10} {incr i} {toplevel .t$i}
|% time {winfo children .} 100
|34 microseconds per iteration
|% time {wm stackorder .} 100
|394 microseconds per iteration

It would not be wise to make the ''winfo children'' command
an order of magnitude slower just to add a new capability.
One also needs to remember that the ''winfo children'' command
is often used recursively, so any slowdown would be multiplied
by the depth of the window hierarchy.

The second option would be to keep the ''TkWindow->childList''
sorted as toplevels are raised and lowered either by the
application or the window manager. This would imply binding
to the <Circulate> event under X. While the <Circulate> event
is defined in Tk, it does not seem to actually be delivered
by the window manager. In any event, this seems like an area
ripe for incompatibility and error.

Even if one of the above fixes for the ''winfo children'' command
was doable, it still would not satisfy user's needs. One would
be able to compare the relative stacking order of two toplevels
that have the same parent.

|% toplevel .t1
|% toplevel .t2
|% winfo children .
|{.t1 .t2}

Unfortunately, it would not be possible to compare the stacking
order of two toplevel windows that have different parents.

|% toplevel .t1
|% toplevel .t1.t2
|# No help here!
|% winfo children .
|.t1
|% winfo children .t1
|.t1.t2

It would not even be possible to query the position of the
. window in the stacking order since it does not have a
parent window that can be passed to ''winfo children''.

Since modifying ''winfo children'' could cause some
serious problems and would ultimately be ineffective,
this alternative was rejected. Instead, the documentation
for the ''winfo children'' command should be updated to
indicate that toplevel windows are not returned in stacking
order.

~ Risks

It is not entirely clear what risks would be associated with this TIP.
The logic of the ''wm stackorder'' command is rather insulated from
the rest of the Tk core.  Changing the implementation of
''Tk_RestackWindow()'' and keeping the ''TkWindow->childList'' up to
date w.r.t. external changes would be more risky since it could affect
other parts of the core. Doing an explicit query to find the stacking
order seems a lot less error prone when compared to monitoring events
from the window manager. We might speed things up by
also storing wrapper pointers in the map table so that a call to
''Tk_IdToWindow()'' with a wrapper id would work, but it is not
clear that would help since the ''XQueryTree()'' likely takes up
most of the function processing time.

It is also not known how difficult or costly this functionality will
be to implement on Mac OS, or Mac OS X.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|






|

|

|




|






|

|
|

|

|

|




|

|

|


|






|


|


|





|










|



|


|


|
|





|

|
|













|
|
|
|
|
|
|
|



|
|
|
|
|
|

|

|
|
|



|

|


|
|


|
|
|
|
|

|

|



|







|




|
|
|
|




|
|
|
|
|
|
|



|

|


|



|


|

|





|
|





|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

# TIP 74: wm stackorder command

	Author:         Mo DeJong <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        12-Nov-2001
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

Tk provides no means to query the stacking order of toplevel windows.
This functionality would be useful to applications that wished to save
and restore the state and relative order of each toplevel.  This
functionality would also make it possible to write test cases for window
manager related commands like focus, raise, and lower.  This document
suggests a new _wm stackorder_ command to address this deficiency.

# Specification

	wm stackorder window ?isabove|isbelow? ?window?

The following would return a list of all the toplevels
on the display:

	% wm stackorder .

The returned list would include the passed in window and its children.
Only those toplevel windows that are mapped would be returned.  The
stacking order is from lowest to highest, so the last element in the
list is the window on top of the display.

The _wm stackorder_ command could also be used to compare the
relative position in the stackorder.  The following command would
return true if _.a_ was higher in the stacking order compared to
_.b_.

	% wm stackorder .a isabove .b

The _isbelow_ usage is analogous:

	% wm stackorder .b isbelow .a

One additional C API would be added.  It would accept a Tk window and
return an array of Tk windows in stacking order.  This function would
be implemented in the platform specific window manager code, such as
_tkUnixWm.c_.  This function signature is subject to change.

	TkWindow ** TkWmStackorderToplevel(TkWindow *parentPtr);

# Rationale

Tk exposes a number of features related to toplevel windows through
the _wm_ command.  While a user can set the relative position of a
toplevel in the stacking order, it is not currently possible to query
the stacking order for toplevel windows.

Users are frustrated by the lack of access to this information.  This
is a posting to news:comp.lang.tcl by Jim Ingham is typical:

 > _This seems pretty basic, but for the life of me I can't figure
   out how to determine the stacking order of Tk toplevels.  I want to
   save away the currently open windows in my application, and I would
   like to preserve both positions _and_ window stacking order.  I
   know how to get the positions of toplevels, but I can't figure out
   how to get the window manager's stacking order.  Should be in the
   _wm_ commands, but nothing leaps out at me.  What am I missing?_

It is simply not logical to provide a means to manipulate the stacking
order of toplevel windows without also providing a way to query the
stacking order.  This functionality is needed, if only to help with
the authoring of test cases.  For example, one could verify that a
call to _wm raise_ actually worked by checking to see if the
stacking order was changed.

The second form of the wm stackorder command provides an easy way to
compare the relative position of windows in the stacking order.  This
sort of boolean check is commonly needed in test cases.  One could
implement the same logic by querying the whole list, searching it
twice to find the indices, and then comparing the indices, but the
code would not be as easy to understand and it would not be as
efficient.

The _wm stackorder_ command also has an extra benefit, it provides
an easy way to query the currently mapped toplevel windows.  It is not
difficult to write a procedure that recursively descends through each
window and filters out those windows that are not mapped toplevels.
This _wm stackorder_ command would just make it easier to query this
list.

# Reference Implementation

A reference implementation has been created for X windows and Win32
systems. The X version makes us of the _XQueryTree\(\)_ function
while the Windows version depends on the _EnumWindows\(\)_ Win32 API.
Both implementations query the stacking order of toplevel windows
in the root window.  The patch, test cases, and documentation changes
can be found in Tk patch 481148 at SourceForge.  Porting to MacOS
and MacOS X will require assistance from area maintainers.

# Alternatives

Instead of adding a new _wm stackorder_ command, one could
adjust the behavior of _winfo children_. The
documentation currently reads:

 winfo children window:
    Returns a list containing the path names of all the children of
    window.  The list is in stacking order, with the lowest window
    first.  Top-level windows are returned as children of their
    logical parents.

A user would no doubt conclude that the stacking order was maintained
for both toplevels and contained widgets.  Unfortunately, the
implementation only tracks the stacking order for contained
widgets.

	% toplevel .t
	% pack [button .t.b1]
	% pack [button .t.b2]
	% winfo children .t
	.t.b1 .t.b2
	% raise .t.b1
	% winfo children .t
	.t.b2 .t.b1

Tk does not track stacking order changes for toplevels.

	% toplevel .t2
	% winfo children .
	.t .t2
	% raise .t
	% winfo children .
	.t .t2

There are two possible ways to "fix" the _winfo children_ command
so that it would return toplevels in stacking order. One could call
the _TkWmStackorderToplevel\(\)_ function and use the results to
sort any toplevels that would be returned by _winfo children_.
The other option would be to resort the _TkWindow->childList_
as toplevels are moved up and down in the stacking order.

Both of these alternatives have some serious implementation issues.
The _TkWmStackorderToplevel\(\)_ function is very slow. The X based
implementation recurses through each window in the Tk hierarchy to
create a mapping of wrapper window ids to _TkWindow_s. The function
then queries the X server to find each X window that is a child of
the root screen and checks to see if the window exists in the
mapping. When compared to _winfo children_, which just loops
over an in-memory list, it is easy to see why _wm stackorder_
is so much slower.

	% for {set i 0} {$i < 10} {incr i} {toplevel .t$i}
	% time {winfo children .} 100
	34 microseconds per iteration
	% time {wm stackorder .} 100
	394 microseconds per iteration

It would not be wise to make the _winfo children_ command
an order of magnitude slower just to add a new capability.
One also needs to remember that the _winfo children_ command
is often used recursively, so any slowdown would be multiplied
by the depth of the window hierarchy.

The second option would be to keep the _TkWindow->childList_
sorted as toplevels are raised and lowered either by the
application or the window manager. This would imply binding
to the <Circulate> event under X. While the <Circulate> event
is defined in Tk, it does not seem to actually be delivered
by the window manager. In any event, this seems like an area
ripe for incompatibility and error.

Even if one of the above fixes for the _winfo children_ command
was doable, it still would not satisfy user's needs. One would
be able to compare the relative stacking order of two toplevels
that have the same parent.

	% toplevel .t1
	% toplevel .t2
	% winfo children .
	{.t1 .t2}

Unfortunately, it would not be possible to compare the stacking
order of two toplevel windows that have different parents.

	% toplevel .t1
	% toplevel .t1.t2
	# No help here!
	% winfo children .
	.t1
	% winfo children .t1
	.t1.t2

It would not even be possible to query the position of the
. window in the stacking order since it does not have a
parent window that can be passed to _winfo children_.

Since modifying _winfo children_ could cause some
serious problems and would ultimately be ineffective,
this alternative was rejected. Instead, the documentation
for the _winfo children_ command should be updated to
indicate that toplevel windows are not returned in stacking
order.

# Risks

It is not entirely clear what risks would be associated with this TIP.
The logic of the _wm stackorder_ command is rather insulated from
the rest of the Tk core.  Changing the implementation of
_Tk\_RestackWindow\(\)_ and keeping the _TkWindow->childList_ up to
date w.r.t. external changes would be more risky since it could affect
other parts of the core. Doing an explicit query to find the stacking
order seems a lot less error prone when compared to monitoring events
from the window manager. We might speed things up by
also storing wrapper pointers in the map table so that a call to
_Tk\_IdToWindow\(\)_ with a wrapper id would work, but it is not
clear that would help since the _XQueryTree\(\)_ likely takes up
most of the function processing time.

It is also not known how difficult or costly this functionality will
be to implement on Mac OS, or Mac OS X.

# Copyright

This document has been placed in the public domain.

Name change from tip/75.tip to tip/75.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
136
137
138

TIP:            75
Title:          Refer to Sub-RegExps Inside 'switch -regexp' Bodies
Version:        $Revision: 1.14 $
Author:         Donal K. Fellows <[email protected]>
Author:         J�nos Hol�nyi <[email protected]>
Author:         Salvatore Sanfilippo <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        28-Nov-2001
Post-History:   
Discussions-To: http://purl.org/mini/cgi-bin/chat.cgi
Keywords:       switch,regexp,parentheses
Tcl-Version:    8.5


~ Abstract

Currently, it is necessary to match a regular expression against a
string twice in order to get the sub-expressions out of the matched
string.  This TIP alters that so that those sub-exps can be
substituted directly into the body of the script to be executed.

~Rationale

Similarly to the

|   regexp -- <RE> $string matchvar submatchvar ...

of Tcl and the

|   interact -re <RE> {
|      set matches "$interact_out(0,string) $interact_out(1,string) ..."
|   }


of Tcl/Expect, it would be very helpful and would also make Tcl more
consistent if the [[switch]] command of Tcl would support references
to parenthesized REs inside the switch patterns from the bodies
associated to each of the patterns.  As it is, it is currently
necessary to match the regular expression against the string twice to
obtain this information.

~Specification

The easiest way to get the information is to place it into a variable.
All that remains is a way to specify which variable should receive the
information.  This is done by a new option to the [[switch]] command:
''-matchvar''.  The argument to this optiongives the name of a
variable in which will be placed a Tcl list of the matches discovered
by the RE engine, such that the part of the string that was matched is
given by [[lindex $var 0]], the first parenthesis by [[lindex $var
1]], etc.  The alternative to this is to use the name of an array, but
this is more expensive.

The indices which the match occurred at can also be sometimes useful.
Therefore, the new option ''-indexvar'' will also be provided which
will name a variable into which a list of match indices (each a two
item list of values in the same way that [[regexp -indices]] computes)
will be placed.  It will be legal for both -matchvar and -indexvar to
be specified in the same [[switch]] command, but only if the matching
mode is -regexp.  (The other kinds of match modes always match against
the whole string anyway.)

Both variables (if specified, of course) will contain the empty list
if the ''default'' branch is taken.

~Example

|set string "some long complicated message"
|switch -matchvar foo -indexvar bar -regexp -- $string {
|   {\w*(e)\w*} {
|      puts "matched [lindex $foo 0] with 'e' at [lindex $bar 1 0]"
|   }

|   default {
|      puts "no words containing a letter 'e' at all"
|   }
|}



~Alternatives

Actually, no new syntax is needed to achieve the mentioned ability.
The solution could adopt the behavior of [[regsub]] ''(description
taken from regsub(n))'':

 > If subSpec contains a `&' or `\0', then it is replaced in the
   substitution with the portion of string that matched exp.  If
   subSpec contains a `\''n''', where ''n'' is a digit between 1 and
   9, then it is replaced in the substitution with the portion of
   string that matched the ''n''-th parenthesized subexpression of
   exp.  Additional backslashes may be used in subSpec to prevent
   special interpretation of `&' or `\0' or `\n' or backslash.

This has the disadvantage of being incompatible with existing code
that makes use of the -regexp option to [[switch]] and which may well
have characters matching the above sequences inside already.

Another alternative can be to specify either -submatches, or -subindexes and
use three elements for every switch case. The first is the regexp,
the second the list of vars like in the [regexp] command, and the
last the script to execute.

|set string [getSomeComplexProtocolLine]
|switch -regexp -submatches -- $string {
|    {EHLO (.*)} {match heloarg} {
|       puts "Helo $heloarg"
|    }

|    {MAIL FROM: <(.*)@(.*)>} {match user host} {
|       puts "Mail from $user at $host"
|    }

|    {QUIT} {} {
|       exit
|    }

|    default {} {
|       puts "What a strange SMTP command!"
|    }
|}  



Usually submatches have quite logical names, so it is possible
that to refer they by name instead of to use [lindex] can be
more comfortable. Another minor advantage of this is that variable
names are very near the script, so it shouldn't be hard to follow
what the script is doing.

On the other side this changes a well-known fact of switch getting
as input two elements for every case; the main proposal of this TIP
has the advantage of leaving that feature of the [[switch]] command as
an invariant.  This makes the overall implementation of the feature
easier, and also makes it easier to tell people how to use.  And it
allows for trivial obtaining of both the matched string and the range
of the input string that matched.  Of course, in that case you could
just have four values for each entry, but that is getting baroque.

~Reference Implementation

http://sf.net/tracker/?func=detail&aid=848578&group_id=10894&atid=310894

~Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
|
>

|






|



|



|
|
<
|
>

|





|



|
|


|
|



|
|
|

|
|
|

|
|

|

|
|
|
|
<
>
|
|
<
<
|
>
>
|


|
|

|

|

|

|


|







|
|
|
|
<
>
|
|
<
>
|
|
<
>
|
|
<
<
>
>









|






|

|

|


>

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
136
137
138

# TIP 75: Refer to Sub-RegExps Inside 'switch -regexp' Bodies

	Author:         Donal K. Fellows <[email protected]>
	Author:         János Holányi <[email protected]>
	Author:         Salvatore Sanfilippo <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        28-Nov-2001
	Post-History:   
	Discussions-To: http://purl.org/mini/cgi-bin/chat.cgi
	Keywords:       switch,regexp,parentheses
	Tcl-Version:    8.5
-----

# Abstract

Currently, it is necessary to match a regular expression against a
string twice in order to get the sub-expressions out of the matched
string.  This TIP alters that so that those sub-exps can be
substituted directly into the body of the script to be executed.

# Rationale

Similarly to the

	   regexp -- <RE> $string matchvar submatchvar ...

of Tcl and the

	   interact -re <RE> {
	      set matches "$interact_out(0,string) $interact_out(1,string) ..."

	   }

of Tcl/Expect, it would be very helpful and would also make Tcl more
consistent if the [switch] command of Tcl would support references
to parenthesized REs inside the switch patterns from the bodies
associated to each of the patterns.  As it is, it is currently
necessary to match the regular expression against the string twice to
obtain this information.

# Specification

The easiest way to get the information is to place it into a variable.
All that remains is a way to specify which variable should receive the
information.  This is done by a new option to the [switch] command:
_-matchvar_.  The argument to this optiongives the name of a
variable in which will be placed a Tcl list of the matches discovered
by the RE engine, such that the part of the string that was matched is
given by [lindex $var 0], the first parenthesis by [lindex $var
1], etc.  The alternative to this is to use the name of an array, but
this is more expensive.

The indices which the match occurred at can also be sometimes useful.
Therefore, the new option _-indexvar_ will also be provided which
will name a variable into which a list of match indices \(each a two
item list of values in the same way that [regexp -indices] computes\)
will be placed.  It will be legal for both -matchvar and -indexvar to
be specified in the same [switch] command, but only if the matching
mode is -regexp.  \(The other kinds of match modes always match against
the whole string anyway.\)

Both variables \(if specified, of course\) will contain the empty list
if the _default_ branch is taken.

# Example

	set string "some long complicated message"
	switch -matchvar foo -indexvar bar -regexp -- $string {
	   {\w*(e)\w*} {
	      puts "matched [lindex $foo 0] with 'e' at [lindex $bar 1 0]"

	   }
	   default {
	      puts "no words containing a letter 'e' at all"


	   }
	}

# Alternatives

Actually, no new syntax is needed to achieve the mentioned ability.
The solution could adopt the behavior of [regsub] _\(description
taken from regsub\(n\)\)_:

 > If subSpec contains a \`&' or \`\\0', then it is replaced in the
   substitution with the portion of string that matched exp.  If
   subSpec contains a \`\\_n**, where _n_ is a digit between 1 and
   9, then it is replaced in the substitution with the portion of
   string that matched the _n_-th parenthesized subexpression of
   exp.  Additional backslashes may be used in subSpec to prevent
   special interpretation of \`&' or \`\\0' or \`\\n' or backslash.

This has the disadvantage of being incompatible with existing code
that makes use of the -regexp option to [switch] and which may well
have characters matching the above sequences inside already.

Another alternative can be to specify either -submatches, or -subindexes and
use three elements for every switch case. The first is the regexp,
the second the list of vars like in the [regexp] command, and the
last the script to execute.

	set string [getSomeComplexProtocolLine]
	switch -regexp -submatches -- $string {
	    {EHLO (.*)} {match heloarg} {
	       puts "Helo $heloarg"

	    }
	    {MAIL FROM: <(.*)@(.*)>} {match user host} {
	       puts "Mail from $user at $host"

	    }
	    {QUIT} {} {
	       exit

	    }
	    default {} {
	       puts "What a strange SMTP command!"


	    }
	}  

Usually submatches have quite logical names, so it is possible
that to refer they by name instead of to use [lindex] can be
more comfortable. Another minor advantage of this is that variable
names are very near the script, so it shouldn't be hard to follow
what the script is doing.

On the other side this changes a well-known fact of switch getting
as input two elements for every case; the main proposal of this TIP
has the advantage of leaving that feature of the [switch] command as
an invariant.  This makes the overall implementation of the feature
easier, and also makes it easier to tell people how to use.  And it
allows for trivial obtaining of both the matched string and the range
of the input string that matched.  Of course, in that case you could
just have four values for each entry, but that is getting baroque.

# Reference Implementation

<http://sf.net/tracker/?func=detail&aid=848578&group\_id=10894&atid=310894>

# Copyright

This document has been placed in the public domain.

Name change from tip/76.tip to tip/76.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

TIP:		76
Title:		Make 'regsub' Return a String
State:		Final
Type:		Project
Tcl-Version:	8.4
Vote:		Done
Post-History:	
Version:	$Revision: 1.3 $
Author:		Bruce Hartweg <[email protected]>
Author:		Donal K. Fellows <[email protected]>
Created:	29-Nov-2001


~ Abstract

This TIP proposes altering the [[regsub]] command so that it can
return the substituted string as the result of the command.

~ Rationale

In many of the most common uses of the [[regsub]] command, the
substituted string is used only once in the immediately following
command.  However, the [[regsub]] command only provides the
substituted string via a variable, with the result of the command
itself being the number of substitutions performed.  For many uses of
the command, it is the substituted string though that is the most
useful result, especially if some other transformation is going to be
applied to it (like further [[regsub]] commands or some other Tcl
command like one of the [[string]] subcommands or [[subst]].)  This
TIP proposes a mechanism for providing the ability to return the
string as the command's result, and in a way that is
backward-compatible with existing scripts.

~ Specification

|   regsub ?switches? exp string subSpec ?varName?

If ''varName'' is supplied the new string is written there and the
number of substitutions are returned (same as current behavior).  If
''varName'' is not supplied than the new string is returned as the
result of the [[regsub]] command.

~ Reference Implementation

This is a pretty easy change, although I do not currently have an
environment where I can actually build and test this the following
should create the desired behavior.

File: ''tcl/generic/tclCmdMZ.c''

Function: ''Tcl_RegsubObjCmd''

Currently (v 1.52):

|    if (objc - idx != 4) {
|	 Tcl_WrongNumArgs(interp, 1, objv,
|		 "?switches? exp string subSpec varName");
|	 return TCL_ERROR;
|    }


which should be changed to:

|    objc -= idx;
|    if (objc != 3 || objc != 4) {
|	 Tcl_WrongNumArgs(interp, 1, objv,
|		 "?switches? exp string subSpec ?varName?");
|	 return TCL_ERROR;
|    }


and then at the end change this:

|    if (Tcl_ObjSetVar2(interp, objv[3], NULL, resultPtr, 0) == NULL) {
|	 Tcl_AppendResult(interp, "couldn't set variable \"",
|		 Tcl_GetString(objv[3]), "\"", (char *) NULL);
|	 result = TCL_ERROR;
|    } else {
|	 /*
|	  * Set the interpreter's object result to an integer object
|	  * holding the number of matches.
|	  */
|
|	 Tcl_SetIntObj(Tcl_GetObjResult(interp), numMatches);
|    }


to this:

|    if (objc == 4) {
|        if (Tcl_ObjSetVar2(interp, objv[3], NULL, resultPtr, 0) == NULL) {
|            Tcl_AppendResult(interp, "couldn't set variable \"",
|        	     Tcl_GetString(objv[3]), "\"", (char *) NULL);
|            result = TCL_ERROR;
|        } else {
|            /*
|             * Set the interpreter's object result to an integer object
|             * holding the number of matches.
|             */
|
|            Tcl_SetIntObj(Tcl_GetObjResult(interp), numMatches);
|        }

|    } else {
|           /*
|            * No varname supplied, return string as result
|            */
|           Tcl_SetObjResult(interp, resultPtr);
|    }


And then minor updates to the man page to show that ''varName'' is
optional.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
|
>

|

|


|

|

|




|
|




|

|

|
|
|
|

|





|

|

|

|
|
|
|
<
|
>


|
|
|
|
|
<
>



|
|
|
|
|
|
|
|
|
|
|
<
>



|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
|
>
|


|


>

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

# TIP 76: Make 'regsub' Return a String
	State:		Final
	Type:		Project
	Tcl-Version:	8.4
	Vote:		Done
	Post-History:	

	Author:		Bruce Hartweg <[email protected]>
	Author:		Donal K. Fellows <[email protected]>
	Created:	29-Nov-2001
-----

# Abstract

This TIP proposes altering the [regsub] command so that it can
return the substituted string as the result of the command.

# Rationale

In many of the most common uses of the [regsub] command, the
substituted string is used only once in the immediately following
command.  However, the [regsub] command only provides the
substituted string via a variable, with the result of the command
itself being the number of substitutions performed.  For many uses of
the command, it is the substituted string though that is the most
useful result, especially if some other transformation is going to be
applied to it \(like further [regsub] commands or some other Tcl
command like one of the [string] subcommands or [subst].\)  This
TIP proposes a mechanism for providing the ability to return the
string as the command's result, and in a way that is
backward-compatible with existing scripts.

# Specification

	   regsub ?switches? exp string subSpec ?varName?

If _varName_ is supplied the new string is written there and the
number of substitutions are returned \(same as current behavior\).  If
_varName_ is not supplied than the new string is returned as the
result of the [regsub] command.

# Reference Implementation

This is a pretty easy change, although I do not currently have an
environment where I can actually build and test this the following
should create the desired behavior.

File: _tcl/generic/tclCmdMZ.c_

Function: _Tcl\_RegsubObjCmd_

Currently \(v 1.52\):

	    if (objc - idx != 4) {
		 Tcl_WrongNumArgs(interp, 1, objv,
			 "?switches? exp string subSpec varName");
		 return TCL_ERROR;

	    }

which should be changed to:

	    objc -= idx;
	    if (objc != 3 || objc != 4) {
		 Tcl_WrongNumArgs(interp, 1, objv,
			 "?switches? exp string subSpec ?varName?");
		 return TCL_ERROR;

	    }

and then at the end change this:

	    if (Tcl_ObjSetVar2(interp, objv[3], NULL, resultPtr, 0) == NULL) {
		 Tcl_AppendResult(interp, "couldn't set variable \"",
			 Tcl_GetString(objv[3]), "\"", (char *) NULL);
		 result = TCL_ERROR;
	    } else {
		 /*
		  * Set the interpreter's object result to an integer object
		  * holding the number of matches.
		  */
	
		 Tcl_SetIntObj(Tcl_GetObjResult(interp), numMatches);

	    }

to this:

	    if (objc == 4) {
	        if (Tcl_ObjSetVar2(interp, objv[3], NULL, resultPtr, 0) == NULL) {
	            Tcl_AppendResult(interp, "couldn't set variable \"",
	        	     Tcl_GetString(objv[3]), "\"", (char *) NULL);
	            result = TCL_ERROR;
	        } else {
	            /*
	             * Set the interpreter's object result to an integer object
	             * holding the number of matches.
	             */
	
	            Tcl_SetIntObj(Tcl_GetObjResult(interp), numMatches);

	        }
	    } else {
	           /*
	            * No varname supplied, return string as result
	            */
	           Tcl_SetObjResult(interp, resultPtr);

	    }

And then minor updates to the man page to show that _varName_ is
optional.

# Copyright

This document has been placed in the public domain.

Name change from tip/77.tip to tip/77.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

TIP:		77
Title:		Support for Nested Paired Item Lists
Version:	$Revision: 1.3 $
Author:		Christian Williams <[email protected]>
State:		Withdrawn
Type:		Project
Tcl-Version:	8.5
Vote:		Pending
Created:	07-Dec-2001
Obsoleted-By:	111
Post-History:	


~ Abstract

Tcl arrays can be transformed to and from lists using the ''array
get'' and ''array set'' commands.  This TIP proposes a new command for
working directly these paired lists, and extending them to allow
nesting in a manner analogous to [22].

~ Rationale

Tcl lists provide only ordinal access to their items; often it makes
more sense to access items by pre-assigned descriptive names.  This
can be easily accomplished with Tcl arrays.  Consider these
alternatives:

|  set urlList { http tcl.activestate.com 80 /index.html }
|
|  array set urlArray {
|       proto   http
|       host    tcl.activestate.com
|       port    80
|       uri     /index.html
|  }


Clearly the array approach promotes more readable code
(''$urlArray(host)'' versus ''[lindex $urlList 1]'').

However, it's quite unwieldy and sometimes expensive to use arrays to
access members of many sets of structured data, particularly when that
data contains nested structures.

Consider this structured data:

|  set data {
|       text    {ignored-data}
|       valid-styles {
|               justification {left centered right full}
|               font          {courier helvetica times}
|       }
|  }



Extracting items from structures like this can be accomplished by
multiple ''array set'' commands:

|  array set dataArray $data
|  array set validStylesArray $dataArray(valid-styles)
|  puts "Justification: $validStylesArray(justification)"

To modify an item in ''struct'', we need some pretty ugly code:

|  array set dataArray $struct
|  array set validStylesArray $dataArray(valid-styles)
|  set validStylesArray(justification) {left}
|  set dataArray(valid-styles) [array get validStylesArray]
|  set data [array get dataArray]

Clearly, all this setting and getting of arrays imposes a rather high
overhead; many variables are created and moved around.  Also, if this
is occurring in a loop, then care must be taken to unset the
''dataArray'' and ''validStylesArray'' arrays first.

In contrast, a C programmer may expect that code to look more like
this:

|  data->valid-styles->justification = 'left';

Extending Tcl with a command supporting nested, paired item lists
would permit very efficient and readable handling of these useful data
structures.

~ Specification

Under this proposal, a new command named ''pair'' (referring to the
pairs of name/value list items it works with) would be added to the
Tcl core.

A well-formed paired list is defined as a well-formed Tcl list whose
length is evenly divisible by two.  In each pair of list items, the
first item gives the name of the pair, and the second gives the value.
Paired lists may be nested by placing a valid paired list in the
second (value) item of any pair.  Note that the pairs are not grouped
together into a two-item list as in TclX's keyed lists.  Tcl's ''array
get'' command returns a well-formed paired list.

The syntax for the new ''pair'' command would be:

|  pair option variable node ?newValue?

Valid values for the ''options'' argument include ''get'', ''set'',
''unset'', ''exists'', and ''append''.  These subcommands are
equivalent to the existing Tcl commands of the same names.

The ''variable'' argument is the name of a Tcl variable; it is always
referred to by name, not by its value (that is, no ''$'').  Generally,
the variable would contain a well-formed, and optionally nested,
paired list.

The ''node'' argument is a well-formed Tcl list of zero or more items
specifying the route to the item we're interested in.

For example:

|  set data {
|       text    {ignored-data}
|       valid-styles {
|               justification {left centered right full}
|               font          {courier helvetica times}
|       }
|  }


|
|  puts "Justification: [pair get data {valid-styles justification}]"

displays "Justification: left centered right full".

If the ''data'' argument contains zero items, then the "root" node of
the variable is targeted -- that is, the entire variable:

|  pair set node {} new-value
|  puts $node

displays "new-value".

If a non-existent node is targeted using the ''get'' or ''unset''
options, an error is returned:

|  unset x
|  pair get x {first second third}
|  -> no such value

If a non-existent node is targeted using the ''set'' or ''append''
options, the node, and any parent nodes, are created.

|  unset x
|  pair set x {first second third} value
|  puts $x

displays "first {second {third value}}"

The ''exists'' option mimics Tcl's ''info exists'' command:

|  set x {name value}
|  pair exists x name
|  -> 1
|  pair exists x name2
|  -> 0

The ''set'' and ''append'' options return the value of the node that
has just been set, not the value of the variable.  This would seem to
be more in keeping with the intent of Tcl's ''set'' and ''append''
commands' return values than duplicating the exact behaviour:

|  puts [pair set x {first second third} value]

displays "value".

An error is returned if a variable is passed to the ''pair'' command
which doesn't contain a well-formed paired Tcl list at any point on
the way to the node specified by the ''node'' argument:

|  set x {name value thirdarg}
|  pair get x name
|  -> list must have an even number of elements

If there are traces registered on the variable passed to the ''pair''
command, they are triggered in the same manner as Tcl's ''set'' and
''append'' commands.  Note that the ''append'' option triggers only
write triggers, not read triggers.

Note that the ''set'' and ''append'' options both return the value of
the node specified, and the ''newValue'' argument is optional in both
cases, making the ''get'' option redundant.  The ''get'' command is
included to improve readability.

If the variable passed to ''pair'' doesn't exist, it will be created
if the option is 'set' or ''append''; the ''exists'' option will
always return a ''0''; the ''get'' option will return an error.

If a paired list contains multiple pairs with identical names, the
pair occurring later in the list is targeted.  This is specified to
mimic the behaviour of ''array set'':

|  set x "name value1 name value2"
|  pair get x name
|  -> value2
|
|  array set arrX $x
|  set arrX(name)
|  -> value2

~ Reference Implementation

http://sf.net/tracker/?func=detail&aid=491070&group_id=10894&atid=310894

There should be a public C API for working with nested paired lists.
The supplied reference code currently does not provide this.

~ Notes

It would be nice to mimic Tcl 8.4's new ''unset -nocomplain''
behaviour.

~ Side Effects

Whether the result of the pair operation is successful, the underlying
Tcl_Obj that represents the list argument may have its internal
representation invalidated or changed to that of a list.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|

|
|

|

|






|
|
|
|
|
|
|
<
|
>

|







|
|
|
|
|
<
<
|
>
>

|

|
|
|

|

|
|
|
|
|




|




|





|

|
|






|
|
|

|

|

|
|


|
|



|




|
|
|
|
|
<
<
>
>
|
|



|


|
|



|


|
|
|

|


|
|
|

|

|

|
|
|
|
|

|

|


|



|

|

|
|
|

|
|
|


|
|
|


|
|
|



|

|
|
|
|
|
|
|

|

|




|

|


|


|


|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

# TIP 77: Support for Nested Paired Item Lists

	Author:		Christian Williams <[email protected]>
	State:		Withdrawn
	Type:		Project
	Tcl-Version:	8.5
	Vote:		Pending
	Created:	07-Dec-2001
	Obsoleted-By:	111
	Post-History:	
-----

# Abstract

Tcl arrays can be transformed to and from lists using the _array
get_ and _array set_ commands.  This TIP proposes a new command for
working directly these paired lists, and extending them to allow
nesting in a manner analogous to [[22]](22.md).

# Rationale

Tcl lists provide only ordinal access to their items; often it makes
more sense to access items by pre-assigned descriptive names.  This
can be easily accomplished with Tcl arrays.  Consider these
alternatives:

	  set urlList { http tcl.activestate.com 80 /index.html }
	
	  array set urlArray {
	       proto   http
	       host    tcl.activestate.com
	       port    80
	       uri     /index.html

	  }

Clearly the array approach promotes more readable code
\(_$urlArray\(host\)_ versus _[lindex $urlList 1]_\).

However, it's quite unwieldy and sometimes expensive to use arrays to
access members of many sets of structured data, particularly when that
data contains nested structures.

Consider this structured data:

	  set data {
	       text    {ignored-data}
	       valid-styles {
	               justification {left centered right full}
	               font          {courier helvetica times}


	       }
	  }

Extracting items from structures like this can be accomplished by
multiple _array set_ commands:

	  array set dataArray $data
	  array set validStylesArray $dataArray(valid-styles)
	  puts "Justification: $validStylesArray(justification)"

To modify an item in _struct_, we need some pretty ugly code:

	  array set dataArray $struct
	  array set validStylesArray $dataArray(valid-styles)
	  set validStylesArray(justification) {left}
	  set dataArray(valid-styles) [array get validStylesArray]
	  set data [array get dataArray]

Clearly, all this setting and getting of arrays imposes a rather high
overhead; many variables are created and moved around.  Also, if this
is occurring in a loop, then care must be taken to unset the
_dataArray_ and _validStylesArray_ arrays first.

In contrast, a C programmer may expect that code to look more like
this:

	  data->valid-styles->justification = 'left';

Extending Tcl with a command supporting nested, paired item lists
would permit very efficient and readable handling of these useful data
structures.

# Specification

Under this proposal, a new command named _pair_ \(referring to the
pairs of name/value list items it works with\) would be added to the
Tcl core.

A well-formed paired list is defined as a well-formed Tcl list whose
length is evenly divisible by two.  In each pair of list items, the
first item gives the name of the pair, and the second gives the value.
Paired lists may be nested by placing a valid paired list in the
second \(value\) item of any pair.  Note that the pairs are not grouped
together into a two-item list as in TclX's keyed lists.  Tcl's _array
get_ command returns a well-formed paired list.

The syntax for the new _pair_ command would be:

	  pair option variable node ?newValue?

Valid values for the _options_ argument include _get_, _set_,
_unset_, _exists_, and _append_.  These subcommands are
equivalent to the existing Tcl commands of the same names.

The _variable_ argument is the name of a Tcl variable; it is always
referred to by name, not by its value \(that is, no _$_\).  Generally,
the variable would contain a well-formed, and optionally nested,
paired list.

The _node_ argument is a well-formed Tcl list of zero or more items
specifying the route to the item we're interested in.

For example:

	  set data {
	       text    {ignored-data}
	       valid-styles {
	               justification {left centered right full}
	               font          {courier helvetica times}


	       }
	  }
	
	  puts "Justification: [pair get data {valid-styles justification}]"

displays "Justification: left centered right full".

If the _data_ argument contains zero items, then the "root" node of
the variable is targeted -- that is, the entire variable:

	  pair set node {} new-value
	  puts $node

displays "new-value".

If a non-existent node is targeted using the _get_ or _unset_
options, an error is returned:

	  unset x
	  pair get x {first second third}
	  -> no such value

If a non-existent node is targeted using the _set_ or _append_
options, the node, and any parent nodes, are created.

	  unset x
	  pair set x {first second third} value
	  puts $x

displays "first \{second \{third value\}\}"

The _exists_ option mimics Tcl's _info exists_ command:

	  set x {name value}
	  pair exists x name
	  -> 1
	  pair exists x name2
	  -> 0

The _set_ and _append_ options return the value of the node that
has just been set, not the value of the variable.  This would seem to
be more in keeping with the intent of Tcl's _set_ and _append_
commands' return values than duplicating the exact behaviour:

	  puts [pair set x {first second third} value]

displays "value".

An error is returned if a variable is passed to the _pair_ command
which doesn't contain a well-formed paired Tcl list at any point on
the way to the node specified by the _node_ argument:

	  set x {name value thirdarg}
	  pair get x name
	  -> list must have an even number of elements

If there are traces registered on the variable passed to the _pair_
command, they are triggered in the same manner as Tcl's _set_ and
_append_ commands.  Note that the _append_ option triggers only
write triggers, not read triggers.

Note that the _set_ and _append_ options both return the value of
the node specified, and the _newValue_ argument is optional in both
cases, making the _get_ option redundant.  The _get_ command is
included to improve readability.

If the variable passed to _pair_ doesn't exist, it will be created
if the option is 'set' or _append_; the _exists_ option will
always return a _0_; the _get_ option will return an error.

If a paired list contains multiple pairs with identical names, the
pair occurring later in the list is targeted.  This is specified to
mimic the behaviour of _array set_:

	  set x "name value1 name value2"
	  pair get x name
	  -> value2
	
	  array set arrX $x
	  set arrX(name)
	  -> value2

# Reference Implementation

<http://sf.net/tracker/?func=detail&aid=491070&group\_id=10894&atid=310894>

There should be a public C API for working with nested paired lists.
The supplied reference code currently does not provide this.

# Notes

It would be nice to mimic Tcl 8.4's new _unset -nocomplain_
behaviour.

# Side Effects

Whether the result of the pair operation is successful, the underlying
Tcl\_Obj that represents the list argument may have its internal
representation invalidated or changed to that of a list.

# Copyright

This document has been placed in the public domain.

Name change from tip/78.tip to tip/78.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484

TIP:            78
Title:          TEA 2.0 Definitions
Version:        $Revision: 1.4 $
Author:         Andreas Kupries <[email protected]>
Author:         Larry W. Virden <[email protected]>
State:          Draft
Type:           Informative
Vote:           Pending
Created:        15-Dec-2001
Post-History:   


~ Abstract

This document is an informational TIP providing definitions for
commonly used terms (like package, extension, core, distribution,
etc.) to make future communication among people in the community
easier.  It is recommended that future and past documents specifying
details inside of the greater context of TEA refer to this document to
ensure a consistent usage of terms.

~ Background

This document is an adjunct to the [[TIP <<vision>>]].  ''(DKF - Is
this meant to be a reference to [34]?  Edit to such if so...)''

To facilitate the specification and adoption of clearly defined
interfaces to various activities and technologies it specifies a
number of terms used by the community at large to create a greater
unity and coherence in the usage of these terms.  In other words, by
creating generally accepted definitions for important terms the risk
of misunderstanding each other is reduced.

~ Specification of Technical Terms

This section specifies a number of important technical terms in
alphabetical order.  Terms used inside of a specification are
highlighted.

 * Application

 > An entity implementing some functionality required by a ''P/A
   User'' (see section ''Roles'') to perform his work.  Consists of
   one more files.  May make use of ''packages'' to implement its
   functionality.

 * Archive

 > Encapsulation of a ''distribution'' in a single file.  Well-known
   formats for archives are tar, gzipped tar, bzipped tar, and zip.

 * Binary generation

 > The process of wrapping up a built package into a binary
   ''distribution''.  See ''building'' too.

 * Building

 > The process of ''configuring'' and ''transforming'' a source
   ''distribution'' into a set of files which can be either
   immediately installed on the site which built them or wrapped into
   a binary ''distribution'' for shipment to other sites.  This also
   includes the execution of a test-suite coming with the package.

 * Bundle

 > A ''distribution'' encapsulating more than one ''package''.

 * Catalog

 > A catalog is a site providing an index of the packages.

 * Configuration

 > The process of customizing a source distribution for a particular
   architecture and/or site.  A part of ''Building''.

 * Conflict

 > Two or more packages are said to be in conflict if the usage of one of them
   excludes the usage of the others.

 > In a ''strong conflict'' installing one of the packages disallows
   even the installation of the others.

 * Core

 > A shorthand for ''Tcl core''.

 * Core distribution.

 > See ''Tcl core distribution''.

 * Dependency

 > A relationship between packages.  A package X is said dependent on
   another package Y if said package Y is required to allow X to work.

 > There are several types of dependencies:

 > * Build-time dependency

 > > Y is required to allow X to be build.

 > * Run-time dependency

 > > Y is required to allow the usage of an installed X.

 > * Optional dependency

 > > Y can be used by X (usually for improved performance) but is not
     required for building or use.

 * Distribution

 > An encapsulation of one or more ''packages'' for transport between
   places, machines, organizations, and people.  Several types of
   distributions are possible, explained below.

 > 1. binary

 > > A binary distribution is in a state and format allowing the
     installation of the contained packages on a particular platform.

 > > It contains at least all the files

 > > * implementing the functionality of the distributed packages and

 > > * required to allow the package management of the Tcl core to
       handle the packages.

 > > A binary distribution usually contains just the files for a
     single architecture.  This is not a explicit requirement however.
     In other words, a binary distribution is allowed to contain the
     files for several architectures.  Such a binary distribution will
     be called a ''fat binary distribution''.

 > > We distinguish between three sub-types:

 > > * installable

 > > > This is the minimal binary distribution we spoke of before.

 > > * auto-installable

 > > > Like ''installable''', but additionally contains an application
       whose execution will perform all the steps which are necessary
       to install the contained packages at a site.  The installation
       to add the packages to (and thus the location of the installed
       packages) can be freely chosen by the caller of the executable.

 > > * auto-image

 > > > Like ''auto-installable'', but the final location of the
       packages is hard-wired into the distribution.  This means that
       a site using auto-images is restricted to one installation per
       architecture for which files are contained in the binary
       distribution.

 > > > Some of the existing archive formats restrict their contained
       distributions to this type.  Examples of such archive formats
       are

 > > > * RPM (RedHat Package Manager)

 > > > * DEB (DEBian Linux package format)

 > > See [TIP 55] for the specification of a proposed layout for
     binary distributions.

 > 1. bundle

 > > A distribution which either contains the distributions of more
     than one package or a list of references to packages.  The
     references are done by specifying the name and version of the
     packages contained in the bundle.

 > 1. buildable

 > > See ''source''.

 > 1. compileable

 > > See ''source''.

 > 1. raw

 > > A raw distribution is the most fundamental distribution.  Its
     format is nearly completely unspecified.  Its contents are
     straight from a source repository.  The process of converting a
     raw distribution into a source distribution is called
     ''Preparation''.

 > > Because of the unformatted nature of a raw distribution the
     commands for its conversion into a source distribution have to be
     part of it.  This is the only part of a raw distribution which
     can and has to be specified.

 > > Example: The execution of ''autoconf'' to generate a
     ''configure'' script from its ''configure.in'' file can be a
     single step in a complex preparation.

 > 1. source

 > > A source distribution is in a format and state where tools can be
     used to build its contents.

 > > The format needs further specification but for now we can assume
     that it is governed by the current TEA specification.

 > > Alternate name for this type of distribution are ''compileable''
     and ''buildable''.

 * Distribution repository

 > See ''repository''

 * Extension

 > Alternate name for a ''package'', generally used for packages
   requiring compilation to become functional.

 > This term is ''deprecated''.

 * Installation

 > A special type of ''distribution repository, binary'' (see
   ''repository'') containing all ''packages'' which were installed on
   a site.  A site may host several installations differing in version
   and/or configuration of Tcl, and/or the platform Tcl was built for,
   etc.

 > Currently difficult to do but in the future it should made be
   possible for an installation to refer and use another installation,
   provided both are configured identically.  This allows a site to
   build a hierarchy of installations from the most general containing
   the common packages down to installations associated with one or
   more ''P/A Developers''.

 * Installing

 > The process of unpacking a binary distribution and adding the
   contained packages to an ''installation''.  The latter may include
   moving files to their proper places.

 > Also the process of adding a built package to an ''installation''.

 * Manifest

 > A file detailing the files making up a particular package.

 * Package

 > A collection of files providing additional functionality to a user
   of a Tcl interpreter when loaded into said interpreter.

 > Some files in a package implement the provided functionality
   whereas other files contain meta-information required by the
   package management of Tcl to be able to use the package.

 * Preparation

 > The process of converting a raw ''distribution'' into a source
   ''distribution'' suitable as input to ''building''.  This includes
   actions like:

 > * Retrieval of sources from a source repository

 > * Creating a ''configure'' file from its ''configure.in''.

 > * Creating the distributed documentation from internal sources.

 > * Removal of internal files containing notes, scratch info and the like.

 > * Inserting version information into files.

 > * ...

 > The tool ''makedist'' (which I wrote) is in my mind when thinking
   about this step.

 * Raw retrieval

 > The process of retrieving a raw ''distribution'' from a ''source
   repository''.

 * Repository

 > General term with two possible meanings.

 > 1. A collection of ''archives''.  The exact term for this type of
     repository is "distribution repository".

 > > If a distribution repository is restricted to one type of
     distributions this type can be added to the term as further
     specification of the type of repository.  Thus

 > > * ''distribution repository, binary'', or

 > > * ''distribution repository, source''.

 > 2. A collection of directories, developer files and control files
      containing version control information.  The exact term for this
      type of repository is ''source repository''.

 > > A repository can either be internal to an organization or public.

 * Source repository

 > See ''repository''

 * Tcl core

 > The most fundamental part in the Tcl world; the interpreter engine
   and the builtin commands coming with it.  These are all commands
   and procedures reported by ''info commands'' for a ''tclsh'' which
   was started with an empty ''.tclshrc'' file and after sourcing all
   ''.tcl'' files in the directory returned by ''info library''.

 * Tcl core distribution

 > The most fundamental distribution there is.  Contains the ''Tcl
   core'' and a number of packages.

~ Roles

The terms in the preceding section specified both passive data
structures and actions upon them.  This section specifies the possible
actors, i.e. entities which perform one or more of these actions.

To make the specification easier, related actions are grouped into
roles of behavior.  The mapping from roles to actual actors,
i.e. people and organizations is n:m.  On other words, one actor may
have several roles, either at once or changing over time and one role
can be held by several distinct actors.

Examples are given at the end of this section.

 1. Catalog manager

 > A catalog manager handles one or more catalogs.  He is responsible
   for

 > * the final name arbitration for packages with conflicting names

 > * and the categorization of the packages indexed by the catalog.

 1. P/A Builder

 > A package and/or application builder is a person and/or organization

 > * who retrieves raw distributions from source repositories and (in
     a sequence of several steps) generates binary distributions from
     them.

 > * or who retrieves source distributions from distribution
     repositories and (in a sequence of several steps) generates
     binary distributions from them.

 > * uploads the generated binary distributions into one or more
     distribution repositories.

 > * uploads the generated source distributions into one or more
     distribution repositories.

 > The intermediate steps performed by a builder are ''Preparation'',
   ''Building'', and ''Binary generation''.

 > If ''System administrator'' and ''P/A Builder'' coordinate with each other
   it is also possible to install a package directly from the built
   package.

 > ''NOTE:'' Think about splitting P/A Builder into two roles; one for
   the preparation of source ''distributions'' and a second role for
   the generation of binary ''distributions''.

|         TODO Find some nice names for the split roles.

 1. P/A Developer

 > A developer is a ''P/A User'' whose tasks include the creation of
   new packages and/or applications.  A workspace contains the raw
   sources of these new packages and applications.  For posterity and
   version control it is kept synchronized with one or more ''source
   repositories''.

 > During development, at least one installation has to be accessible,
   containing the initial packages, the new packages and the
   applications built upon the packages.

 1. P/A User

 > A person or organization which uses Tcl based tools but does not
   develop new code.  Its workspace contains the files required for
   the tasks at hand.

 > The border between the roles of P/A Developer and P/A User blurs if
   the tool being used allows one to customize/program/extend it in
   Tcl.

 1. Repository manager

 > This role handles the management of all types of ''repositories''.
   This role is not part of the development process ''per se'' and has
   no direct actions for with regards to distributions, packages,
   sources, etc.

 > Repository managers are responsible for keeping the system up and
   running, doing adequate backups, supporting mirrors, providing
   browsing and download capabilities, providing confidence that
   updates to items in the repository are being done by the approved
   person or persons, etc.

 > The role is related to ''System administrator'', but not the same.
   It was split out of that role because a ''System-Administrator'' is
   usually internal to an organization whereas a repository and its
   management can be provided by an entity external to the
   organization.

 1. System administrator

 > A system administrator manages

 > * one or more ''installations'' of the Tcl core and additional
     packages.  Each installation may be configured differently (Tcl
     version, installed packages, platform, ...).

 > * Installed packages are taken either from a ''distribution
     repository'' or directly from a built package.  The latter has to
     be done in coordination with a ''P/A Builder''.

 > Her responsibilities include

 > * the creation of empty installations, 

 > * the destruction of installations,

 > * the addition and removal of packages to/from an existing
     installation.

The three P/A roles are central to the development process and bound
together in a tight loop of information flowing between them.  The
other three roles handle the support structure without which the other
roles would be unable to communicate and collaborate.

#image:78pa_cycle

Examples:

 * Larry Virden is ''System-Administrator'', ''P/A Builder'' and ''P/A
   User'' for his organization.

 * I (the author of this TIP) am all roles, on my system at home.

 * ActiveState is ''Repository Manager'' for the Perl community and
   plans to become one for the Tcl community.

 * SourceForge is a combination of ''Repository Manager'' and
   ''Catalog Manager''.

 * Most people with a windows machine at home are
   ''System-Administration'' and ''P/A User'' for this machine.

~ Visual Representation

The following drawings are a visual adjunct to the terms in the last
sections to aid in the understanding of the terms and their relations.

Legend:

 * Blue rounded boxes - Areas of responsibility for roles.  The
   responsible role is written in gold text inside of the box.

 * White rounded boxes with a black border - Data, like packages,
   distributions, etc.

 * White boxes with a red border - Actions on data.

#image:78tea_terms_relations_1 Roles, Data and Actions

#image:78tea_terms_relations_2 Relationships Between Data Entities

~ Copyright  

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|
|




|

|
|








|







|
|
|




|




|
|



|
|

|




|



|



|
|



|


|




|



|



|


|

|

|

|

|

|

|




|



|

|


|

|

|


|



|

|

|

|

|

|


|
|

|

|





|



|

|

|


|

|




|

|

|

|

|

|



|

|




|
|


|

|


|


|
|



|



|


|



|
|




|




|



|
|


|



|



|


|





|
|


|

|

|

|

|

|

|




|
|



|

|


|



|

|

|

|

|



|



|

|
|
|



|
|

|















|


|

|



|

|
|


|
|


|


|


|
|

|



|
|
|

|



|


|
|

|





|



|





|
|



|





|
|






|

|
|
|

|
|
|

|

|

|

|







|



|
|

|

|


|
|


|

|














|

|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484

# TIP 78: TEA 2.0 Definitions

	Author:         Andreas Kupries <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	State:          Draft
	Type:           Informative
	Vote:           Pending
	Created:        15-Dec-2001
	Post-History:   
-----

# Abstract

This document is an informational TIP providing definitions for
commonly used terms \(like package, extension, core, distribution,
etc.\) to make future communication among people in the community
easier.  It is recommended that future and past documents specifying
details inside of the greater context of TEA refer to this document to
ensure a consistent usage of terms.

# Background

This document is an adjunct to the [TIP <<vision>>].  _\(DKF - Is
this meant to be a reference to [[34]](34.md)?  Edit to such if so...\)_

To facilitate the specification and adoption of clearly defined
interfaces to various activities and technologies it specifies a
number of terms used by the community at large to create a greater
unity and coherence in the usage of these terms.  In other words, by
creating generally accepted definitions for important terms the risk
of misunderstanding each other is reduced.

# Specification of Technical Terms

This section specifies a number of important technical terms in
alphabetical order.  Terms used inside of a specification are
highlighted.

 * Application

	 > An entity implementing some functionality required by a _P/A
   User_ \(see section _Roles_\) to perform his work.  Consists of
   one more files.  May make use of _packages_ to implement its
   functionality.

 * Archive

	 > Encapsulation of a _distribution_ in a single file.  Well-known
   formats for archives are tar, gzipped tar, bzipped tar, and zip.

 * Binary generation

	 > The process of wrapping up a built package into a binary
   _distribution_.  See _building_ too.

 * Building

	 > The process of _configuring_ and _transforming_ a source
   _distribution_ into a set of files which can be either
   immediately installed on the site which built them or wrapped into
   a binary _distribution_ for shipment to other sites.  This also
   includes the execution of a test-suite coming with the package.

 * Bundle

	 > A _distribution_ encapsulating more than one _package_.

 * Catalog

	 > A catalog is a site providing an index of the packages.

 * Configuration

	 > The process of customizing a source distribution for a particular
   architecture and/or site.  A part of _Building_.

 * Conflict

	 > Two or more packages are said to be in conflict if the usage of one of them
   excludes the usage of the others.

	 > In a _strong conflict_ installing one of the packages disallows
   even the installation of the others.

 * Core

	 > A shorthand for _Tcl core_.

 * Core distribution.

	 > See _Tcl core distribution_.

 * Dependency

	 > A relationship between packages.  A package X is said dependent on
   another package Y if said package Y is required to allow X to work.

	 > There are several types of dependencies:

	 > \* Build-time dependency

	 > > Y is required to allow X to be build.

	 > \* Run-time dependency

	 > > Y is required to allow the usage of an installed X.

	 > \* Optional dependency

	 > > Y can be used by X \(usually for improved performance\) but is not
     required for building or use.

 * Distribution

	 > An encapsulation of one or more _packages_ for transport between
   places, machines, organizations, and people.  Several types of
   distributions are possible, explained below.

	 > 1. binary

	 > > A binary distribution is in a state and format allowing the
     installation of the contained packages on a particular platform.

	 > > It contains at least all the files

	 > > \* implementing the functionality of the distributed packages and

	 > > \* required to allow the package management of the Tcl core to
       handle the packages.

	 > > A binary distribution usually contains just the files for a
     single architecture.  This is not a explicit requirement however.
     In other words, a binary distribution is allowed to contain the
     files for several architectures.  Such a binary distribution will
     be called a _fat binary distribution_.

	 > > We distinguish between three sub-types:

	 > > \* installable

	 > > > This is the minimal binary distribution we spoke of before.

	 > > \* auto-installable

	 > > > Like _installable**, but additionally contains an application
       whose execution will perform all the steps which are necessary
       to install the contained packages at a site.  The installation
       to add the packages to \(and thus the location of the installed
       packages\) can be freely chosen by the caller of the executable.

	 > > \* auto-image

	 > > > Like _auto-installable_, but the final location of the
       packages is hard-wired into the distribution.  This means that
       a site using auto-images is restricted to one installation per
       architecture for which files are contained in the binary
       distribution.

	 > > > Some of the existing archive formats restrict their contained
       distributions to this type.  Examples of such archive formats
       are

	 > > > \* RPM \(RedHat Package Manager\)

	 > > > \* DEB \(DEBian Linux package format\)

	 > > See [TIP 55] for the specification of a proposed layout for
     binary distributions.

	 > 1. bundle

	 > > A distribution which either contains the distributions of more
     than one package or a list of references to packages.  The
     references are done by specifying the name and version of the
     packages contained in the bundle.

	 > 1. buildable

	 > > See _source_.

	 > 1. compileable

	 > > See _source_.

	 > 1. raw

	 > > A raw distribution is the most fundamental distribution.  Its
     format is nearly completely unspecified.  Its contents are
     straight from a source repository.  The process of converting a
     raw distribution into a source distribution is called
     _Preparation_.

	 > > Because of the unformatted nature of a raw distribution the
     commands for its conversion into a source distribution have to be
     part of it.  This is the only part of a raw distribution which
     can and has to be specified.

	 > > Example: The execution of _autoconf_ to generate a
     _configure_ script from its _configure.in_ file can be a
     single step in a complex preparation.

	 > 1. source

	 > > A source distribution is in a format and state where tools can be
     used to build its contents.

	 > > The format needs further specification but for now we can assume
     that it is governed by the current TEA specification.

	 > > Alternate name for this type of distribution are _compileable_
     and _buildable_.

 * Distribution repository

	 > See _repository_

 * Extension

	 > Alternate name for a _package_, generally used for packages
   requiring compilation to become functional.

	 > This term is _deprecated_.

 * Installation

	 > A special type of _distribution repository, binary_ \(see
   _repository_\) containing all _packages_ which were installed on
   a site.  A site may host several installations differing in version
   and/or configuration of Tcl, and/or the platform Tcl was built for,
   etc.

	 > Currently difficult to do but in the future it should made be
   possible for an installation to refer and use another installation,
   provided both are configured identically.  This allows a site to
   build a hierarchy of installations from the most general containing
   the common packages down to installations associated with one or
   more _P/A Developers_.

 * Installing

	 > The process of unpacking a binary distribution and adding the
   contained packages to an _installation_.  The latter may include
   moving files to their proper places.

	 > Also the process of adding a built package to an _installation_.

 * Manifest

	 > A file detailing the files making up a particular package.

 * Package

	 > A collection of files providing additional functionality to a user
   of a Tcl interpreter when loaded into said interpreter.

	 > Some files in a package implement the provided functionality
   whereas other files contain meta-information required by the
   package management of Tcl to be able to use the package.

 * Preparation

	 > The process of converting a raw _distribution_ into a source
   _distribution_ suitable as input to _building_.  This includes
   actions like:

	 > \* Retrieval of sources from a source repository

	 > \* Creating a _configure_ file from its _configure.in_.

	 > \* Creating the distributed documentation from internal sources.

	 > \* Removal of internal files containing notes, scratch info and the like.

	 > \* Inserting version information into files.

	 > \* ...

	 > The tool _makedist_ \(which I wrote\) is in my mind when thinking
   about this step.

 * Raw retrieval

	 > The process of retrieving a raw _distribution_ from a _source
   repository_.

 * Repository

	 > General term with two possible meanings.

	 > 1. A collection of _archives_.  The exact term for this type of
     repository is "distribution repository".

	 > > If a distribution repository is restricted to one type of
     distributions this type can be added to the term as further
     specification of the type of repository.  Thus

	 > > \* _distribution repository, binary_, or

	 > > \* _distribution repository, source_.

	 > 2. A collection of directories, developer files and control files
      containing version control information.  The exact term for this
      type of repository is _source repository_.

	 > > A repository can either be internal to an organization or public.

 * Source repository

	 > See _repository_

 * Tcl core

	 > The most fundamental part in the Tcl world; the interpreter engine
   and the builtin commands coming with it.  These are all commands
   and procedures reported by _info commands_ for a _tclsh_ which
   was started with an empty _.tclshrc_ file and after sourcing all
   _.tcl_ files in the directory returned by _info library_.

 * Tcl core distribution

	 > The most fundamental distribution there is.  Contains the _Tcl
   core_ and a number of packages.

# Roles

The terms in the preceding section specified both passive data
structures and actions upon them.  This section specifies the possible
actors, i.e. entities which perform one or more of these actions.

To make the specification easier, related actions are grouped into
roles of behavior.  The mapping from roles to actual actors,
i.e. people and organizations is n:m.  On other words, one actor may
have several roles, either at once or changing over time and one role
can be held by several distinct actors.

Examples are given at the end of this section.

 1. Catalog manager

	 > A catalog manager handles one or more catalogs.  He is responsible
   for

	 > \* the final name arbitration for packages with conflicting names

	 > \* and the categorization of the packages indexed by the catalog.

 1. P/A Builder

	 > A package and/or application builder is a person and/or organization

	 > \* who retrieves raw distributions from source repositories and \(in
     a sequence of several steps\) generates binary distributions from
     them.

	 > \* or who retrieves source distributions from distribution
     repositories and \(in a sequence of several steps\) generates
     binary distributions from them.

	 > \* uploads the generated binary distributions into one or more
     distribution repositories.

	 > \* uploads the generated source distributions into one or more
     distribution repositories.

	 > The intermediate steps performed by a builder are _Preparation_,
   _Building_, and _Binary generation_.

	 > If _System administrator_ and _P/A Builder_ coordinate with each other
   it is also possible to install a package directly from the built
   package.

	 > _NOTE:_ Think about splitting P/A Builder into two roles; one for
   the preparation of source _distributions_ and a second role for
   the generation of binary _distributions_.

		         TODO Find some nice names for the split roles.

 1. P/A Developer

	 > A developer is a _P/A User_ whose tasks include the creation of
   new packages and/or applications.  A workspace contains the raw
   sources of these new packages and applications.  For posterity and
   version control it is kept synchronized with one or more _source
   repositories_.

	 > During development, at least one installation has to be accessible,
   containing the initial packages, the new packages and the
   applications built upon the packages.

 1. P/A User

	 > A person or organization which uses Tcl based tools but does not
   develop new code.  Its workspace contains the files required for
   the tasks at hand.

	 > The border between the roles of P/A Developer and P/A User blurs if
   the tool being used allows one to customize/program/extend it in
   Tcl.

 1. Repository manager

	 > This role handles the management of all types of _repositories_.
   This role is not part of the development process _per se_ and has
   no direct actions for with regards to distributions, packages,
   sources, etc.

	 > Repository managers are responsible for keeping the system up and
   running, doing adequate backups, supporting mirrors, providing
   browsing and download capabilities, providing confidence that
   updates to items in the repository are being done by the approved
   person or persons, etc.

	 > The role is related to _System administrator_, but not the same.
   It was split out of that role because a _System-Administrator_ is
   usually internal to an organization whereas a repository and its
   management can be provided by an entity external to the
   organization.

 1. System administrator

	 > A system administrator manages

	 > \* one or more _installations_ of the Tcl core and additional
     packages.  Each installation may be configured differently \(Tcl
     version, installed packages, platform, ...\).

	 > \* Installed packages are taken either from a _distribution
     repository_ or directly from a built package.  The latter has to
     be done in coordination with a _P/A Builder_.

	 > Her responsibilities include

	 > \* the creation of empty installations, 

	 > \* the destruction of installations,

	 > \* the addition and removal of packages to/from an existing
     installation.

The three P/A roles are central to the development process and bound
together in a tight loop of information flowing between them.  The
other three roles handle the support structure without which the other
roles would be unable to communicate and collaborate.

![](../assets/78pa_cycle.gif)

Examples:

 * Larry Virden is _System-Administrator_, _P/A Builder_ and _P/A
   User_ for his organization.

 * I \(the author of this TIP\) am all roles, on my system at home.

 * ActiveState is _Repository Manager_ for the Perl community and
   plans to become one for the Tcl community.

 * SourceForge is a combination of _Repository Manager_ and
   _Catalog Manager_.

 * Most people with a windows machine at home are
   _System-Administration_ and _P/A User_ for this machine.

# Visual Representation

The following drawings are a visual adjunct to the terms in the last
sections to aid in the understanding of the terms and their relations.

Legend:

 * Blue rounded boxes - Areas of responsibility for roles.  The
   responsible role is written in gold text inside of the box.

 * White rounded boxes with a black border - Data, like packages,
   distributions, etc.

 * White boxes with a red border - Actions on data.

![Roles, Data and Actions](../assets/78tea_terms_relations_1.gif)

![Relationships Between Data Entities](../assets/78tea_terms_relations_2.gif)

# Copyright  

This document has been placed in the public domain.

Name change from tip/79.tip to tip/79.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

TIP:            79
Title:          Add Deletion Callback to Tcl_CreateObjTrace
Version:        $Revision: 1.7 $
Author:         Kevin Kenny <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        03-Jan-2002
Post-History:   
Discussions-To: news:comp.lang.tcl
Keywords:       trace,Tcl_Obj
Tcl-Version:    8.4


~ Abstract

This document is a correction to the ''Tcl_CreateObjTrace'' API from
[32].  It addresses a deficiency that the API provides no deletion
callback for its client data.

~ Rationale

In developing a reference implementation for the changes described in
[32], the author of this TIP discovered an anomaly in the proposed API
for ''Tcl_CreateObjTrace.''  While the function accepts a
''ClientData'' parameter, it provides no deletion callback for the
client data, making it difficult to clean up the client data if
''Tcl_DeleteTrace'' is called from a point in the code where the
client data is not readily available.  (The usual pattern in the Tcl
library is to provide a deletion callback wherever client data is
passed to the Tcl interpreter; ''Tcl_CreateObjCommand'' is an example.

~ Specification

The ''Tcl_CreateObjTrace'' function proposed in [32] shall be changed
to the following:

| Tcl_Trace Tcl_CreateObjTrace ( Tcl_Interp*                interp,
|                                int                        level, 
|                                int                        flags,
|                                Tcl_CmdObjTraceProc*       objProc,
|                                ClientData                 clientData,
|                                Tcl_CmdObjTraceDeleteProc* deleteProc );

The ''Tcl_CreateObjTrace'' function adds a trace to the Tcl evaluator.
The ''interp'' argument is the Tcl interpreter for which tracing is
being requested.  The ''level'' argument is the maximum depth of
recursive calls; when the execution depth of the interpreter exceeds
this number, the trace callback does not execute.  The ''objProc''
argument is the callback procedure to execute each time a Tcl command
is evaluated; it is expected to have arguments and result type that
match ''Tcl_CmdObjTraceProc'' below.  The ''clientData'' argument is
client data to pass to the ''objProc'' callback.  The ''deleteProc''
argument specifies a function to call when the trace is removed by a
call to ''Tcl_DeleteTrace.''  This parameter may be a null pointer if
no deletion callback is desired.  Finally, the ''flags'' argument
gives flags that control the tracing.  Initially, the only flag
supported will be ''TCL_ALLOW_INLINE_COMPILE''.  If this flag is set,
the bytecode compiler is permitted to compile in-line code for the Tcl
built-in commands; any command that has been compiled in-line will not
be traced.

The trace token returned from ''Tcl_CreateObjTrace'' may be passed as
a parameter to ''Tcl_DeleteTrace'', which arranges to cancel the
tracing.  If a non-empty ''deleteProc'' argument was supplied to
''Tcl_CreateObjTrace'', it is called at this time.  After
''Tcl_DeleteTrace'' returns, no further calls to the trace procedure
will be made, and the trace token must not be used further in the
calling program.

The ''Tcl_CmdObjTraceProc'' will have the following type signature.

|    typedef int Tcl_CmdObjTraceProc( ClientData     clientData,
|                                     Tcl_Interp*    interp,
|                                     int            level,
|                                     CONST char*    command,
|                                     Tcl_Command    commandInfo,
|                                     int            objc,
|                                     Tcl_Obj *CONST objv[] );

The ''clientData'' parameter is the client data that was passed to
''Tcl_CreateObjTrace''.  The ''interp'' parameter designates a Tcl
interpreter.  The ''level'' parameter specifies the execution level.
The ''command'' parameter gives the raw UTF-8 text of the command
being evaluated, before any substitutions have been performed.  The
''commandInfo'' parameter is an opaque ''Tcl_Command'' object that
gives information about the command.  The ''objc'' and ''objv''
parameters are the command name and parameter vector after
substitution.

The trace procedure is expected to return a standard Tcl status
return.  If it returns ''TCL_OK'', the command is evaluated normally.
If it returns ''TCL_ERROR'', evaluation of the command does not take
place.  The interpreter result is expected to contain an error
message.  If it returns any other status, such as ''TCL_BREAK'',
''TCL_CONTINUE'' or ''TCL_RETURN'', it is treated as if the command
had done so.

The ''Tcl_CmdObjTraceDeleteProc'' will have the following type
signature.

|    typedef void Tcl_CmdObjTraceDeleteProc( ClientData clientData );

The ''clientData'' parameter is the client data that was originally
passed into ''Tcl_CreateObjTrace''.

~ Copyright

Copyright � 2002 by Kevin B. Kenny.  Distribution in whole or part,
with or without annotations, is unlimited.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|
|


|


|
|
|

|
|

|

|

|


|
|
|
|
|
|

|
|
|

|


|
|

|
|

|




|
|
|
|
|



|

|
|
|
|
|
|
|

|
|
|
|

|
|




|
|

|
|


|


|

|
|

|

|

>

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

# TIP 79: Add Deletion Callback to Tcl_CreateObjTrace

	Author:         Kevin Kenny <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        03-Jan-2002
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Keywords:       trace,Tcl_Obj
	Tcl-Version:    8.4
-----

# Abstract

This document is a correction to the _Tcl\_CreateObjTrace_ API from
[[32]](32.md).  It addresses a deficiency that the API provides no deletion
callback for its client data.

# Rationale

In developing a reference implementation for the changes described in
[[32]](32.md), the author of this TIP discovered an anomaly in the proposed API
for _Tcl\_CreateObjTrace._  While the function accepts a
_ClientData_ parameter, it provides no deletion callback for the
client data, making it difficult to clean up the client data if
_Tcl\_DeleteTrace_ is called from a point in the code where the
client data is not readily available.  \(The usual pattern in the Tcl
library is to provide a deletion callback wherever client data is
passed to the Tcl interpreter; _Tcl\_CreateObjCommand_ is an example.

# Specification

The _Tcl\_CreateObjTrace_ function proposed in [[32]](32.md) shall be changed
to the following:

	 Tcl_Trace Tcl_CreateObjTrace ( Tcl_Interp*                interp,
	                                int                        level, 
	                                int                        flags,
	                                Tcl_CmdObjTraceProc*       objProc,
	                                ClientData                 clientData,
	                                Tcl_CmdObjTraceDeleteProc* deleteProc );

The _Tcl\_CreateObjTrace_ function adds a trace to the Tcl evaluator.
The _interp_ argument is the Tcl interpreter for which tracing is
being requested.  The _level_ argument is the maximum depth of
recursive calls; when the execution depth of the interpreter exceeds
this number, the trace callback does not execute.  The _objProc_
argument is the callback procedure to execute each time a Tcl command
is evaluated; it is expected to have arguments and result type that
match _Tcl\_CmdObjTraceProc_ below.  The _clientData_ argument is
client data to pass to the _objProc_ callback.  The _deleteProc_
argument specifies a function to call when the trace is removed by a
call to _Tcl\_DeleteTrace._  This parameter may be a null pointer if
no deletion callback is desired.  Finally, the _flags_ argument
gives flags that control the tracing.  Initially, the only flag
supported will be _TCL\_ALLOW\_INLINE\_COMPILE_.  If this flag is set,
the bytecode compiler is permitted to compile in-line code for the Tcl
built-in commands; any command that has been compiled in-line will not
be traced.

The trace token returned from _Tcl\_CreateObjTrace_ may be passed as
a parameter to _Tcl\_DeleteTrace_, which arranges to cancel the
tracing.  If a non-empty _deleteProc_ argument was supplied to
_Tcl\_CreateObjTrace_, it is called at this time.  After
_Tcl\_DeleteTrace_ returns, no further calls to the trace procedure
will be made, and the trace token must not be used further in the
calling program.

The _Tcl\_CmdObjTraceProc_ will have the following type signature.

	    typedef int Tcl_CmdObjTraceProc( ClientData     clientData,
	                                     Tcl_Interp*    interp,
	                                     int            level,
	                                     CONST char*    command,
	                                     Tcl_Command    commandInfo,
	                                     int            objc,
	                                     Tcl_Obj *CONST objv[] );

The _clientData_ parameter is the client data that was passed to
_Tcl\_CreateObjTrace_.  The _interp_ parameter designates a Tcl
interpreter.  The _level_ parameter specifies the execution level.
The _command_ parameter gives the raw UTF-8 text of the command
being evaluated, before any substitutions have been performed.  The
_commandInfo_ parameter is an opaque _Tcl\_Command_ object that
gives information about the command.  The _objc_ and _objv_
parameters are the command name and parameter vector after
substitution.

The trace procedure is expected to return a standard Tcl status
return.  If it returns _TCL\_OK_, the command is evaluated normally.
If it returns _TCL\_ERROR_, evaluation of the command does not take
place.  The interpreter result is expected to contain an error
message.  If it returns any other status, such as _TCL\_BREAK_,
_TCL\_CONTINUE_ or _TCL\_RETURN_, it is treated as if the command
had done so.

The _Tcl\_CmdObjTraceDeleteProc_ will have the following type
signature.

	    typedef void Tcl_CmdObjTraceDeleteProc( ClientData clientData );

The _clientData_ parameter is the client data that was originally
passed into _Tcl\_CreateObjTrace_.

# Copyright

Copyright © 2002 by Kevin B. Kenny.  Distribution in whole or part,
with or without annotations, is unlimited.

Name change from tip/8.tip to tip/8.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

TIP:           8
Title:         Add Winico support to the wm command on windows
Version:       $Revision: 1.8 $
Author:        Vince Darley <[email protected]>
State:         Final
Type:          Project
Tcl-Version:   8.4.0
Vote:          Done
Created:       06-Nov-2000
Post-History:


~ Abstract

Add to ''wm'' the ability to do the windows-titlebar-icon manipulation
that the Winico extension currently provides, without the bugs noted
in that extension.

~ Proposal

Modify ''wm'' on Windows only to allow an optional ''-default'' argument.

|wm iconbitmap .winpath ?-default? filename

And to allow a file which is of valid windows-icon format to be
interpreted as such.  Any file which is not correctly interpreted
as an icon will be handled as before, by the ''bitmap'' code (which
will generally either do nothing, or throw an error, thus maintaining
backwards compatibility).

The ''-default'' argument, if given, will change not the icon of the
.winpath given, but rather the default icon for all windows in the
current application for which no specific icon as been set.

An implementation already exists, which fixes the basic "wrapper
window" problems and which has the above syntax.  The issues
surrounding reference counting of icons in use has also been addressed
in this patch so that icons no longer in use are released (the Winico
patch required manual deletion of icons).  This reference
implementation is available from
ftp://ftp.ucsd.edu/pub/alpha/tcl/tkWinWm.diff (documentation has been
separately patched, and can also be made available).

~ Rationale

There have been many requests on news:comp.lang.tcl for this ability
in the Tk core, and several bug reports filed against Winico, and this
ability has been placed on the Tk 8.4 roadmap.
http://purl.org/tcl/home/software/tcltk/roadmap.tml

The choice of ''wm iconbitmap'' is suggested, because ''wm
iconbitmap'' currently doesn't appear to do anything on Windows, yet
is the obvious choice for the user trying to set the window's icon
(e.g. many posts on news:comp.lang.tcl are actually asking why ''wm
iconbitmap'' doesn't do anything).

In the future we may wish to extend ''wm iconbitmap'' on all platforms
so that other image types can be accepted (e.g. .gif, .png).  This
proposal extends naturally to allow such future work.  The primary
changes required will be icon<->image conversion routines.

~ Alternatives

Fix the core so that Winico can work properly as an extension.

My implementation as shown that this would require a couple of
patches, and also the exporting of an additional obscure function into
Tk's stub table (a function which would ensure that Tk's window
manager is completely initialised).  It would also not help the users
posting to news:comp.lang.tcl asking "why doesn't wm iconbitmap do
anything?"

~ Objections

''This is platform specific and should go in an extension''

See ''Alternatives'' above, also see the ''future suggestion'' above
in which this kind of code can be usefully extended in a
cross-platform way.

''The -default flag is weird, and it means we ignore the window name''

I agree, but please suggest a better alternative rather than just
moaning.  The command with the -default flag is in my opinion more
useful than the command without (for example it makes sure that Tk's
built-in dialogs have the icon of your application).  An alternative
might be to use ''wm iconbitmap -default filename'', but that involves
more significant modifications of the semantics of ''wm''.  It might,
however, be a good idea.

''wm iconbitmap will still do nothing when given a bitmap''

Yes, but there's that backwards compatibility issue.  This should be
properly documented with pointers to the use of valid icon file
formats.  When or if proper support is added to Tk for .gif, .png or
even Tk images as icons, this bug can be fixed.  The purpose of this
TIP is not to fix that bug, but to provide a better solution.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|



|

|

|



|

|

|






|
|

|
|

|




|

|
|

|
|

|
|



|





|
|



|

|

|



|



|
|
|
|


|







|


>

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

# TIP 8: Add Winico support to the wm command on windows

	Author:        Vince Darley <[email protected]>
	State:         Final
	Type:          Project
	Tcl-Version:   8.4.0
	Vote:          Done
	Created:       06-Nov-2000
	Post-History:
-----

# Abstract

Add to _wm_ the ability to do the windows-titlebar-icon manipulation
that the Winico extension currently provides, without the bugs noted
in that extension.

# Proposal

Modify _wm_ on Windows only to allow an optional _-default_ argument.

	wm iconbitmap .winpath ?-default? filename

And to allow a file which is of valid windows-icon format to be
interpreted as such.  Any file which is not correctly interpreted
as an icon will be handled as before, by the _bitmap_ code \(which
will generally either do nothing, or throw an error, thus maintaining
backwards compatibility\).

The _-default_ argument, if given, will change not the icon of the
.winpath given, but rather the default icon for all windows in the
current application for which no specific icon as been set.

An implementation already exists, which fixes the basic "wrapper
window" problems and which has the above syntax.  The issues
surrounding reference counting of icons in use has also been addressed
in this patch so that icons no longer in use are released \(the Winico
patch required manual deletion of icons\).  This reference
implementation is available from
ftp://ftp.ucsd.edu/pub/alpha/tcl/tkWinWm.diff \(documentation has been
separately patched, and can also be made available\).

# Rationale

There have been many requests on news:comp.lang.tcl for this ability
in the Tk core, and several bug reports filed against Winico, and this
ability has been placed on the Tk 8.4 roadmap.
<http://purl.org/tcl/home/software/tcltk/roadmap.tml>

The choice of _wm iconbitmap_ is suggested, because _wm
iconbitmap_ currently doesn't appear to do anything on Windows, yet
is the obvious choice for the user trying to set the window's icon
\(e.g. many posts on news:comp.lang.tcl are actually asking why _wm
iconbitmap_ doesn't do anything\).

In the future we may wish to extend _wm iconbitmap_ on all platforms
so that other image types can be accepted \(e.g. .gif, .png\).  This
proposal extends naturally to allow such future work.  The primary
changes required will be icon<->image conversion routines.

# Alternatives

Fix the core so that Winico can work properly as an extension.

My implementation as shown that this would require a couple of
patches, and also the exporting of an additional obscure function into
Tk's stub table \(a function which would ensure that Tk's window
manager is completely initialised\).  It would also not help the users
posting to news:comp.lang.tcl asking "why doesn't wm iconbitmap do
anything?"

# Objections

_This is platform specific and should go in an extension_

See _Alternatives_ above, also see the _future suggestion_ above
in which this kind of code can be usefully extended in a
cross-platform way.

_The -default flag is weird, and it means we ignore the window name_

I agree, but please suggest a better alternative rather than just
moaning.  The command with the -default flag is in my opinion more
useful than the command without \(for example it makes sure that Tk's
built-in dialogs have the icon of your application\).  An alternative
might be to use _wm iconbitmap -default filename_, but that involves
more significant modifications of the semantics of _wm_.  It might,
however, be a good idea.

_wm iconbitmap will still do nothing when given a bitmap_

Yes, but there's that backwards compatibility issue.  This should be
properly documented with pointers to the use of valid icon file
formats.  When or if proper support is added to Tk for .gif, .png or
even Tk images as icons, this bug can be fixed.  The purpose of this
TIP is not to fix that bug, but to provide a better solution.

# Copyright

This document has been placed in the public domain.

Name change from tip/80.tip to tip/80.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
136

137
138
139
140
141

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191


192
193
194
195
196
197
198
199
200

201
202
203
204
205
206
207
208
209

210
211
212
213
214
215
216
217
218
219
220
221

222
223
224

225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241

242
243
244
245
246
247

248
249

250
251
252

253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276

277
278
279
280
281

282
283
284
285
286

287
288
289
290
291
292
293

294
295

296
297
298
299
300
301

302
303
304
305
306
307
308

309
310
311


312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332

333
334
335
336
337
338
339
340



341
342
343
344
345
346
347
348
349
350
351
352
353

354
355

356
357
358
359
360
361

362
363
364
365
366
367

368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391

392
393
394
395
396

397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412


413
414
415
416
417
418
419
420
421
422




423
424
425
426
427
428
429



430
431
432
433

434
435


436










































437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455

456
457
458
459
460
461
462


463
464

465
466
467

468
469
470
471
472
473
474


475
476

477
478
479

480
481
482
483
484
485
486

487
488

489
490

491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526

TIP:            80
Title:          Additional Options for 'lsearch'
Version:        $Revision: 1.10 $
Author:         Tom Wilkason <[email protected]>
Author:         Tom Wilkason <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        02-Jan-2002
Post-History:   
Discussions-To: news:comp.lang.tcl
Tcl-Version:    8.4


~ Abstract

This TIP proposes additional options for the ''lsearch'' command to
return and work with all matching items in the return rather than the
first matching item. Additional options are also added.

~ Rationale

The ''lsearch'' function works well for finding the first item in a
list that matches a pattern.  However it is often useful to find all
of the items in the list that match a pattern.  This TIP proposes
adding options to return the entire list of matches.  With this
capability, additional options are proposed to return the data rather
than the indices (since you often want to work the the data anyway),
and to add an option to return the logical exclusion of the matching
items (i.e. those that don't match the search pattern).

~ Specification

I propose the following options be added to ''lsearch'':

Option: ''-start index''

 > Initiates the list search starting at ''index'', which can be
   any valid list index (such as 0 , end , end-1 ...) 

Option: ''-all''

 > Returns a list of all indices that match the search condition
   (rather than the first one).  The indices are returned low to high
   order.  For a no match condition, a {} (empty list) is returned.
   If the the ''-all'' or ''-inline'' switches are not specified, a
   -1 is returned for a no match condition just as is done now.

Option: ''-inline''

 > Returns a single item (or a list of items for ''-all'') of the data
   that matches the search condition rather than the index (or
   indices).  An empty result or empty list (''-all'') is returned for
   a no match condition.  The data is returned in original list order.
   This option is useful when you want to iterate over the returned
   data anyway.  e.g.

|    foreach item [lsearch -all -inline -glob $someList *stuff] {
|       # deal with item
|    }


Option: ''-not''

 > Negates the sense of the search condition (i.e. what doesn't
   match).  When used with the ''-inline'' or ''-all'' options, the
   return set will be the items that do match.  If all items match
   then a {} is returned.  Without the ''-all'' option, the first item
   in the list that does not match will be returned.

These can be combined as needed and yield some powerful capabilities
when iterating over sub-lists (esp. with the new ''lset'' command).

~ Reference Implementation

Changes to the ''Tcl_LsearchObjCmd'' command in ''generic/tclCmdIL.c''
are needed along with documentation and test code.  The changes to the
8.4 head version of ''tclCmdIL.c'' are available below.

|/*
| *----------------------------------------------------------------------
| *

| * Tcl_LsearchObjCmd --
| *

| *      This procedure is invoked to process the "lsearch" Tcl command.
| *      See the user documentation for details on what it does.
| *

| * Results:
| *      A standard Tcl result.
| *

| * Side effects:
| *      See the user documentation.
| *

| *----------------------------------------------------------------------
| */
|
|int
|Tcl_LsearchObjCmd(clientData, interp, objc, objv)
|    ClientData clientData;      /* Not used. */
|    Tcl_Interp *interp;         /* Current interpreter. */
|    int objc;                   /* Number of arguments. */
|    Tcl_Obj *CONST objv[];      /* Argument values. */
|{

|    char *bytes, *patternBytes;
|    int i, match, mode, index, result, listc, length, elemLen;
|    int useStart=-1, offset, allData=0, returnInline=0;
|    int dataType, isIncreasing, lower, upper, patInt, objInt, notMatch=0;
|    double patDouble, objDouble;
|    Tcl_Obj *patObj, **listv, *listPtr, *startPtr = NULL;
|    static CONST char *options[] = {
|        "-all", "-ascii", "-decreasing", "-dictionary",
|        "-exact", "-glob", "-increasing", "-inline",
|        "-integer", "-not", "-real", "-regexp",
|        "-sorted", "-start", NULL
|    };
|    enum options {
|        LSEARCH_ALL, LSEARCH_ASCII, LSEARCH_DECREASING, LSEARCH_DICTIONARY,
|        LSEARCH_EXACT, LSEARCH_GLOB, LSEARCH_INCREASING, LSEARCH_INLINE,
|        LSEARCH_INTEGER, LSEARCH_NOT, LSEARCH_REAL, LSEARCH_REGEXP,
|        LSEARCH_SORTED, LSEARCH_START
|    };
|
|    enum datatypes {
|        ASCII, DICTIONARY, INTEGER, REAL
|    };
|
|    enum modes {
|        EXACT, GLOB, REGEXP, SORTED
|    };
|
|    mode = GLOB;
|    dataType = ASCII;
|    isIncreasing = 1;
|    /* Note: This counts options as possible list|patterns */
|    if (objc < 3) {
|        Tcl_WrongNumArgs(interp, 1, objv, "?options? list pattern");
|        return TCL_ERROR;
|    }

|    for (i = 1; i < objc-2; i++) {
|        if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, &index)
|                != TCL_OK) {
|            return TCL_ERROR;
|        }

|        switch ((enum options) index) {
|            case LSEARCH_ASCII:         /* -ascii */
|                dataType = ASCII;
|                break;
|            case LSEARCH_NOT:           /* -not */
|                notMatch = 1;
|                break;
|            case LSEARCH_ALL:           /* -all */
|                allData = 1;
|                listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
|                break;
|            case LSEARCH_INLINE:        /* -inline */
|                returnInline = 1;
|                break;
|            case LSEARCH_START:         /* -start index */
|                useStart = ++i;         /* Use next arg as offset index */
|                if (objc-i < 2) {
|                    Tcl_SetResult(interp,
|                            "missing argument to -start option", TCL_STATIC);
|                }

|                break;
|            case LSEARCH_DECREASING:    /* -decreasing */
|                isIncreasing = 0;
|                break;
|            case LSEARCH_DICTIONARY:    /* -dictionary */
|                dataType = DICTIONARY;
|                break;
|            case LSEARCH_EXACT:         /* -exact */
|                mode = EXACT;
|                break;
|            case LSEARCH_INCREASING:    /* -increasing */
|                isIncreasing = 1;
|                break;
|            case LSEARCH_INTEGER:       /* -integer */
|                dataType = INTEGER;
|                break;
|            case LSEARCH_GLOB:          /* -glob */
|                mode = GLOB;
|                break;
|            case LSEARCH_REAL:          /* -real */
|                dataType = REAL;
|                break;
|            case LSEARCH_REGEXP:        /* -regexp */
|                mode = REGEXP;
|                break;
|            case LSEARCH_SORTED:        /* -sorted */
|                mode = SORTED;
|                break;
|        }
|    }


|     
|
|    /*
|     * -start option processing:
|     * Ensure we get a unique copy of command line arg for start index
|     */
|    if (useStart > 0) {
|        startPtr = Tcl_DuplicateObj(objv[useStart]);
|    }

|
|    /*
|     * Make sure the list argument is a list object and get its length and
|     * a pointer to its array of element pointers.
|     */
|    result = Tcl_ListObjGetInline(interp, objv[objc - 2], &listc, &listv);
|    if (result != TCL_OK) {
|        return result;
|    }

|    /*
|     * Retrieve user specified start offset.
|     */
|    if (useStart > 0) {
|        result = TclGetIntForIndex(interp, startPtr, /*end*/ listc-1, &offset);
|        Tcl_DecrRefCount(startPtr); /* free unneeded obj */
|
|        if (result != TCL_OK) {
|           return result;
|        } else if (offset < 0) {
|           offset = 0;
|        }

|    } else {
|       offset = 0;
|    }

|
|    /*
|     * Process the pattern
|     */
|    patObj = objv[objc - 1];
|    patternBytes = NULL;
|    if ((enum modes) mode == EXACT || (enum modes) mode == SORTED) {
|        switch ((enum datatypes) dataType) {
|            case ASCII:
|            case DICTIONARY:
|                patternBytes = Tcl_GetStringFromObj(patObj, &length);
|                break;
|            case INTEGER:
|                result = Tcl_GetIntFromObj(interp, patObj, &patInt);
|                if (result != TCL_OK) {
|                    return result;
|                }

|                break;
|            case REAL:
|                result = Tcl_GetDoubleFromObj(interp, patObj, &patDouble);
|                if (result != TCL_OK) {
|                    return result;
|                }

|                break;
|        }

|    } else {
|        patternBytes = Tcl_GetStringFromObj(patObj, &length);
|    }

|
|    /*
|     * Set default index value to -1, indicating failure; if we find the
|     * item in the course of our search, index will be set to the correct
|     * value.
|     */
|    index = -1;
|    match = 0;
|    if ((enum modes) mode == SORTED && allData == FALSE) {
|        /*
|         * If the data is sorted, we can do a more intelligent search.
|         * Note that there is no point in being smart when -all was
|         * specified; in that case, we have to look at all items anyway.
|         */
|        lower = offset-1 /*-1*/;
|        upper = listc;
|        while (lower + 1 != upper) {
|            i = (lower + upper)/2;
|            switch ((enum datatypes) dataType) {
|                case ASCII: {
|                    bytes = Tcl_GetString(listv[i]);
|                    match = strcmp(patternBytes, bytes);
|                    break;
|                }

|                case DICTIONARY: {
|                    bytes = Tcl_GetString(listv[i]);
|                    match = DictionaryCompare(patternBytes, bytes);
|                    break;
|                }

|                case INTEGER: {
|                    result = Tcl_GetIntFromObj(interp, listv[i], &objInt);
|                    if (result != TCL_OK) {
|                        return result;
|                    }

|                    if (patInt == objInt) {
|                        match = 0;
|                    } else if (patInt < objInt) {
|                        match = -1;
|                    } else {
|                        match = 1;
|                    }

|                    break;
|                }

|                case REAL: {
|                    result = Tcl_GetDoubleFromObj(interp, listv[i],
|                            &objDouble);
|                    if (result != TCL_OK) {
|                        return result;
|                    }

|                    if (patDouble == objDouble) {
|                        match = 0;
|                    } else if (patDouble < objDouble) {
|                        match = -1;
|                    } else {
|                        match = 1;
|                    }

|                    break;
|                }
|            }


|            if (match == 0) {
|                /*
|                 * Normally, binary search is written to stop when it
|                 * finds a match.  If there are duplicates of an element in
|                 * the list, our first match might not be the first occurance.
|                 * Consider:  0 0 0 1 1 1 2 2 2
|                 * To maintain consistancy with standard lsearch semantics,
|                 * we must find the leftmost occurance of the pattern in the
|                 * list.  Thus we don't just stop searching here.  This
|                 * variation means that a search always makes log n
|                 * comparisons (normal binary search might "get lucky" with
|                 * an early comparison).
|                 */
|                index = i;
|                upper = i;
|            } else if (match > 0) {
|                if (isIncreasing) {
|                    lower = i;
|                } else {
|                    upper = i;
|                }

|            } else {
|                if (isIncreasing) {
|                    upper = i;
|                } else {
|                    lower = i;
|                }
|            }
|        }



|    } else {
|        for (i = offset; i < listc; i++) {
|            match = 0;
|            switch ((enum modes) mode) {
|                case SORTED:
|                case EXACT: {
|                    switch ((enum datatypes) dataType) {
|                        case ASCII: {
|                            bytes = Tcl_GetStringFromObj(listv[i], &elemLen);
|                            if (length == elemLen) {
|                                match = (memcmp(bytes, patternBytes,
|                                        (size_t) length) == 0);
|                            }

|                            break;
|                        }

|                        case DICTIONARY: {
|                            bytes = Tcl_GetString(listv[i]);
|                            match =
|                                (DictionaryCompare(bytes, patternBytes) == 0);
|                            break;
|                        }

|                        case INTEGER: {
|                            result = Tcl_GetIntFromObj(interp, listv[i],
|                                    &objInt);
|                            if (result != TCL_OK) {
|                                return result;
|                            }

|                            match = (objInt == patInt);
|                            break;
|                        }
|                        case REAL: {
|                            result = Tcl_GetDoubleFromObj(interp, listv[i],
|                                    &objDouble);
|                            if (result != TCL_OK) {
|                                return result;
|                            }
|                            match = (objDouble == patDouble);
|                            break;
|                        }
|                    }
|                    break;
|                }
|                case GLOB: {
|                    match = Tcl_StringMatch(Tcl_GetString(listv[i]),
|                            patternBytes);
|                    break;
|                }
|                case REGEXP: {
|                    match = Tcl_RegExpMatchObj(interp, listv[i], patObj);
|                    if (match < 0) {
|                        return TCL_ERROR;

|                    }
|                    break;
|                }
|            }
|            /* Invert match condition for -not */

|            if (notMatch) {
|                match = (match != 0 ? 0 : 1);
|            }
|
|            /* Process the possible match for this element */
|            if (match != 0) {
|                if (allData) {
|                    if (returnInline) {
|                        /* Append data */
|                        Tcl_ListObjAppendElement(interp, listPtr,listv[i]);
|                    } else {
|                        /* Append index */
|                        Tcl_ListObjAppendElement(interp, listPtr,Tcl_NewIntObj(i));
|                    }
|                } else {
|                    index = i;


|                    break;
|                }
|            }
|        }
|    }
|    /*
|     * Return either a list (-all) or a single element
|     */
|    if (allData) {
|        Tcl_SetObjResult(interp,listPtr);




|    } else {
|        if (returnInline) {
|            if (index < 0) { /* Return a null */
|                Tcl_SetObjResult(interp,Tcl_NewObj());
|            } else {         /* Return one datum */
|                Tcl_SetObjResult(interp,listv[index]);
|            }



|        } else {
|            Tcl_SetIntObj(Tcl_GetObjResult(interp), index);
|        }
|    }

|    return TCL_OK;
|}













































~ Notes

The changes to ''lsearch'' are entirely backward compatible and do no
change the behaviour or performance of the command for existing
options.  Moreover, these changes should not impact any of the other
list changes in [22], [33] or [45].

~ Copyright

This document has been placed in the public domain.

~ Appendix

The benchmarks below denote the expected speed increase of using the
new options vs. tcl only implementations.  Your mileage may vary.

|##
|# performs a lsearch -all -inline -glob search
|#

|proc lsearch_dataGLOB {listData pattern} {
|    set result [list]
|    foreach item $listData {
|        if {[string match $pattern $item]} {
|            lappend result $item
|        }
|    }


|    return $result
|}

|##
|# performs a lsearch -all -inline -regexp search
|#

|proc lsearch_dataRE {listData pattern} {
|    set result [list]
|    foreach item $listData {
|        if {[regexp $pattern $item]} {
|            lappend result $item
|        }
|    }


|    return $result
|}

|##
|# performs a lsearch -all -glob search
|#

|proc lsearch_allGLOB {listData pattern} {
|    set result [list]
|    set count 0
|    foreach item $listData {
|        if {[string match $pattern $item]} {
|            lappend result $count
|        }

|        incr count
|    }

|    return $result
|}

|
|# Build a 2K list of data
|catch {unset LIST}
|time {lappend LIST someStuff} 1000
|time {lappend LIST otherStuff} 1000
|
|# Case with all data matching in a 2K list 2.8x speedup
|puts "#C implementation [time {lsearch -glob -all -inline $LIST *Stuff} 100]"
|#=> C implementation 3766 microseconds per iteration
|puts "#tcl implementation [time {lsearch_dataGLOB $LIST *Stuff} 100]"
|#=> tcl implementation 10815 microseconds per iteration
|
|# Case with all data matching but returning indicies 3X speed up
|puts "#C implementation [time {lsearch -glob -all $LIST *Stuff} 100]"
|#=> C implementation 4305 microseconds per iteration
|puts "#tcl implementation [time {lsearch_allGLOB $LIST *Stuff} 100]"
|#=> tcl implementation 13277 microseconds per iteration
|
|# Case with no matching data 8X speed up
|puts "#C implementation [time {lsearch -glob -all -inline $LIST none*} 100]"
|#=> C implementation 646 microseconds per iteration
|puts "#tcl implementation [time {lsearch_dataGLOB $LIST none*} 100]"
|#=> tcl implementation 5354 microseconds per iteration
|
|
|# Repeat with RE, note more time spent in RE engine 2X speedup
|puts "#C implementation [time {lsearch -regexp -all -inline $LIST Stuff} 100]"
|#=> C implementation 35260 microseconds per iteration
|puts "#tcl implementation [time {lsearch_dataRE $LIST Stuff} 100]"
|#=> tcl implementation 62292 microseconds per iteration
|
|# Case with no matching data 2X speedup
|puts "#C implementation [time {lsearch -regexp -all -inline $LIST none*} 100]"
|#=> C implementation 14815 microseconds per iteration
|puts "#tcl implementation [time {lsearch_dataRE $LIST none} 100]"
|#=> tcl implementation 30553 microseconds per iteration

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|



|

|




|

|

|

|

|

|
|

|


|
|
|


|

|
|
|




|
|
<
|
>
|

|
|

|



|

|

|

|

|
|
<
>
|
<
>
|
|
<
>
|
|
<
>
|
|
<
>
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
<
>
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
<
<
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
<
>
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
>
|
|
<
<
<
>
|
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
>
>
|
<
<
<
<
<
<
<
<
<
>
>
>
>
|
<
<
|
<
<
<
>
>
>
|
|
<
<
>
|
<
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

|


|

|



|




|
|
<
>
|
|
|
|
|
<
<
>
>
|
<
>
|
|
<
>
|
|
|
|
|
<
<
>
>
|
<
>
|
|
<
>
|
|
|
|
|
|
<
>
|
<
>
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>

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
136
137
138
139

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159

160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188


189
190
191
192
193
194
195
196
197
198

199
200
201
202
203
204
205
206
207

208
209
210
211
212
213
214
215
216
217
218
219

220
221
222

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239

240
241
242
243
244
245

246
247

248
249
250

251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274

275
276
277
278
279

280
281
282
283
284

285
286
287
288
289
290
291

292
293

294
295
296
297
298
299

300
301
302
303
304
305
306

307
308


309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330

331
332
333
334
335
336



337
338
339
340
341
342
343
344
345
346
347
348
349
350
351

352
353

354
355
356
357
358
359

360
361
362
363
364
365

366
367












368










369
370
371



372
373






374








375
376
377









378
379
380
381
382


383



384
385
386
387
388


389
390

391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453

454
455
456
457
458
459


460
461
462

463
464
465

466
467
468
469
470
471


472
473
474

475
476
477

478
479
480
481
482
483
484

485
486

487
488

489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526

# TIP 80: Additional Options for 'lsearch'

	Author:         Tom Wilkason <[email protected]>
	Author:         Tom Wilkason <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        02-Jan-2002
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Tcl-Version:    8.4
-----

# Abstract

This TIP proposes additional options for the _lsearch_ command to
return and work with all matching items in the return rather than the
first matching item. Additional options are also added.

# Rationale

The _lsearch_ function works well for finding the first item in a
list that matches a pattern.  However it is often useful to find all
of the items in the list that match a pattern.  This TIP proposes
adding options to return the entire list of matches.  With this
capability, additional options are proposed to return the data rather
than the indices \(since you often want to work the the data anyway\),
and to add an option to return the logical exclusion of the matching
items \(i.e. those that don't match the search pattern\).

# Specification

I propose the following options be added to _lsearch_:

Option: _-start index_

 > Initiates the list search starting at _index_, which can be
   any valid list index \(such as 0 , end , end-1 ...\) 

Option: _-all_

 > Returns a list of all indices that match the search condition
   \(rather than the first one\).  The indices are returned low to high
   order.  For a no match condition, a \{\} \(empty list\) is returned.
   If the the _-all_ or _-inline_ switches are not specified, a
   -1 is returned for a no match condition just as is done now.

Option: _-inline_

 > Returns a single item \(or a list of items for _-all_\) of the data
   that matches the search condition rather than the index \(or
   indices\).  An empty result or empty list \(_-all_\) is returned for
   a no match condition.  The data is returned in original list order.
   This option is useful when you want to iterate over the returned
   data anyway.  e.g.

	    foreach item [lsearch -all -inline -glob $someList *stuff] {
	       # deal with item

	    }

Option: _-not_

 > Negates the sense of the search condition \(i.e. what doesn't
   match\).  When used with the _-inline_ or _-all_ options, the
   return set will be the items that do match.  If all items match
   then a \{\} is returned.  Without the _-all_ option, the first item
   in the list that does not match will be returned.

These can be combined as needed and yield some powerful capabilities
when iterating over sub-lists \(esp. with the new _lset_ command\).

# Reference Implementation

Changes to the _Tcl\_LsearchObjCmd_ command in _generic/tclCmdIL.c_
are needed along with documentation and test code.  The changes to the
8.4 head version of _tclCmdIL.c_ are available below.

	/*
	 *----------------------------------------------------------------------

	 *
	 * Tcl_LsearchObjCmd --

	 *
	 *      This procedure is invoked to process the "lsearch" Tcl command.
	 *      See the user documentation for details on what it does.

	 *
	 * Results:
	 *      A standard Tcl result.

	 *
	 * Side effects:
	 *      See the user documentation.

	 *
	 *----------------------------------------------------------------------
	 */
	
	int
	Tcl_LsearchObjCmd(clientData, interp, objc, objv)
	    ClientData clientData;      /* Not used. */
	    Tcl_Interp *interp;         /* Current interpreter. */
	    int objc;                   /* Number of arguments. */
	    Tcl_Obj *CONST objv[];      /* Argument values. */

	{
	    char *bytes, *patternBytes;
	    int i, match, mode, index, result, listc, length, elemLen;
	    int useStart=-1, offset, allData=0, returnInline=0;
	    int dataType, isIncreasing, lower, upper, patInt, objInt, notMatch=0;
	    double patDouble, objDouble;
	    Tcl_Obj *patObj, **listv, *listPtr, *startPtr = NULL;
	    static CONST char *options[] = {
	        "-all", "-ascii", "-decreasing", "-dictionary",
	        "-exact", "-glob", "-increasing", "-inline",
	        "-integer", "-not", "-real", "-regexp",
	        "-sorted", "-start", NULL
	    };
	    enum options {
	        LSEARCH_ALL, LSEARCH_ASCII, LSEARCH_DECREASING, LSEARCH_DICTIONARY,
	        LSEARCH_EXACT, LSEARCH_GLOB, LSEARCH_INCREASING, LSEARCH_INLINE,
	        LSEARCH_INTEGER, LSEARCH_NOT, LSEARCH_REAL, LSEARCH_REGEXP,
	        LSEARCH_SORTED, LSEARCH_START
	    };
	
	    enum datatypes {
	        ASCII, DICTIONARY, INTEGER, REAL
	    };
	
	    enum modes {
	        EXACT, GLOB, REGEXP, SORTED
	    };
	
	    mode = GLOB;
	    dataType = ASCII;
	    isIncreasing = 1;
	    /* Note: This counts options as possible list|patterns */
	    if (objc < 3) {
	        Tcl_WrongNumArgs(interp, 1, objv, "?options? list pattern");
	        return TCL_ERROR;

	    }
	    for (i = 1; i < objc-2; i++) {
	        if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, &index)
	                != TCL_OK) {
	            return TCL_ERROR;

	        }
	        switch ((enum options) index) {
	            case LSEARCH_ASCII:         /* -ascii */
	                dataType = ASCII;
	                break;
	            case LSEARCH_NOT:           /* -not */
	                notMatch = 1;
	                break;
	            case LSEARCH_ALL:           /* -all */
	                allData = 1;
	                listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
	                break;
	            case LSEARCH_INLINE:        /* -inline */
	                returnInline = 1;
	                break;
	            case LSEARCH_START:         /* -start index */
	                useStart = ++i;         /* Use next arg as offset index */
	                if (objc-i < 2) {
	                    Tcl_SetResult(interp,
	                            "missing argument to -start option", TCL_STATIC);

	                }
	                break;
	            case LSEARCH_DECREASING:    /* -decreasing */
	                isIncreasing = 0;
	                break;
	            case LSEARCH_DICTIONARY:    /* -dictionary */
	                dataType = DICTIONARY;
	                break;
	            case LSEARCH_EXACT:         /* -exact */
	                mode = EXACT;
	                break;
	            case LSEARCH_INCREASING:    /* -increasing */
	                isIncreasing = 1;
	                break;
	            case LSEARCH_INTEGER:       /* -integer */
	                dataType = INTEGER;
	                break;
	            case LSEARCH_GLOB:          /* -glob */
	                mode = GLOB;
	                break;
	            case LSEARCH_REAL:          /* -real */
	                dataType = REAL;
	                break;
	            case LSEARCH_REGEXP:        /* -regexp */
	                mode = REGEXP;
	                break;
	            case LSEARCH_SORTED:        /* -sorted */
	                mode = SORTED;
	                break;


	        }
	    }
	     
	
	    /*
	     * -start option processing:
	     * Ensure we get a unique copy of command line arg for start index
	     */
	    if (useStart > 0) {
	        startPtr = Tcl_DuplicateObj(objv[useStart]);

	    }
	
	    /*
	     * Make sure the list argument is a list object and get its length and
	     * a pointer to its array of element pointers.
	     */
	    result = Tcl_ListObjGetInline(interp, objv[objc - 2], &listc, &listv);
	    if (result != TCL_OK) {
	        return result;

	    }
	    /*
	     * Retrieve user specified start offset.
	     */
	    if (useStart > 0) {
	        result = TclGetIntForIndex(interp, startPtr, /*end*/ listc-1, &offset);
	        Tcl_DecrRefCount(startPtr); /* free unneeded obj */
	
	        if (result != TCL_OK) {
	           return result;
	        } else if (offset < 0) {
	           offset = 0;

	        }
	    } else {
	       offset = 0;

	    }
	
	    /*
	     * Process the pattern
	     */
	    patObj = objv[objc - 1];
	    patternBytes = NULL;
	    if ((enum modes) mode == EXACT || (enum modes) mode == SORTED) {
	        switch ((enum datatypes) dataType) {
	            case ASCII:
	            case DICTIONARY:
	                patternBytes = Tcl_GetStringFromObj(patObj, &length);
	                break;
	            case INTEGER:
	                result = Tcl_GetIntFromObj(interp, patObj, &patInt);
	                if (result != TCL_OK) {
	                    return result;

	                }
	                break;
	            case REAL:
	                result = Tcl_GetDoubleFromObj(interp, patObj, &patDouble);
	                if (result != TCL_OK) {
	                    return result;

	                }
	                break;

	        }
	    } else {
	        patternBytes = Tcl_GetStringFromObj(patObj, &length);

	    }
	
	    /*
	     * Set default index value to -1, indicating failure; if we find the
	     * item in the course of our search, index will be set to the correct
	     * value.
	     */
	    index = -1;
	    match = 0;
	    if ((enum modes) mode == SORTED && allData == FALSE) {
	        /*
	         * If the data is sorted, we can do a more intelligent search.
	         * Note that there is no point in being smart when -all was
	         * specified; in that case, we have to look at all items anyway.
	         */
	        lower = offset-1 /*-1*/;
	        upper = listc;
	        while (lower + 1 != upper) {
	            i = (lower + upper)/2;
	            switch ((enum datatypes) dataType) {
	                case ASCII: {
	                    bytes = Tcl_GetString(listv[i]);
	                    match = strcmp(patternBytes, bytes);
	                    break;

	                }
	                case DICTIONARY: {
	                    bytes = Tcl_GetString(listv[i]);
	                    match = DictionaryCompare(patternBytes, bytes);
	                    break;

	                }
	                case INTEGER: {
	                    result = Tcl_GetIntFromObj(interp, listv[i], &objInt);
	                    if (result != TCL_OK) {
	                        return result;

	                    }
	                    if (patInt == objInt) {
	                        match = 0;
	                    } else if (patInt < objInt) {
	                        match = -1;
	                    } else {
	                        match = 1;

	                    }
	                    break;

	                }
	                case REAL: {
	                    result = Tcl_GetDoubleFromObj(interp, listv[i],
	                            &objDouble);
	                    if (result != TCL_OK) {
	                        return result;

	                    }
	                    if (patDouble == objDouble) {
	                        match = 0;
	                    } else if (patDouble < objDouble) {
	                        match = -1;
	                    } else {
	                        match = 1;

	                    }
	                    break;


	                }
	            }
	            if (match == 0) {
	                /*
	                 * Normally, binary search is written to stop when it
	                 * finds a match.  If there are duplicates of an element in
	                 * the list, our first match might not be the first occurance.
	                 * Consider:  0 0 0 1 1 1 2 2 2
	                 * To maintain consistancy with standard lsearch semantics,
	                 * we must find the leftmost occurance of the pattern in the
	                 * list.  Thus we don't just stop searching here.  This
	                 * variation means that a search always makes log n
	                 * comparisons (normal binary search might "get lucky" with
	                 * an early comparison).
	                 */
	                index = i;
	                upper = i;
	            } else if (match > 0) {
	                if (isIncreasing) {
	                    lower = i;
	                } else {
	                    upper = i;

	                }
	            } else {
	                if (isIncreasing) {
	                    upper = i;
	                } else {
	                    lower = i;



	                }
	            }
	        }
	    } else {
	        for (i = offset; i < listc; i++) {
	            match = 0;
	            switch ((enum modes) mode) {
	                case SORTED:
	                case EXACT: {
	                    switch ((enum datatypes) dataType) {
	                        case ASCII: {
	                            bytes = Tcl_GetStringFromObj(listv[i], &elemLen);
	                            if (length == elemLen) {
	                                match = (memcmp(bytes, patternBytes,
	                                        (size_t) length) == 0);

	                            }
	                            break;

	                        }
	                        case DICTIONARY: {
	                            bytes = Tcl_GetString(listv[i]);
	                            match =
	                                (DictionaryCompare(bytes, patternBytes) == 0);
	                            break;

	                        }
	                        case INTEGER: {
	                            result = Tcl_GetIntFromObj(interp, listv[i],
	                                    &objInt);
	                            if (result != TCL_OK) {
	                                return result;

	                            }
	                            match = (objInt == patInt);












	                            break;










	                        }
	                        case REAL: {
	                            result = Tcl_GetDoubleFromObj(interp, listv[i],



	                                    &objDouble);
	                            if (result != TCL_OK) {






	                                return result;








	                            }
	                            match = (objDouble == patDouble);
	                            break;









	                        }
	                    }
	                    break;
	                }
	                case GLOB: {


	                    match = Tcl_StringMatch(Tcl_GetString(listv[i]),



	                            patternBytes);
	                    break;
	                }
	                case REGEXP: {
	                    match = Tcl_RegExpMatchObj(interp, listv[i], patObj);


	                    if (match < 0) {
	                        return TCL_ERROR;

	                    }
	                    break;
	                }
	            }
	            /* Invert match condition for -not */
	            if (notMatch) {
	                match = (match != 0 ? 0 : 1);
	            }
	
	            /* Process the possible match for this element */
	            if (match != 0) {
	                if (allData) {
	                    if (returnInline) {
	                        /* Append data */
	                        Tcl_ListObjAppendElement(interp, listPtr,listv[i]);
	                    } else {
	                        /* Append index */
	                        Tcl_ListObjAppendElement(interp, listPtr,Tcl_NewIntObj(i));
	                    }
	                } else {
	                    index = i;
	                    break;
	                }
	            }
	        }
	    }
	    /*
	     * Return either a list (-all) or a single element
	     */
	    if (allData) {
	        Tcl_SetObjResult(interp,listPtr);
	    } else {
	        if (returnInline) {
	            if (index < 0) { /* Return a null */
	                Tcl_SetObjResult(interp,Tcl_NewObj());
	            } else {         /* Return one datum */
	                Tcl_SetObjResult(interp,listv[index]);
	            }
	        } else {
	            Tcl_SetIntObj(Tcl_GetObjResult(interp), index);
	        }
	    }
	    return TCL_OK;
	}

# Notes

The changes to _lsearch_ are entirely backward compatible and do no
change the behaviour or performance of the command for existing
options.  Moreover, these changes should not impact any of the other
list changes in [[22]](22.md), [[33]](33.md) or [[45]](45.md).

# Copyright

This document has been placed in the public domain.

# Appendix

The benchmarks below denote the expected speed increase of using the
new options vs. tcl only implementations.  Your mileage may vary.

	##
	# performs a lsearch -all -inline -glob search

	#
	proc lsearch_dataGLOB {listData pattern} {
	    set result [list]
	    foreach item $listData {
	        if {[string match $pattern $item]} {
	            lappend result $item


	        }
	    }
	    return $result

	}
	##
	# performs a lsearch -all -inline -regexp search

	#
	proc lsearch_dataRE {listData pattern} {
	    set result [list]
	    foreach item $listData {
	        if {[regexp $pattern $item]} {
	            lappend result $item


	        }
	    }
	    return $result

	}
	##
	# performs a lsearch -all -glob search

	#
	proc lsearch_allGLOB {listData pattern} {
	    set result [list]
	    set count 0
	    foreach item $listData {
	        if {[string match $pattern $item]} {
	            lappend result $count

	        }
	        incr count

	    }
	    return $result

	}
	
	# Build a 2K list of data
	catch {unset LIST}
	time {lappend LIST someStuff} 1000
	time {lappend LIST otherStuff} 1000
	
	# Case with all data matching in a 2K list 2.8x speedup
	puts "#C implementation [time {lsearch -glob -all -inline $LIST *Stuff} 100]"
	#=> C implementation 3766 microseconds per iteration
	puts "#tcl implementation [time {lsearch_dataGLOB $LIST *Stuff} 100]"
	#=> tcl implementation 10815 microseconds per iteration
	
	# Case with all data matching but returning indicies 3X speed up
	puts "#C implementation [time {lsearch -glob -all $LIST *Stuff} 100]"
	#=> C implementation 4305 microseconds per iteration
	puts "#tcl implementation [time {lsearch_allGLOB $LIST *Stuff} 100]"
	#=> tcl implementation 13277 microseconds per iteration
	
	# Case with no matching data 8X speed up
	puts "#C implementation [time {lsearch -glob -all -inline $LIST none*} 100]"
	#=> C implementation 646 microseconds per iteration
	puts "#tcl implementation [time {lsearch_dataGLOB $LIST none*} 100]"
	#=> tcl implementation 5354 microseconds per iteration
	
	
	# Repeat with RE, note more time spent in RE engine 2X speedup
	puts "#C implementation [time {lsearch -regexp -all -inline $LIST Stuff} 100]"
	#=> C implementation 35260 microseconds per iteration
	puts "#tcl implementation [time {lsearch_dataRE $LIST Stuff} 100]"
	#=> tcl implementation 62292 microseconds per iteration
	
	# Case with no matching data 2X speedup
	puts "#C implementation [time {lsearch -regexp -all -inline $LIST none*} 100]"
	#=> C implementation 14815 microseconds per iteration
	puts "#tcl implementation [time {lsearch_dataRE $LIST none} 100]"
	#=> tcl implementation 30553 microseconds per iteration

Name change from tip/81.tip to tip/81.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
TIP:            81
Title:          [incr Tcl] Functional Areas for Maintainer Assignments
Version:        $Revision: 1.7 $
Author:         Donal K. Fellows <[email protected]>
State:          Withdrawn
Type:           Process
Vote:           Pending
Created:        07-Jan-2002
Post-History:   


~ Abstract

This document proposes a division of [[incr Tcl]]'s source code into
functional areas so that each area may be assigned to one or more
maintainers.

~ Background

In order for [[incr Tcl]] to be adopted by the Tcl Core Team (see
[50]), it must be managed by the processes already established for
handling source (see [0] and [16] for details and rationale.)

~ Functional Areas

[[incr Tcl]] shall be divided into the following 8 functional units
(the seventh is the obsolete parts of the source tree, and the eighth
is the shared part of the source tree), each to be assigned one or
more maintainers:

 1. ''Objects'' -
      generic/itcl_bicmds.c,
      generic/itcl_class.c,
      generic/itcl_methods.c,
      generic/itcl_objects.c,
      generic/itcl_parse.c,
      doc/body.n,
      doc/class.n,
      doc/configbody.n,
      tests/basic.test,
      tests/body.test,
      tests/info.test,
      tests/inherit.test,
      tests/interp.test,
      tests/methods.test,
      tests/protection.test,

 2. ''Other Commands'' -
      generic/itcl_cmds.c,
      generic/itcl_ensemble.c,
      doc/code.n,
      doc/delete.n,
      doc/ensemble.n,
      doc/find.n,
      doc/local.n,
      doc/scope.n,
      tests/chain.test,
      tests/delete.test,
      tests/ensemble.test,
      tests/import.test,
      tests/local.test,
      tests/namespace.test,
      tests/scope.test

 3. ''Mac Build+Support'' -
      mac/tclMacAppInit.c,
      mac/MW_ItclHeader.pch,
      mac/pkgIndex.tcl,
      mac/itclMacApplication.r,
      mac/itclMacLibrary.r,
      mac/itclMacResource.r,
      mac/itclMacTclCode.r,
      mac/itclStaticApplication.r

 4. ''Unix Build+Support'' -
      unix/tclAppInit.c,
      configure.in ''(to move to unix/configure.in)'',
      aclocal.m4  ''(to move to unix/aclocal.m4 and gain pieces the
                     poorly-named Itcl tcl.m4)'',
      Makefile.in ''(to move to unix/Makefile.in)'',
      itclConfig.sh.in ''(to move to unix/itclConfig.sh.in)'',
      pkgIndex.tcl.in ''(to move to unix/pkgIndex.tcl.in)''

 5. ''Windows Build+Support'' -
      win/dllEntryPoint.c,
      win/makefile.bc,
      win/makefile.vc,
      win/rc/itcl.rc

 6. ''Other'' -
      generic/itcl_util.c,
      generic/itcl_linkage.c,
      doc/itclsh.1,
      library/itcl.tcl,
      tests/mkindex.itcl,
      tests/mkindex.test,
      tests/tclIndex

~ Obsolete Files

These files are all obsolete in one way or another, and will be removed
as part of the migration process.  They are listed here for completeness
only.

 * generic/itcl_obsolete.c,
   generic/itcl_migrate.c,
   doc/man.macros,
   doc/itcl_class.n,
   doc/itcl_info.n
   tests/defs,
   tests/old/AAA.test,
   tests/old/Bar.tcl,
   tests/old/BarFoo.tcl,
   tests/old/Baz.tcl,
   tests/old/Foo.tcl,
   tests/old/FooBar.tcl,
<
|
<
|
|
|
|
|
|
>

|

|



|

|
|
|

|

|
|
|


|
|
|
|
|
|











|
|
|














|

|







|

|
|
|
|
|
|

|





|
|
|






|





|
|

|
|








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

# TIP 81: [incr Tcl] Functional Areas for Maintainer Assignments

	Author:         Donal K. Fellows <[email protected]>
	State:          Withdrawn
	Type:           Process
	Vote:           Pending
	Created:        07-Jan-2002
	Post-History:   
-----

# Abstract

This document proposes a division of [incr Tcl]'s source code into
functional areas so that each area may be assigned to one or more
maintainers.

# Background

In order for [incr Tcl] to be adopted by the Tcl Core Team \(see
[[50]](50.md)\), it must be managed by the processes already established for
handling source \(see [[0]](0.md) and [[16]](16.md) for details and rationale.\)

# Functional Areas

[incr Tcl] shall be divided into the following 8 functional units
\(the seventh is the obsolete parts of the source tree, and the eighth
is the shared part of the source tree\), each to be assigned one or
more maintainers:

 1. _Objects_ -
      generic/itcl\_bicmds.c,
      generic/itcl\_class.c,
      generic/itcl\_methods.c,
      generic/itcl\_objects.c,
      generic/itcl\_parse.c,
      doc/body.n,
      doc/class.n,
      doc/configbody.n,
      tests/basic.test,
      tests/body.test,
      tests/info.test,
      tests/inherit.test,
      tests/interp.test,
      tests/methods.test,
      tests/protection.test,

 2. _Other Commands_ -
      generic/itcl\_cmds.c,
      generic/itcl\_ensemble.c,
      doc/code.n,
      doc/delete.n,
      doc/ensemble.n,
      doc/find.n,
      doc/local.n,
      doc/scope.n,
      tests/chain.test,
      tests/delete.test,
      tests/ensemble.test,
      tests/import.test,
      tests/local.test,
      tests/namespace.test,
      tests/scope.test

 3. _Mac Build\+Support_ -
      mac/tclMacAppInit.c,
      mac/MW\_ItclHeader.pch,
      mac/pkgIndex.tcl,
      mac/itclMacApplication.r,
      mac/itclMacLibrary.r,
      mac/itclMacResource.r,
      mac/itclMacTclCode.r,
      mac/itclStaticApplication.r

 4. _Unix Build\+Support_ -
      unix/tclAppInit.c,
      configure.in _\(to move to unix/configure.in\)_,
      aclocal.m4  _\(to move to unix/aclocal.m4 and gain pieces the
                     poorly-named Itcl tcl.m4\)_,
      Makefile.in _\(to move to unix/Makefile.in\)_,
      itclConfig.sh.in _\(to move to unix/itclConfig.sh.in\)_,
      pkgIndex.tcl.in _\(to move to unix/pkgIndex.tcl.in\)_

 5. _Windows Build\+Support_ -
      win/dllEntryPoint.c,
      win/makefile.bc,
      win/makefile.vc,
      win/rc/itcl.rc

 6. _Other_ -
      generic/itcl\_util.c,
      generic/itcl\_linkage.c,
      doc/itclsh.1,
      library/itcl.tcl,
      tests/mkindex.itcl,
      tests/mkindex.test,
      tests/tclIndex

# Obsolete Files

These files are all obsolete in one way or another, and will be removed
as part of the migration process.  They are listed here for completeness
only.

 * generic/itcl\_obsolete.c,
   generic/itcl\_migrate.c,
   doc/man.macros,
   doc/itcl\_class.n,
   doc/itcl\_info.n
   tests/defs,
   tests/old/AAA.test,
   tests/old/Bar.tcl,
   tests/old/BarFoo.tcl,
   tests/old/Baz.tcl,
   tests/old/Foo.tcl,
   tests/old/FooBar.tcl,
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

   tests/old/toasters/Hazard.tcl,
   tests/old/toasters/Outlet.tcl,
   tests/old/toasters/SmartToaster.tcl,
   tests/old/toasters/Toaster.tcl,
   tests/old/toasters/tclIndex,
   tests/old/toasters/usualway.tcl

~ Shared Files

The following files are shared by all of [[incr Tcl]].  Any maintainer
may modify them as necessary to complete changes they are making to
their portion of [[incr Tcl]].  Some of the following files define
[[incr Tcl]]'s API and should be changed only in accordance with TCT
approval.

 * generic/itcl.h,
   generic/itclInt.h,
   generic/itcl.decls,
   generic/itclInt.decls,
   doc/itcl.n,
   doc/itclvars.n,
   tests/all,
   tests/all.tcl

~ Generated Files

The following files are generated, so they don't need maintainers.

 * generic/itclDecls.h,
   generic/itclIntDecls.h,
   generic/itclStubInit.c,
   generic/itclStubLib.c,
   configure ''(moves to unix/configure, trailing configure.in)''

~ Copyright

This document has been placed in the public domain.








|

|

|
|











|







|

|


>
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
   tests/old/toasters/Hazard.tcl,
   tests/old/toasters/Outlet.tcl,
   tests/old/toasters/SmartToaster.tcl,
   tests/old/toasters/Toaster.tcl,
   tests/old/toasters/tclIndex,
   tests/old/toasters/usualway.tcl

# Shared Files

The following files are shared by all of [incr Tcl].  Any maintainer
may modify them as necessary to complete changes they are making to
their portion of [incr Tcl].  Some of the following files define
[incr Tcl]'s API and should be changed only in accordance with TCT
approval.

 * generic/itcl.h,
   generic/itclInt.h,
   generic/itcl.decls,
   generic/itclInt.decls,
   doc/itcl.n,
   doc/itclvars.n,
   tests/all,
   tests/all.tcl

# Generated Files

The following files are generated, so they don't need maintainers.

 * generic/itclDecls.h,
   generic/itclIntDecls.h,
   generic/itclStubInit.c,
   generic/itclStubLib.c,
   configure _\(moves to unix/configure, trailing configure.in\)_

# Copyright

This document has been placed in the public domain.

Name change from tip/82.tip to tip/82.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

TIP:		82
Title:		Add -offrelief Option to Checkbutton and Radiobutton
Version:	$Revision: 1.4 $
Author:		D. Richard Hipp <[email protected]>
State:		Final
Type:		Project
Vote:		Done
Created:	10-Jan-2002
Post-History:	
Tcl-Version:	8.4


~ Abstract

This TIP proposes adding option ''-offrelief'' to the checkbutton and
radiobutton widgets to specify the relief of the widget when
''-indicatoron'' is off and the state of the button is off.  This
feature is needed to support the use of checkbutton and radiobutton
widgets on toolbars.

~ Rationale

The checkbutton and radiobutton widgets both support the
''-overrelief'' option which is suppose to provide the capability to
change the relief of the widget on mouse-over.  The ''-overrelief''
option is not used by the underlying C code.  The value of
''-overrelief'' is used only by the script bindings to change the
''-relief'' option in response to ''<Enter>'' and ''<Leave>'' events.
But with the checkbutton and radiobutton widgets, the value of
''-relief'' is ignored when ''-indicatoron'' is turned off.  Hence,
''-overrelief'' has no effect when ''-indicatoron'' is off.

An example of the effect we would like to achieve is the
Bold/Italic/Underline and text justification toolbar buttons on word
processors.  The Bold/Italic/Underline toolbar buttons are most
naturally implemented using Tk checkbuttons and the text justification
toolbar buttons are most naturally implemented using Tk radiobuttons.
The buttons are configured to be flat most of the time (''-relief''
flat) but raise up on mouseover (''-overrelief'' raised).  Toolbar
buttons do not show indicators (''-indicatoron'' off).  This last
configuration option is the crux of the problem since when
''-indicatoron'' is off, the relief of the button is hard-coded to be
raised when the button is on and sunken when the button is off.  In
the current implementation, there is no way to get the off-relief to
be flat, and hence there is no way to achieve the customary look for
these common toolbar buttons.

~ Proposed Enhancement

This TIP proposes to modify the checkbutton and radiobutton widgets to
support a ''-offrelief'' option.  ''-offrelief'' will take any of the
usual relief values.  The default value will be ''raised''.  The
''-offrelief'' option determines the relief of the widget when
''-indicatoron'' option is off and the button itself is off.

The default bindings for checkbuttons and radiobuttons will also need
to be changed so that they copy the value of ''-overrelief'' into
''-offrelief'' instead of into ''-relief'' when the value of
''-indicatoron'' is false.

When ''-indicatoron'' is off and the button itself is on, the relief
continues to be hard-coded to sunken.  For symmetry, we might consider
adding another ''-onrelief'' option to cover this case.  But it is
difficult to imagine ever wanting to change the value of ''-onrelief''
so it has been omitted from this TIP.  If there as strong desire to
have ''-onrelief'', it can be added later.

~ Alternative Proposals

A simpler solution would be to change the ''-indicatoron'' option so
that it causes the off-relief to come from the ''-relief'' option
instead of using a hard-coded ''raised'' relief.  That approach is
conceptually simpler, but it breaks backwards compatibility and so
must be rejected.

Another possibility is to modify ''-indicatoron'' so that it takes a
third value (other than ''on'' or ''off'') where the third value works
like ''off'' but takes the off-relief from the ''-relief'' option
instead of always using ''raised''.  But this second idea seems more
contrived and makes it more difficult to define an alternative
on-relief value with a later modification.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|

|



|


|
|

|
|

|
|






|
|
|

|





|


|
|
|
|


|
|
|

|

|
|

|

|

|
|
|



|
|
|
|



|


>

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

# TIP 82: Add -offrelief Option to Checkbutton and Radiobutton

	Author:		D. Richard Hipp <[email protected]>
	State:		Final
	Type:		Project
	Vote:		Done
	Created:	10-Jan-2002
	Post-History:	
	Tcl-Version:	8.4
-----

# Abstract

This TIP proposes adding option _-offrelief_ to the checkbutton and
radiobutton widgets to specify the relief of the widget when
_-indicatoron_ is off and the state of the button is off.  This
feature is needed to support the use of checkbutton and radiobutton
widgets on toolbars.

# Rationale

The checkbutton and radiobutton widgets both support the
_-overrelief_ option which is suppose to provide the capability to
change the relief of the widget on mouse-over.  The _-overrelief_
option is not used by the underlying C code.  The value of
_-overrelief_ is used only by the script bindings to change the
_-relief_ option in response to _<Enter>_ and _<Leave>_ events.
But with the checkbutton and radiobutton widgets, the value of
_-relief_ is ignored when _-indicatoron_ is turned off.  Hence,
_-overrelief_ has no effect when _-indicatoron_ is off.

An example of the effect we would like to achieve is the
Bold/Italic/Underline and text justification toolbar buttons on word
processors.  The Bold/Italic/Underline toolbar buttons are most
naturally implemented using Tk checkbuttons and the text justification
toolbar buttons are most naturally implemented using Tk radiobuttons.
The buttons are configured to be flat most of the time \(_-relief_
flat\) but raise up on mouseover \(_-overrelief_ raised\).  Toolbar
buttons do not show indicators \(_-indicatoron_ off\).  This last
configuration option is the crux of the problem since when
_-indicatoron_ is off, the relief of the button is hard-coded to be
raised when the button is on and sunken when the button is off.  In
the current implementation, there is no way to get the off-relief to
be flat, and hence there is no way to achieve the customary look for
these common toolbar buttons.

# Proposed Enhancement

This TIP proposes to modify the checkbutton and radiobutton widgets to
support a _-offrelief_ option.  _-offrelief_ will take any of the
usual relief values.  The default value will be _raised_.  The
_-offrelief_ option determines the relief of the widget when
_-indicatoron_ option is off and the button itself is off.

The default bindings for checkbuttons and radiobuttons will also need
to be changed so that they copy the value of _-overrelief_ into
_-offrelief_ instead of into _-relief_ when the value of
_-indicatoron_ is false.

When _-indicatoron_ is off and the button itself is on, the relief
continues to be hard-coded to sunken.  For symmetry, we might consider
adding another _-onrelief_ option to cover this case.  But it is
difficult to imagine ever wanting to change the value of _-onrelief_
so it has been omitted from this TIP.  If there as strong desire to
have _-onrelief_, it can be added later.

# Alternative Proposals

A simpler solution would be to change the _-indicatoron_ option so
that it causes the off-relief to come from the _-relief_ option
instead of using a hard-coded _raised_ relief.  That approach is
conceptually simpler, but it breaks backwards compatibility and so
must be rejected.

Another possibility is to modify _-indicatoron_ so that it takes a
third value \(other than _on_ or _off_\) where the third value works
like _off_ but takes the off-relief from the _-relief_ option
instead of always using _raised_.  But this second idea seems more
contrived and makes it more difficult to define an alternative
on-relief value with a later modification.

# Copyright

This document has been placed in the public domain.

Name change from tip/83.tip to tip/83.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
136
137
138

139
140
141

142
143
144
145
146
147
148

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

165
166
167

168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188

189
190
191
192
193
194

195
196
197
198
199
200
201
202
203

TIP:            83
Title:          Augment Tcl_EvalFile with Tcl_EvalChannel and Tcl_EvalUrl
Version:        $Revision: 1.6 $
Author:         Marian Szczepkowski <[email protected]>
Author:         <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        24-Jan-2002
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP adds the ability to load Tcl files directly from URLs to the
core, together with a basic mechanism to simply evaluate a stream of
characters from a channel.

~ Proposal

I propose to split the ''Tcl_EvalFile'' function into two components
to enable the [[source]] command to use URL's to obtain source
material.

This will mean splitting ''Tcl_EvalFile'' into ''Tcl_EvalFile'' and
''Tcl_EvalChannel'' which are the two logical entities.  Maintaining
''Tcl_EvalFile'' will preserve backward compatability.

Creating ''Tcl_EvalChannel'' will provide generic functionality for
future use.

Adding ''Tcl_EvalUrl'' will enable handling standard URL format
strings.

This would enable this [[source http://anywhere.com/file.tcl]] to be
used.

Code will also need to be added to ''Tcl_SourceObjCmd'' to select
functionality requested.

~ Pro.

In a corporate environment where scripts are subject to change but the
interface is not, this allows scripts to be stored remotely on a
central server.

This also allows Tcl to interwork in a networked environment.

~ Con.

Security!!!!

This may mean in the long run adding a signing layer, but don't use it
if you don't want to.

~ Sample

I figure it looking something like this.
Snipped from 8.3 source.

~ Tcl_SourceObjCmd

|int
|Tcl_SourceObjCmd(dummy, interp, objc, objv)
|    ClientData dummy;		/* Not used. */
|    Tcl_Interp *interp;		/* Current interpreter. */
|    int objc;			/* Number of arguments. */
|    Tcl_Obj *CONST objv[];	/* Argument objects. */
|{

|    char *bytes;
|    int result;
|
|    if (objc != 2) {
|        Tcl_WrongNumArgs(interp, 1, objv, "fileName");
|        return TCL_ERROR;
|    }

|
|    bytes = Tcl_GetString(objv[1]);
|    if (strstr(ptr,"://")) {
|        result = Tcl_EvalFile(interp, bytes);
|    } else {
|        result = Tcl_EvalUrl(interp, bytes);
|    }

|    return result;

|}



~ Tcl_EvalFile




|int
|Tcl_EvalFile(interp, fileName)
|    Tcl_Interp *interp;         /* Interpreter in which to process file. */
|    char *fileName;             /* Name of file to process.  Tilde-substitution
|                                 * will be performed on this name. */
|{
|    int result, length;
|    struct stat statBuf;
|    Interp *iPtr;
|    Tcl_DString nameString;
|    char *name, *string;
|    Tcl_Channel chan;
|    Tcl_Obj *objPtr;
|
|    name = Tcl_TranslateFileName(interp, fileName, &nameString);
|    if (name == NULL) {
|        return TCL_ERROR;
|    }

|
|    result = TCL_ERROR;
|
|    if (TclStat(name, &statBuf) == -1) {
|        Tcl_SetErrno(errno);
|        Tcl_AppendResult(interp, "couldn't read file \"", fileName,
|                "\": ", Tcl_PosixError(interp), (char *) NULL);
|        goto end;
|    }

|
|    chan = Tcl_OpenFileChannel(interp, name, "r", 0644);
|    if (chan == (Tcl_Channel) NULL) {
|        Tcl_ResetResult(interp);
|        Tcl_AppendResult(interp, "couldn't read file \"", fileName,
|                "\": ", Tcl_PosixError(interp), (char *) NULL);
|        goto end;
|    }

|
|    result = Tcl_EvalChannel(interp, chan);
|
|  end:
|    Tcl_DStringFree(&nameString);
|    return result;
|}


~ Tcl_EvalUrl

|int
|Tcl_EvalUrl(interp, fileName)
|    Tcl_Interp *interp;	/* Interpreter in which to process file. */
|    char *fileName;	/* Name of URL to process. */
|{

|    return TCL_ERROR;
|}


~ Tcl_EvalChannel

|int
|Tcl_EvalChannel(interp, chan)
|    Tcl_Interp *interp; /* Interpreter in which to process file. */
|    Tcl_Channel chan;   /* Name of file to process. */
|{

|    int result, length;
|    struct stat statBuf;
|    char *oldScriptFile;
|    Interp *iPtr;
|    char *name, *string;
|    Tcl_Obj *objPtr;
|
|    result = TCL_ERROR;
|    objPtr = Tcl_NewObj();
|
|    if (Tcl_ReadChars(chan, objPtr, -1, 0) < 0) {
|        Tcl_Close(interp, chan);
|        Tcl_AppendResult(interp, "couldn't read file \"", fileName,
|                "\": ", Tcl_PosixError(interp), (char *) NULL);
|        goto end;
|    }

|    if (Tcl_Close(interp, chan) != TCL_OK) {
|        goto end;
|    }

|
|    iPtr = (Interp *) interp;
|    oldScriptFile = iPtr->scriptFile;
|    iPtr->scriptFile = fileName;
|    string = Tcl_GetStringFromObj(objPtr, &length);
|    result = Tcl_EvalEx(interp, string, length, 0);
|    iPtr->scriptFile = oldScriptFile;
|
|    if (result == TCL_RETURN) {
|        result = TclUpdateReturnInfo(iPtr);
|    } else if (result == TCL_ERROR) {
|        char msg[200 + TCL_INTEGER_SPACE];
|
|        /*
|         * Record information telling where the error occurred.
|         */
|
|        sprintf(msg, "\n    (file \"%.150s\" line %d)", fileName,
|                interp->errorLine);
|        Tcl_AddErrorInfo(interp, msg);
|    }

|
|  end:
|    Tcl_DecrRefCount(objPtr);
|    return result;
|}


~ Comments

The VFS extension interface of Tcl 8.4 plus the tclvfs and
vfs::http packages provide the ability to [[source]] an URL.
I believe that makes this proposal out of date.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|





|

|
|


|
|
|

|


|


|


|


|







|






|




|

|
|
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
>
|
>

>
|
>
>
>
|
<
<
<
<
<
<
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
<
|
>
|

|
|
|
|
<
>
|
<
|
>
|

|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
|
>
|


|


|


>

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
136

137
138

139
140
141
142
143
144
145
146

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

163
164
165

166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

187
188
189
190
191

192
193
194
195
196
197
198
199
200
201
202
203

# TIP 83: Augment Tcl_EvalFile with Tcl_EvalChannel and Tcl_EvalUrl

	Author:         Marian Szczepkowski <[email protected]>
	Author:         <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        24-Jan-2002
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP adds the ability to load Tcl files directly from URLs to the
core, together with a basic mechanism to simply evaluate a stream of
characters from a channel.

# Proposal

I propose to split the _Tcl\_EvalFile_ function into two components
to enable the [source] command to use URL's to obtain source
material.

This will mean splitting _Tcl\_EvalFile_ into _Tcl\_EvalFile_ and
_Tcl\_EvalChannel_ which are the two logical entities.  Maintaining
_Tcl\_EvalFile_ will preserve backward compatability.

Creating _Tcl\_EvalChannel_ will provide generic functionality for
future use.

Adding _Tcl\_EvalUrl_ will enable handling standard URL format
strings.

This would enable this [source <http://anywhere.com/file.tcl]> to be
used.

Code will also need to be added to _Tcl\_SourceObjCmd_ to select
functionality requested.

# Pro.

In a corporate environment where scripts are subject to change but the
interface is not, this allows scripts to be stored remotely on a
central server.

This also allows Tcl to interwork in a networked environment.

# Con.

Security!!!!

This may mean in the long run adding a signing layer, but don't use it
if you don't want to.

# Sample

I figure it looking something like this.
Snipped from 8.3 source.

# Tcl\_SourceObjCmd

	int
	Tcl_SourceObjCmd(dummy, interp, objc, objv)
	    ClientData dummy;		/* Not used. */
	    Tcl_Interp *interp;		/* Current interpreter. */
	    int objc;			/* Number of arguments. */
	    Tcl_Obj *CONST objv[];	/* Argument objects. */

	{
	    char *bytes;
	    int result;
	
	    if (objc != 2) {
	        Tcl_WrongNumArgs(interp, 1, objv, "fileName");
	        return TCL_ERROR;

	    }
	
	    bytes = Tcl_GetString(objv[1]);
	    if (strstr(ptr,"://")) {
	        result = Tcl_EvalFile(interp, bytes);
	    } else {
	        result = Tcl_EvalUrl(interp, bytes);

	    }
	    return result;
	}

# Tcl\_EvalFile

	int
	Tcl_EvalFile(interp, fileName)
	    Tcl_Interp *interp;         /* Interpreter in which to process file. */
	    char *fileName;             /* Name of file to process.  Tilde-substitution
	                                 * will be performed on this name. */
	{






	    int result, length;
	    struct stat statBuf;
	    Interp *iPtr;
	    Tcl_DString nameString;
	    char *name, *string;
	    Tcl_Channel chan;
	    Tcl_Obj *objPtr;
	
	    name = Tcl_TranslateFileName(interp, fileName, &nameString);
	    if (name == NULL) {
	        return TCL_ERROR;

	    }
	
	    result = TCL_ERROR;
	
	    if (TclStat(name, &statBuf) == -1) {
	        Tcl_SetErrno(errno);
	        Tcl_AppendResult(interp, "couldn't read file \"", fileName,
	                "\": ", Tcl_PosixError(interp), (char *) NULL);
	        goto end;

	    }
	
	    chan = Tcl_OpenFileChannel(interp, name, "r", 0644);
	    if (chan == (Tcl_Channel) NULL) {
	        Tcl_ResetResult(interp);
	        Tcl_AppendResult(interp, "couldn't read file \"", fileName,
	                "\": ", Tcl_PosixError(interp), (char *) NULL);
	        goto end;

	    }
	
	    result = Tcl_EvalChannel(interp, chan);
	
	  end:
	    Tcl_DStringFree(&nameString);
	    return result;

	}

# Tcl\_EvalUrl

	int
	Tcl_EvalUrl(interp, fileName)
	    Tcl_Interp *interp;	/* Interpreter in which to process file. */
	    char *fileName;	/* Name of URL to process. */

	{
	    return TCL_ERROR;

	}

# Tcl\_EvalChannel

	int
	Tcl_EvalChannel(interp, chan)
	    Tcl_Interp *interp; /* Interpreter in which to process file. */
	    Tcl_Channel chan;   /* Name of file to process. */

	{
	    int result, length;
	    struct stat statBuf;
	    char *oldScriptFile;
	    Interp *iPtr;
	    char *name, *string;
	    Tcl_Obj *objPtr;
	
	    result = TCL_ERROR;
	    objPtr = Tcl_NewObj();
	
	    if (Tcl_ReadChars(chan, objPtr, -1, 0) < 0) {
	        Tcl_Close(interp, chan);
	        Tcl_AppendResult(interp, "couldn't read file \"", fileName,
	                "\": ", Tcl_PosixError(interp), (char *) NULL);
	        goto end;

	    }
	    if (Tcl_Close(interp, chan) != TCL_OK) {
	        goto end;

	    }
	
	    iPtr = (Interp *) interp;
	    oldScriptFile = iPtr->scriptFile;
	    iPtr->scriptFile = fileName;
	    string = Tcl_GetStringFromObj(objPtr, &length);
	    result = Tcl_EvalEx(interp, string, length, 0);
	    iPtr->scriptFile = oldScriptFile;
	
	    if (result == TCL_RETURN) {
	        result = TclUpdateReturnInfo(iPtr);
	    } else if (result == TCL_ERROR) {
	        char msg[200 + TCL_INTEGER_SPACE];
	
	        /*
	         * Record information telling where the error occurred.
	         */
	
	        sprintf(msg, "\n    (file \"%.150s\" line %d)", fileName,
	                interp->errorLine);
	        Tcl_AddErrorInfo(interp, msg);

	    }
	
	  end:
	    Tcl_DecrRefCount(objPtr);
	    return result;

	}

# Comments

The VFS extension interface of Tcl 8.4 plus the tclvfs and
vfs::http packages provide the ability to [source] an URL.
I believe that makes this proposal out of date.

# Copyright

This document has been placed in the public domain.

Name change from tip/84.tip to tip/84.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

TIP:            84
Title:          Add control for mouse movement filtering
Version:        $Revision: 1.5 $
Author:         Jyrki Alakuijala <[email protected]>
Author:         Jeff Hobbs <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        26-Feb-2002
Post-History:   
Tcl-Version:    8.4


~ Abstract

When the mouse is moved, the Tcl/Tk system eats most of the mouse
movement events and only the last movement event when Tcl/Tk is not
busy is stored in the event queue.  I would like to obtain all the
movement events from the X-server or the Windows UI.

~ Rationale

I have an artistic drawing program where I need to track mouse as
accurately as possible.  At the moment I poll the ''XQueryPointer()''
in the busy loops to create (pseudo)events in the C-side of the code
to compensate for the missing events, but (of course) this does not
work in Windows.

I would like to have an option for the widget system or for the window
control so that a window (or, alternatively all the windows) could
receive all the movement events instead of only the last buffered one.

This has been a problem for me since 1995 and has - at many times -
caused me to consider changing the widget system.

~ Implementation

|    int Tk_CollapseMotionEvents(Display *display, int collapse)

A reference implementation is SF Tk patch 564642, which adds a flag to the TkDisplay that specifies whether motions events should be collapsed or not.  The default is the current behavior of collapsing these events.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|






|


|
|
|



|





|

|



|


>

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

# TIP 84: Add control for mouse movement filtering

	Author:         Jyrki Alakuijala <[email protected]>
	Author:         Jeff Hobbs <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        26-Feb-2002
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

When the mouse is moved, the Tcl/Tk system eats most of the mouse
movement events and only the last movement event when Tcl/Tk is not
busy is stored in the event queue.  I would like to obtain all the
movement events from the X-server or the Windows UI.

# Rationale

I have an artistic drawing program where I need to track mouse as
accurately as possible.  At the moment I poll the _XQueryPointer\(\)_
in the busy loops to create \(pseudo\)events in the C-side of the code
to compensate for the missing events, but \(of course\) this does not
work in Windows.

I would like to have an option for the widget system or for the window
control so that a window \(or, alternatively all the windows\) could
receive all the movement events instead of only the last buffered one.

This has been a problem for me since 1995 and has - at many times -
caused me to consider changing the widget system.

# Implementation

	    int Tk_CollapseMotionEvents(Display *display, int collapse)

A reference implementation is SF Tk patch 564642, which adds a flag to the TkDisplay that specifies whether motions events should be collapsed or not.  The default is the current behavior of collapsing these events.

# Copyright

This document has been placed in the public domain.

Name change from tip/85.tip to tip/85.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
136
137


138
139

140
141
142
143

144
145
146
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

TIP:            85
Title:          Custom Comparisons in Tcltest
Version:        $Revision: 1.14 $
Author:         Arjen Markus <[email protected]>
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        31-Jan-2002
Post-History:   
Keywords:       test,string comparison,floating-point
Tcl-Version:    8.4


~ Abstract

This TIP proposes a simple mechanism to make the ''tcltest'' package
an even more flexible package than it already is by allowing the
programmer to define his or her own comparison procedures.  Such
procedures can deal with issues like allowing a (small) tolerance in
floating-point results.

~ Rationale

The ''test'' command of the package ''tcltest 2.0'' supports the
comparison of the actual result with the expected result by a number
of methods: exact matching, glob-style matching and matching via a
regular expression, according to the ''-match'' option.  The flexibility
is indeed enhanced over the package ''tcltest 1.0,'' as it is now much
easier to allow for small variations in ''string'' results.  But
it is nearly impossible to define an accurate test that checks if
floating-point results are the "same" - exact matching will seldom
suffice due to platform-specific round-off errors or differences in
formatting a floating-point number (''0.12'' versus ''.12'' for
instance).

It is also impossible to compare results that are not easily expressed
as strings, for instance an application that produces binary files
that need to be compared or simply very long strings - these could
easily be stored in an external file, but would be awkward in a file
with a large number of such tests.

~ Proposal

The package ''tcltest 2.0.2'' defines an internal comparison procedure,
''CompareStrings'' that performs matching according to the three built-in
''-match'' options of ''test''.  This
procedure can easily be replaced by one that invokes registered 
commands or procedures. Such a command or procedure takes two 
arguments and returns 1 for a match and a 0 for failure, 
just as ''CompareStrings'' does in the current implementation:

| proc myMatchProc { expected actual } { 
|   if { $expected (is somehow equal) $actual } {
|      return 1
|   } else
|      return 0
|   }
| }



A new public command ''customMatch'' is proposed for the purpose
of registering these matching commands.  It can register a procedure,
such as ''myMatchProc'' defined above:

| ::tcltest::customMatch mytype myMatchProc

or, as in the sample implementation, an incomplete command:

| ::tcltest::customMatch exact [list ::string equal]

When the ''test'' command is called with the ''-match mytype'' option,
the command ''myMatchProc'' will be completed with two arguments,
the expected and actual results, and will be evaluated in the global
namespace to determine whether the test result matches the expected
result.  Likewise, the ''test'' option ''-match exact'' will
cause matching to be tested by the command ''::string equal''.
The default value of the ''-match'' option will continue to be ''exact''.

Allowing procedures to be invoked by their type names gives us the 
flexibility to register as many such procedures or commands as required.

Because this proposal adds a new public command to the ''tcltest''
package, the version will be incremented to 2.1.

A patch to the current HEAD that implements this proposal is
available as Tcl Patch 521362 at the Tcl project at SourceForge.
http://sf.net/tracker/?func=detail&aid=521362&group_id=10894&atid=310894

~ Two Examples

To show how this works, we include two simple examples:

 * Testing a package for calculating mathematical functions like
   Bessel functions.

 * Testing for negative results, as when providing an alternative, but
   incompatible implementation of a feature.

First, suppose you have defined a package for calculating the value of
a general Bessel function, just the sort of function that returns
floating-point numbers.  Then the results may be imprecise due to
rounding-off errors, different values of ''tcl_precision'' or, even
more banally, differences in the formatting of floating-point numbers
(''0.12'' versus ''.12'' for instance). 

The following shows how to do this:

| #

| # Test implementation of Bessel functions
| # (Table only provides 4 decimals)
| #

| customMatch 4decimals matchFloat4Decimals
|
| proc matchFloat4Decimals { expected actual } {
|    return [expr {abs($expected-$actual) <= 0.5e-4}]
| }

|
| test "J0-1.1" "J0 for x=1.0" -match 4decimals -body {
|    J0 1.0
| } -result 0.7652
|
| test "J1-1.1" "J0 for x=1.0" -match 4decimals -body {
|    J1 1.0
| } -result 0.4401

The second example occurs for instance when testing alternative
implementations: you want to check that the original standard feature
is failing whereas the new but incompatible alternative gets it right.
Then:

| proc matchNegative { expected actual } {
|    set match 0
|    foreach a $actual e $expected {
|       if { $a != $e } {
|          set match 1
|          break
|       }
|    }


|    return $match
| }

|
| customMatch negative matchNegative
|
| #

| # Floating-point comparisons are imprecise. The following
| # test returns typically such a list as {643 1357 1921 79 781 1219}
| # so nothing even close to the expected values.
| # 

| test "ManyCompares-1.2" "Compare fails - naive comparison" \
|    -match negative -body {
|    set naiv_eq 0
|    set naiv_ne 0
|    set naiv_ge 0
|    set naiv_gt 0
|    set naiv_le 0
|    set naiv_lt 0
|
|    for { set i -1000 } { $i <= 1000 } { incr i } {
|       if { $i == 0 } continue
|
|       set x [expr {1.01/double($i)}]
|       set y [expr {(2.1*$x)*(double($i)/2.1)}]
|
|       if { $y == 1.01 } { incr naiv_eq }
|       if { $y != 1.01 } { incr naiv_ne }
|       if { $y >= 1.01 } { incr naiv_ge }
|       if { $y >  1.01 } { incr naiv_gt }
|       if { $y <= 1.01 } { incr naiv_le }
|       if { $y <  1.01 } { incr naiv_lt }
|    }

|    set result [list $naiv_eq $naiv_ne $naiv_ge $naiv_gt $naiv_le $naiv_lt]
| } -result {2000 0 2000 0 2000 0}

makes sure that a mismatch is treated as the expected outcome.

~ Alternatives and objections

Of course, it is possible to achieve these effects within the current
framework of ''tcltest'', by putting these match procedures inside the
body of the test case. No extra user command would be necessary then.

There are at least two drawbacks to this approach:

 * The result against which we want to match is hidden in the code

 * If the test fails, the actual result is not printed (at least not
   by the ''tcltest'' framework).

As a matter of fact, the proposed mechanism actually simplifies the 
current implementation of the three match types to a certain degree by 
turning a switch between the three types into an array index.

~ See Also

Tcl Feature Request 490298.
http://sf.net/tracker/?func=detail&aid=490298&group_id=10894&atid=360894

~ History

''Cameron Laird'' was quite enthousiastic about the idea of providing 
custom match procedures.

''Mo DeJong'' requested the explicit examples (the second is actually 
the situation that triggered this TIP in the first place).

''Don Porter <[email protected]>'' revised the registration mechanism 
such that an arbitrary set of matching commands or procedures can be supported. His suggestions led to a revision of the TIP. He also 
revised the draft implementation.

~ Copyright

This document is placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|


|

|


|
|
|



|
|







|

|
|
|



|

|
|
|
|
|
<
<
|
>
>
|

|

|



|

|
|


|
|
|




|




|

|












|

|



<
>
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
|
|






|
|
|
|
|
|
<
<
>
>
|
<
>
|
|
|
<
>
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|



|


|






|
|





|


|

|

|


|
|

|



|


>

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
136
137

138
139
140
141

142
143
144
145

146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

# TIP 85: Custom Comparisons in Tcltest

	Author:         Arjen Markus <[email protected]>
	Author:         Don Porter <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        31-Jan-2002
	Post-History:   
	Keywords:       test,string comparison,floating-point
	Tcl-Version:    8.4
-----

# Abstract

This TIP proposes a simple mechanism to make the _tcltest_ package
an even more flexible package than it already is by allowing the
programmer to define his or her own comparison procedures.  Such
procedures can deal with issues like allowing a \(small\) tolerance in
floating-point results.

# Rationale

The _test_ command of the package _tcltest 2.0_ supports the
comparison of the actual result with the expected result by a number
of methods: exact matching, glob-style matching and matching via a
regular expression, according to the _-match_ option.  The flexibility
is indeed enhanced over the package _tcltest 1.0,_ as it is now much
easier to allow for small variations in _string_ results.  But
it is nearly impossible to define an accurate test that checks if
floating-point results are the "same" - exact matching will seldom
suffice due to platform-specific round-off errors or differences in
formatting a floating-point number \(_0.12_ versus _.12_ for
instance\).

It is also impossible to compare results that are not easily expressed
as strings, for instance an application that produces binary files
that need to be compared or simply very long strings - these could
easily be stored in an external file, but would be awkward in a file
with a large number of such tests.

# Proposal

The package _tcltest 2.0.2_ defines an internal comparison procedure,
_CompareStrings_ that performs matching according to the three built-in
_-match_ options of _test_.  This
procedure can easily be replaced by one that invokes registered 
commands or procedures. Such a command or procedure takes two 
arguments and returns 1 for a match and a 0 for failure, 
just as _CompareStrings_ does in the current implementation:

	 proc myMatchProc { expected actual } { 
	   if { $expected (is somehow equal) $actual } {
	      return 1
	   } else
	      return 0


	   }
	 }

A new public command _customMatch_ is proposed for the purpose
of registering these matching commands.  It can register a procedure,
such as _myMatchProc_ defined above:

	 ::tcltest::customMatch mytype myMatchProc

or, as in the sample implementation, an incomplete command:

	 ::tcltest::customMatch exact [list ::string equal]

When the _test_ command is called with the _-match mytype_ option,
the command _myMatchProc_ will be completed with two arguments,
the expected and actual results, and will be evaluated in the global
namespace to determine whether the test result matches the expected
result.  Likewise, the _test_ option _-match exact_ will
cause matching to be tested by the command _::string equal_.
The default value of the _-match_ option will continue to be _exact_.

Allowing procedures to be invoked by their type names gives us the 
flexibility to register as many such procedures or commands as required.

Because this proposal adds a new public command to the _tcltest_
package, the version will be incremented to 2.1.

A patch to the current HEAD that implements this proposal is
available as Tcl Patch 521362 at the Tcl project at SourceForge.
<http://sf.net/tracker/?func=detail&aid=521362&group\_id=10894&atid=310894>

# Two Examples

To show how this works, we include two simple examples:

 * Testing a package for calculating mathematical functions like
   Bessel functions.

 * Testing for negative results, as when providing an alternative, but
   incompatible implementation of a feature.

First, suppose you have defined a package for calculating the value of
a general Bessel function, just the sort of function that returns
floating-point numbers.  Then the results may be imprecise due to
rounding-off errors, different values of _tcl\_precision_ or, even
more banally, differences in the formatting of floating-point numbers
\(_0.12_ versus _.12_ for instance\). 

The following shows how to do this:


	 #
	 # Test implementation of Bessel functions
	 # (Table only provides 4 decimals)

	 #
	 customMatch 4decimals matchFloat4Decimals
	
	 proc matchFloat4Decimals { expected actual } {
	    return [expr {abs($expected-$actual) <= 0.5e-4}]

	 }
	
	 test "J0-1.1" "J0 for x=1.0" -match 4decimals -body {
	    J0 1.0
	 } -result 0.7652
	
	 test "J1-1.1" "J0 for x=1.0" -match 4decimals -body {
	    J1 1.0
	 } -result 0.4401

The second example occurs for instance when testing alternative
implementations: you want to check that the original standard feature
is failing whereas the new but incompatible alternative gets it right.
Then:

	 proc matchNegative { expected actual } {
	    set match 0
	    foreach a $actual e $expected {
	       if { $a != $e } {
	          set match 1
	          break


	       }
	    }
	    return $match

	 }
	
	 customMatch negative matchNegative
	

	 #
	 # Floating-point comparisons are imprecise. The following
	 # test returns typically such a list as {643 1357 1921 79 781 1219}
	 # so nothing even close to the expected values.

	 # 
	 test "ManyCompares-1.2" "Compare fails - naive comparison" \
	    -match negative -body {
	    set naiv_eq 0
	    set naiv_ne 0
	    set naiv_ge 0
	    set naiv_gt 0
	    set naiv_le 0
	    set naiv_lt 0
	
	    for { set i -1000 } { $i <= 1000 } { incr i } {
	       if { $i == 0 } continue
	
	       set x [expr {1.01/double($i)}]
	       set y [expr {(2.1*$x)*(double($i)/2.1)}]
	
	       if { $y == 1.01 } { incr naiv_eq }
	       if { $y != 1.01 } { incr naiv_ne }
	       if { $y >= 1.01 } { incr naiv_ge }
	       if { $y >  1.01 } { incr naiv_gt }
	       if { $y <= 1.01 } { incr naiv_le }
	       if { $y <  1.01 } { incr naiv_lt }

	    }
	    set result [list $naiv_eq $naiv_ne $naiv_ge $naiv_gt $naiv_le $naiv_lt]
	 } -result {2000 0 2000 0 2000 0}

makes sure that a mismatch is treated as the expected outcome.

# Alternatives and objections

Of course, it is possible to achieve these effects within the current
framework of _tcltest_, by putting these match procedures inside the
body of the test case. No extra user command would be necessary then.

There are at least two drawbacks to this approach:

 * The result against which we want to match is hidden in the code

 * If the test fails, the actual result is not printed \(at least not
   by the _tcltest_ framework\).

As a matter of fact, the proposed mechanism actually simplifies the 
current implementation of the three match types to a certain degree by 
turning a switch between the three types into an array index.

# See Also

Tcl Feature Request 490298.
<http://sf.net/tracker/?func=detail&aid=490298&group\_id=10894&atid=360894>

# History

_Cameron Laird_ was quite enthousiastic about the idea of providing 
custom match procedures.

_Mo DeJong_ requested the explicit examples \(the second is actually 
the situation that triggered this TIP in the first place\).

_Don Porter <[email protected]>_ revised the registration mechanism 
such that an arbitrary set of matching commands or procedures can be supported. His suggestions led to a revision of the TIP. He also 
revised the draft implementation.

# Copyright

This document is placed in the public domain.

Name change from tip/86.tip to tip/86.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346

TIP:            86
Title:          Improved Debugger Support
Version:        $Revision: 1.26 $
Author:         Peter MacDonald <[email protected]>
Author:         Peter MacDonald <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        08-Feb-2002
Post-History:   
Tcl-Version:    8.7


~ Abstract

This TIP proposes the storage by Tcl of source code file-name and
line-numbering information, making it available at script execution
time. It also adds additional '''trace''' and '''info''' subcommands
to make it easier for a debugger to control a Tcl script much as
''gdb'' can control a C program.

~ Rationale

Currently, although Tcl provides quite reasonable information to users
in error traces, the line numbers within those traces are always
relative to the evaluation context containing them (often the
procedure, but not always) and not to the script file containing the
procedure.  This is substantially different to virtually every other
computer language and makes correlating errors with the source line
that caused them much more difficult.  This also makes coupling a Tcl
interpreter to an external debugging tool more difficult.  This TIP
proposes adding new interfaces to the Tcl core to make such debugging
activity easier.

A new '''trace execution''' option enables Tcl to track line number
and source file information associated with statements being executed
and call a single callback.
A new '''info line'' option provides access to line number information.
As a result, it becomes a simple matter to implement a debugger for
Tcl, in Tcl.  Furthermore, the implementation also serves as example usage of
the C interface, enabling similar capabilities at the lower level.

A simple Tcl debugger, ''tgdb'', written in Tcl and emulating ''gdb'',
is included with this TIP to demonstrate the
use of this interface.  ''tgdb'' runs and controls a Tcl application
in a sub-interp using '''trace execution'''  and '''interp alias'''.
It supports breakpoints on lines/procs/vars/etc,
single-stepping, up/down stack and evals.  It is designed to work both as a
commandline and a slave process (see ''Reference Implementation'').

Finally, upon error within a procedure, the file path and
absolute (as opposed to relative) line number are printed out when
available, even in the case where called from an after or callback
invocation.  Aside from aiding the user in more easily locating and
dealing with errors, the message is machine parseable  For example:
automatically bring the user into an editor at the offending line.

~ Specification

A new '''execution''' subcommand to the '''trace''' command.

 > '''trace execution''' ''target'' ?''level''?

This arranges for an execution trace to be setup for commands at nesting
''level'' or above, thereby providing a simple Tcl interface for tracing
commands to say, implement a  debugger.  With no arguments,  the current
target is returned.  If target is the empty string, the execution trace
is removed.  The ''target'' argument is assumed to be a command string to be
executed.  When level is
not specified, it defaults to 0, meaning trace all  commands.  For  each
traced command, the following data will be produced:

 * linenumber

 >  The  line number the instruction begins on.

 * filename

 > The fully normalized file name.

 * nestlevel

 > The nesting level of the command.

 * stacklevel

 > The stack call level as per '''info level'''.

 * curnsproc

 > The current fully qualified namespace/function.

 * cmdname

 > The fully qualified command name of the command to be invoked.

 * command

 > The command line to be executed including arguments.

 * flags

 > Integer bit flags, currently bit 1 is set for breakpoint.

The target is presumed
to be a valid Tcl command onto which is appended the above arguments
before evaluation. Any return
from the command other than a normal return results in the command not
being executed.  As with all traces, execution tracing is disabled
within a trace handler.

Second, a new '''line''' subcommand to '''info''' gives access to the file
path and line number information.  It takes
subcommands of its own in turn:

 * '''info line current'''

 > Returns a list with two items: the line number and file name of
   the current statement.

 * '''info line number''' ''proc'' ?''line''?

 > Get/set the line number for the start of ''proc''.  In get mode,
   returns the definition line number in the message body.

 * '''info line level''' ''number''

 > Like the info level command, but returns the line number and
  file name from which the call at level number originates.
  For use with ''trace execution''.

 * '''info line file''' ?''proc'' ?''file''??

 > Get/set the sourced file path for ''proc''.  If ''proc'' is not specified,
   dump all known sourced file paths.

 * '''info line find''' ''file line''

 > Given a file path and line number, return the ''proc'' name
   containing line number ''line''.  A new nonstatic procedure
   ''TclFindProcByLine()'' provides this function.

 * '''info line relativeerror''' ?''bool''?

 > Set to 1 to disable absolute line number and file path on a
   procedure error.  This demotes procedure traceback errors to the
   same format as all other traceback errors, that is, using the
   relative the line number and file name.

These exhibit the following behavior:

 * ''What does this do when you redefine a proc?''

 > You get the values from the latest definition.

 * ''What about when you use interp aliases?''

 > You get an error, as it is not considered a proc.

 * ''And if proc itself gets redefined by someone's special
   debugger?''

 > If the definition is not the result of a source, the file/line come
   back as an empty string.

Third, a new ''info'' subcommand ''return''.

 * '''info return'''

 > When in ''trace execution'' mode, returns the saved last result of
  the previously executed command. Otherwise returns an empty string.
  Commands executed as part of a trace handler do not affect or change
  the saved last result. 

Forth, an additional flag option ''debug'' to ''trace add variable''

  * '''trace add variable {read write unset debug} command'''

  > Used in conjuction with ''read'', ''write'', and ''unset'',
   this option allows a debugger to set read/write traces that will
   not trigger the execution trace. In other words, it specifies
   that the command is debugger code that is not to be traced.
   Normally, debugger code is entered via the 
   '''trace execution''' handler and so has tracing disabled.
   This just provides a similar feature for '''trace variable'''

Fifth,  a new '''breakpoint''' subcommand to the '''trace''' command.

 > '''trace breakpoint''' ??''line file'' ?''level'' ...??

The ''trace breakpoint'' manages a list of breakpoints that cause an
''execution trace'' to trigger, even when the nestlevel is exceeded.
With no arguments it returns a ternery list of all breakpoints in sets
of the triples: line, file, and state.  With two arguments, the
current state for the breakpoint is returned.  With three or more arguments,
new breakpoints are created.  If created with a state of zero,
the breakpoint is considered inactive.  Setting the state of a
breakpoint to the empty string effectively deletes the breakpoint.
A state set to an N greater than zero triggers every Nth time.

~ Changes

Sourced file paths are stored per interp in a hash table.  File/line
numbering information is also stored in the ''Interp'', ''Proc'', ''After'',
and ''CallFrame'' structures.  Newline counting/shifting code was
added to ''proc'', ''while'', ''for'', ''foreach'', and ''if''.
All but the non-trivial code is active
only when the new TRACE_LINE_NUMBERS interp flag is active,
which is the case when using ''trace execution''.

Most new variables within Interp are in the struct subfield sourceInfo
of type ''Tcl_SourceInfo'', which can be retrieved via the new
''Tcl_GetSourceInfo(interp)'' stubbed/public call.

~ Overhead/Impact

The runtime impact to Tcl should be modest: a few 10's of
kilobytes of memory, even for moderately large programs.  Most of the space
impact occurs in storing the file paths.
A typical example from a large system:

|  100 sourced files * 100 bytes = 10K.

The other space overhead adds up to several words (8 bytes on a 32-bit
platform) per defined procedure, plus an additional words in
the ''Interp'' structure.

Runtime processing overhead should be negligible.

However, there have been no benchmarks done to validate these
assertions.

~ Reference Implementation

This patch is against Tcl 8.4.9 and represents a complete rework
of the approach.

http://pdqi.com/download/tclline-8.4.9.diff.gz

There is a simple demonstration debugger script: ''tgdb.tcl''.

http://pdqi.com/download/tgdb.tcl

~ Previous/Old Reference Implementation

http://pdqi.com/download/tclline-cvs.diff.gz - Patch against CVS head.

http://pdqi.com/download/tclline-8.4.6.diff.gz - Patch against Tcl 8.4.6

The CVS patch was against the CVS head is as of June 13/2004.
These have been lightly tested against numerous small Tcl programs.

There is also an initial version of a debugger: ''tgdb''.

http://pdqi.com/download/tgdb-2.0.tar.gz

''tgdb'' emulates the basic commands of ''gdb'' (''s'', ''n'',
''c'', ''f'', ''bt'', ''break'', ''info locals'', etc).  This newest
version also supports watchpoints and display variables.
With ''load'' and ''run'' commands added, ''tgdb'' should probably
work even with ''emacs'' and ''ddd''.

An additional package ''pdqi'' provides ''tdb'', a GUI front-end to
''gdb'', modified to also work with ''tgdb''.

~ Possible Future Enhancements

Build and store a line number table internally during parse?

Line number lookup via the source string.
A simple way to implement this might be to lookup string against the
''codePtr->source+bestSrcOffset'' as returned by ''GetSrcInfoForPc()''.

Add special handling for eval.  Cases like ''eval $str'' should eventually
be changed to report a line number of 0 (or more likely the line number
of the original statement) for all statements with any argument involving
a sub-eval. 

Possibly implement character offsets within a line.

~ Notes

A test has been added to the tests/trace.test.
A utility ''trcline.tcl'' is provided that the test uses to
provide some measure of the accuracy of the line number tracing.

~ Comments and Feedback

Jeff Hobbs asked what about '''interp alias''', etc.

   * Updated TIP to document cases

Jeff Hobbs notes filename storage is inefficient and finalization

   * Code changed to just increment ref count

   * '''TODO:''' What needs to be done for ''Tcl_Finalize''?

Neil Madden/Stephen Trier comment on info subcommand names ''line'',
''file'' and ''proc'' and possible future uses for ''line''

   * Changed to a single subcommand ''line'' and use sub-sub commands.

   * Additional subsubcommands can easily be added.

Donal Fellows writes: Is there a way to do an equivalent of ''#line''
directives in C

   * we can now set line number etc of a proc.  Is that enough?

Donald Porter notes that changing Tcl_Parse breaks binary compatibility

   * Move all parse variables to Interp and save/restore values
     on entry/exit to Tcl_EvalEx and TclCompileScript.

Donald Porter notes that the hash table should be per Interp

   * Code changed to move hash table to Interp.

Mo DeJong notes: file path should be used in place of file name

   * TIP updated to use path where appropriate

Mo DeJong suggests to maybe use ''TclpObjNormalizePath(fileName)''

   * No action yet

Donal Fellows objects to no support for '''proc'''s in subevals and
Andreas Kupries suggests defining a line number ''Tcl_Token'' type.

   * Add support for '''proc''' in subeval by addition to
     ''ResolvedCmdName''

   * This is now fixed.

Donal Fellows asks if trace is disabled in the execution handler,
how tracing to a sub-interp would work, and clarification on the
purpose and use of trace variable {debug}.

    * The documentation was updated to clarify these points.

~ Copyright

This document has been placed in the public domain.

''tgdb'' and ''pdqi'' have a BSD copyright by Peter MacDonald and
 PDQ Interfaces Inc.

<
|
<
|
|
|
|
|
|
|
|
>

|



|

|

|



|
|







|


|




|

|
|


|


|





|

|

|


|


|






|



|



|



|



|



|



|



|








|



|

|


|

|


|

|

|

|

|


|

|
|
|

|

|






|

|

|

|

|
|

|


|

|

|




|

|

|




|
|

|

|

|
|








|


|
|
|

|
|


|
|

|






|

|
|
|






|




|

|

|

|

|

|




|

|

|
|

|
|

|
|

|





|

|
|
|




|


|


|

|







|

|
|

|



|




|


|









|



|
|

|
|





|



|



|

>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346

# TIP 86: Improved Debugger Support

	Author:         Peter MacDonald <[email protected]>
	Author:         Peter MacDonald <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        08-Feb-2002
	Post-History:   
	Tcl-Version:    8.7
-----

# Abstract

This TIP proposes the storage by Tcl of source code file-name and
line-numbering information, making it available at script execution
time. It also adds additional **trace** and **info** subcommands
to make it easier for a debugger to control a Tcl script much as
_gdb_ can control a C program.

# Rationale

Currently, although Tcl provides quite reasonable information to users
in error traces, the line numbers within those traces are always
relative to the evaluation context containing them \(often the
procedure, but not always\) and not to the script file containing the
procedure.  This is substantially different to virtually every other
computer language and makes correlating errors with the source line
that caused them much more difficult.  This also makes coupling a Tcl
interpreter to an external debugging tool more difficult.  This TIP
proposes adding new interfaces to the Tcl core to make such debugging
activity easier.

A new **trace execution** option enables Tcl to track line number
and source file information associated with statements being executed
and call a single callback.
A new **info line_ option provides access to line number information.
As a result, it becomes a simple matter to implement a debugger for
Tcl, in Tcl.  Furthermore, the implementation also serves as example usage of
the C interface, enabling similar capabilities at the lower level.

A simple Tcl debugger, _tgdb_, written in Tcl and emulating _gdb_,
is included with this TIP to demonstrate the
use of this interface.  _tgdb_ runs and controls a Tcl application
in a sub-interp using **trace execution**  and **interp alias**.
It supports breakpoints on lines/procs/vars/etc,
single-stepping, up/down stack and evals.  It is designed to work both as a
commandline and a slave process \(see _Reference Implementation_\).

Finally, upon error within a procedure, the file path and
absolute \(as opposed to relative\) line number are printed out when
available, even in the case where called from an after or callback
invocation.  Aside from aiding the user in more easily locating and
dealing with errors, the message is machine parseable  For example:
automatically bring the user into an editor at the offending line.

# Specification

A new **execution** subcommand to the **trace** command.

 > **trace execution** _target_ ?_level_?

This arranges for an execution trace to be setup for commands at nesting
_level_ or above, thereby providing a simple Tcl interface for tracing
commands to say, implement a  debugger.  With no arguments,  the current
target is returned.  If target is the empty string, the execution trace
is removed.  The _target_ argument is assumed to be a command string to be
executed.  When level is
not specified, it defaults to 0, meaning trace all  commands.  For  each
traced command, the following data will be produced:

 * linenumber

	 >  The  line number the instruction begins on.

 * filename

	 > The fully normalized file name.

 * nestlevel

	 > The nesting level of the command.

 * stacklevel

	 > The stack call level as per **info level**.

 * curnsproc

	 > The current fully qualified namespace/function.

 * cmdname

	 > The fully qualified command name of the command to be invoked.

 * command

	 > The command line to be executed including arguments.

 * flags

	 > Integer bit flags, currently bit 1 is set for breakpoint.

The target is presumed
to be a valid Tcl command onto which is appended the above arguments
before evaluation. Any return
from the command other than a normal return results in the command not
being executed.  As with all traces, execution tracing is disabled
within a trace handler.

Second, a new **line** subcommand to **info** gives access to the file
path and line number information.  It takes
subcommands of its own in turn:

 * **info line current**

	 > Returns a list with two items: the line number and file name of
   the current statement.

 * **info line number** _proc_ ?_line_?

	 > Get/set the line number for the start of _proc_.  In get mode,
   returns the definition line number in the message body.

 * **info line level** _number_

	 > Like the info level command, but returns the line number and
  file name from which the call at level number originates.
  For use with _trace execution_.

 * **info line file** ?_proc_ ?_file_??

	 > Get/set the sourced file path for _proc_.  If _proc_ is not specified,
   dump all known sourced file paths.

 * **info line find** _file line_

	 > Given a file path and line number, return the _proc_ name
   containing line number _line_.  A new nonstatic procedure
   _TclFindProcByLine\(\)_ provides this function.

 * **info line relativeerror** ?_bool_?

	 > Set to 1 to disable absolute line number and file path on a
   procedure error.  This demotes procedure traceback errors to the
   same format as all other traceback errors, that is, using the
   relative the line number and file name.

These exhibit the following behavior:

 * _What does this do when you redefine a proc?_

	 > You get the values from the latest definition.

 * _What about when you use interp aliases?_

	 > You get an error, as it is not considered a proc.

 * _And if proc itself gets redefined by someone's special
   debugger?_

	 > If the definition is not the result of a source, the file/line come
   back as an empty string.

Third, a new _info_ subcommand _return_.

 * **info return**

	 > When in _trace execution_ mode, returns the saved last result of
  the previously executed command. Otherwise returns an empty string.
  Commands executed as part of a trace handler do not affect or change
  the saved last result. 

Forth, an additional flag option _debug_ to _trace add variable_

  * **trace add variable \{read write unset debug\} command**

	  > Used in conjuction with _read_, _write_, and _unset_,
   this option allows a debugger to set read/write traces that will
   not trigger the execution trace. In other words, it specifies
   that the command is debugger code that is not to be traced.
   Normally, debugger code is entered via the 
   **trace execution** handler and so has tracing disabled.
   This just provides a similar feature for **trace variable**

Fifth,  a new **breakpoint** subcommand to the **trace** command.

 > **trace breakpoint** ??_line file_ ?_level_ ...??

The _trace breakpoint_ manages a list of breakpoints that cause an
_execution trace_ to trigger, even when the nestlevel is exceeded.
With no arguments it returns a ternery list of all breakpoints in sets
of the triples: line, file, and state.  With two arguments, the
current state for the breakpoint is returned.  With three or more arguments,
new breakpoints are created.  If created with a state of zero,
the breakpoint is considered inactive.  Setting the state of a
breakpoint to the empty string effectively deletes the breakpoint.
A state set to an N greater than zero triggers every Nth time.

# Changes

Sourced file paths are stored per interp in a hash table.  File/line
numbering information is also stored in the _Interp_, _Proc_, _After_,
and _CallFrame_ structures.  Newline counting/shifting code was
added to _proc_, _while_, _for_, _foreach_, and _if_.
All but the non-trivial code is active
only when the new TRACE\_LINE\_NUMBERS interp flag is active,
which is the case when using _trace execution_.

Most new variables within Interp are in the struct subfield sourceInfo
of type _Tcl\_SourceInfo_, which can be retrieved via the new
_Tcl\_GetSourceInfo\(interp\)_ stubbed/public call.

# Overhead/Impact

The runtime impact to Tcl should be modest: a few 10's of
kilobytes of memory, even for moderately large programs.  Most of the space
impact occurs in storing the file paths.
A typical example from a large system:

	  100 sourced files * 100 bytes = 10K.

The other space overhead adds up to several words \(8 bytes on a 32-bit
platform\) per defined procedure, plus an additional words in
the _Interp_ structure.

Runtime processing overhead should be negligible.

However, there have been no benchmarks done to validate these
assertions.

# Reference Implementation

This patch is against Tcl 8.4.9 and represents a complete rework
of the approach.

<http://pdqi.com/download/tclline-8.4.9.diff.gz>

There is a simple demonstration debugger script: _tgdb.tcl_.

<http://pdqi.com/download/tgdb.tcl>

# Previous/Old Reference Implementation

<http://pdqi.com/download/tclline-cvs.diff.gz> - Patch against CVS head.

<http://pdqi.com/download/tclline-8.4.6.diff.gz> - Patch against Tcl 8.4.6

The CVS patch was against the CVS head is as of June 13/2004.
These have been lightly tested against numerous small Tcl programs.

There is also an initial version of a debugger: _tgdb_.

<http://pdqi.com/download/tgdb-2.0.tar.gz>

_tgdb_ emulates the basic commands of _gdb_ \(_s_, _n_,
_c_, _f_, _bt_, _break_, _info locals_, etc\).  This newest
version also supports watchpoints and display variables.
With _load_ and _run_ commands added, _tgdb_ should probably
work even with _emacs_ and _ddd_.

An additional package _pdqi_ provides _tdb_, a GUI front-end to
_gdb_, modified to also work with _tgdb_.

# Possible Future Enhancements

Build and store a line number table internally during parse?

Line number lookup via the source string.
A simple way to implement this might be to lookup string against the
_codePtr->source\+bestSrcOffset_ as returned by _GetSrcInfoForPc\(\)_.

Add special handling for eval.  Cases like _eval $str_ should eventually
be changed to report a line number of 0 \(or more likely the line number
of the original statement\) for all statements with any argument involving
a sub-eval. 

Possibly implement character offsets within a line.

# Notes

A test has been added to the tests/trace.test.
A utility _trcline.tcl_ is provided that the test uses to
provide some measure of the accuracy of the line number tracing.

# Comments and Feedback

Jeff Hobbs asked what about **interp alias**, etc.

   * Updated TIP to document cases

Jeff Hobbs notes filename storage is inefficient and finalization

   * Code changed to just increment ref count

   * **TODO:** What needs to be done for _Tcl\_Finalize_?

Neil Madden/Stephen Trier comment on info subcommand names _line_,
_file_ and _proc_ and possible future uses for _line_

   * Changed to a single subcommand _line_ and use sub-sub commands.

   * Additional subsubcommands can easily be added.

Donal Fellows writes: Is there a way to do an equivalent of _\#line_
directives in C

   * we can now set line number etc of a proc.  Is that enough?

Donald Porter notes that changing Tcl\_Parse breaks binary compatibility

   * Move all parse variables to Interp and save/restore values
     on entry/exit to Tcl\_EvalEx and TclCompileScript.

Donald Porter notes that the hash table should be per Interp

   * Code changed to move hash table to Interp.

Mo DeJong notes: file path should be used in place of file name

   * TIP updated to use path where appropriate

Mo DeJong suggests to maybe use _TclpObjNormalizePath\(fileName\)_

   * No action yet

Donal Fellows objects to no support for **proc**s in subevals and
Andreas Kupries suggests defining a line number _Tcl\_Token_ type.

   * Add support for **proc** in subeval by addition to
     _ResolvedCmdName_

   * This is now fixed.

Donal Fellows asks if trace is disabled in the execution handler,
how tracing to a sub-interp would work, and clarification on the
purpose and use of trace variable \{debug\}.

    * The documentation was updated to clarify these points.

# Copyright

This document has been placed in the public domain.

_tgdb_ and _pdqi_ have a BSD copyright by Peter MacDonald and
 PDQ Interfaces Inc.

Name change from tip/87.tip to tip/87.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

TIP:            87
Title:          Allow Tcl Access to the Recursion Limit
Version:        $Revision: 1.11 $
Author:         Stephen Trier <[email protected]>
Author:         Richard Suchenwirth <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        19-Feb-2002
Post-History:   
Discussions-To: news:comp.lang.tcl
Keywords:       Tcl_SetRecusionLimit,recursion limit
Tcl-Version:    8.4


~ Abstract

An extension to the [[interp]] command, [[interp recursionlimit]],
will permit Tcl scripts to control their own recursion limits.  Until
now, this limit has been changeable from a C API, but not from within
Tcl.

~ Rationale

As of Tcl 8.4a3, Tcl scripts must live with the default recursion
depth of 1000 nested calls to the ''Tcl_Eval'' family of functions or
resort to C code to change the limit.  Nevertheless, Tcl programmers
may find it useful to reduce the limit when debugging or to increase
it for scripts that include deeply recursive functions.  The changes
proposed in this TIP will make this possible in pure Tcl code.

~ Specification

 generic/tclInterp.c: Add subcommands to [interp] and to the slave
   interpreter object command with the following syntax:

 > interp recursionlimit ''path'' ''?newlimit?''

 > ''slave'' recursionlimit ''?newlimit?''

 > The parameter ''newlimit'' must be a positive integer.  When it is
   present, the limit is changed to ''newlimit'' and the command
   returns the new recursion limit.  If the ''newlimit'' parameter is
   absent, the command returns the current recursion limit.

 > No maximum value is enforced.  It is the programmer's
   responsibility to ensure the recursion limit will not overflow the
   process stack.

 > A safe interpreter is not allowed to change the recursion limit for
   itself nor for any other interpreter.  Attempting to do so will
   generate an error.  Safe interpreters are allowed to query
   recursion limits.

 > If an interpreter changes its own recursion limit to a value lower
   than the current Tcl_Eval nesting level, the limit will be
   changed, then an error message appropriate to this particular
   situation will be issued by the recursionlimit command.
   (Error text: "falling back due to new recursion limit")

 > If an interpreter changes a sub-interpreter's recursion limit to
   less than the sub-interpreter's current Tcl_Eval nesting level,
   no immediate error is issued.  The sub-interpreter will throw a
   "too many nested calls to Tcl_Eval (infinite loop?)" error if
   its nesting is still deeper than its recursion limit when next
   a command is executed in its context.

 generic/tclTest.c: Remove the now-unnecessary testsetrecursionlimit
   command.

 doc/interp.n: Add documentation for the new subcommands, including a
   warning about stack overflow, much like the warning in the
   documentation for ''Tcl_SetRecursionLimit()''.

 test/interp.test: Add tests for the new subcommands.

~ Comments Received

Discussion of this TIP took place in the following threads:

http://groups.google.com/groups?hl=en&threadm=3C6D0A88.5DC9D8B4%40utdt.edu

http://groups.google.com/groups?hl=en&threadm=3C73E98A.8ED9DDE6%40cisco.com

http://www.geocrawler.com/mail/thread.php3?subject=%5BTCLCORE%5D+TIP+%2387%3A+Allow+Tcl+Access+to+the+Recursion+Limit&list=7375

Using a command or variable ''::tcl::recursionLimit'' to manipulate
the limit was initially considered, but Miguel Sofer suggested making
the function a subcommand of [[interp]] because the recursion limit is
logically an attribute of each interpreter.  Miguel also pointed out that implementing ''TclpCheckStackSpace()'' for Unix would mitigate
the dangers of setting the recursion limit too high.

comp.lang.tcl saw some discussion of whether it would be appropriate to have a way to completely remove the recursion limit. The consensus was to not add such a feature.

The initial version of this TIP did not provide for a diagnostic error message for the case where the nesting is already deeper than the new recursion level. Ken Fitch, Don Porter, Miguel Sofer, and Donal Fellows discussed whether this was important. This version of the TIP uses Donal Fellows's suggestion of changing the recursion limit as requested, but providing a meaningful error message if the nesting is too deep for the new limit.

Donal Fellows suggested that slave interpreters should inherit their recursion limit from their parent. As it turns out, this behavior was already present but was not documented. The reference implementation documents it.

~ Reference Implementation

An implementation of this TIP, with tests and documentation, is patch number 522849 on SourceForge.

~ Copyright

This document is in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|

|




|


|





|




|

|

|
|
|












|


|


|

|








|



|



|

|

|

|

|
|








|



|


>

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

# TIP 87: Allow Tcl Access to the Recursion Limit

	Author:         Stephen Trier <[email protected]>
	Author:         Richard Suchenwirth <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        19-Feb-2002
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Keywords:       Tcl_SetRecusionLimit,recursion limit
	Tcl-Version:    8.4
-----

# Abstract

An extension to the [interp] command, [interp recursionlimit],
will permit Tcl scripts to control their own recursion limits.  Until
now, this limit has been changeable from a C API, but not from within
Tcl.

# Rationale

As of Tcl 8.4a3, Tcl scripts must live with the default recursion
depth of 1000 nested calls to the _Tcl\_Eval_ family of functions or
resort to C code to change the limit.  Nevertheless, Tcl programmers
may find it useful to reduce the limit when debugging or to increase
it for scripts that include deeply recursive functions.  The changes
proposed in this TIP will make this possible in pure Tcl code.

# Specification

 generic/tclInterp.c: Add subcommands to [interp] and to the slave
   interpreter object command with the following syntax:

 > interp recursionlimit _path_ _?newlimit?_

 > _slave_ recursionlimit _?newlimit?_

 > The parameter _newlimit_ must be a positive integer.  When it is
   present, the limit is changed to _newlimit_ and the command
   returns the new recursion limit.  If the _newlimit_ parameter is
   absent, the command returns the current recursion limit.

 > No maximum value is enforced.  It is the programmer's
   responsibility to ensure the recursion limit will not overflow the
   process stack.

 > A safe interpreter is not allowed to change the recursion limit for
   itself nor for any other interpreter.  Attempting to do so will
   generate an error.  Safe interpreters are allowed to query
   recursion limits.

 > If an interpreter changes its own recursion limit to a value lower
   than the current Tcl\_Eval nesting level, the limit will be
   changed, then an error message appropriate to this particular
   situation will be issued by the recursionlimit command.
   \(Error text: "falling back due to new recursion limit"\)

 > If an interpreter changes a sub-interpreter's recursion limit to
   less than the sub-interpreter's current Tcl\_Eval nesting level,
   no immediate error is issued.  The sub-interpreter will throw a
   "too many nested calls to Tcl\_Eval \(infinite loop?\)" error if
   its nesting is still deeper than its recursion limit when next
   a command is executed in its context.

 generic/tclTest.c: Remove the now-unnecessary testsetrecursionlimit
   command.

 doc/interp.n: Add documentation for the new subcommands, including a
   warning about stack overflow, much like the warning in the
   documentation for _Tcl\_SetRecursionLimit\(\)_.

 test/interp.test: Add tests for the new subcommands.

# Comments Received

Discussion of this TIP took place in the following threads:

<http://groups.google.com/groups?hl=en&threadm=3C6D0A88.5DC9D8B4%40utdt.edu>

<http://groups.google.com/groups?hl=en&threadm=3C73E98A.8ED9DDE6%40cisco.com>

<http://www.geocrawler.com/mail/thread.php3?subject=%5BTCLCORE%5D\+TIP\+%2387%3A\+Allow\+Tcl\+Access\+to\+the\+Recursion\+Limit&list=7375>

Using a command or variable _::tcl::recursionLimit_ to manipulate
the limit was initially considered, but Miguel Sofer suggested making
the function a subcommand of [interp] because the recursion limit is
logically an attribute of each interpreter.  Miguel also pointed out that implementing _TclpCheckStackSpace\(\)_ for Unix would mitigate
the dangers of setting the recursion limit too high.

comp.lang.tcl saw some discussion of whether it would be appropriate to have a way to completely remove the recursion limit. The consensus was to not add such a feature.

The initial version of this TIP did not provide for a diagnostic error message for the case where the nesting is already deeper than the new recursion level. Ken Fitch, Don Porter, Miguel Sofer, and Donal Fellows discussed whether this was important. This version of the TIP uses Donal Fellows's suggestion of changing the recursion limit as requested, but providing a meaningful error message if the nesting is too deep for the new limit.

Donal Fellows suggested that slave interpreters should inherit their recursion limit from their parent. As it turns out, this behavior was already present but was not documented. The reference implementation documents it.

# Reference Implementation

An implementation of this TIP, with tests and documentation, is patch number 522849 on SourceForge.

# Copyright

This document is in the public domain.

Name change from tip/88.tip to tip/88.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

TIP:            88
Title:          Extend Tcl Process Id Control via 'pid'
Version:        $Revision: 1.9 $
Author:         Jeff Hobbs <[email protected]>
Author:         Vince Darley <[email protected]>
State:          Rejected
Type:           Project
Vote:           Done
Created:        11-Mar-2002
Post-History:   
Tcl-Version:    8.4
Obsoleted-By:	240


~ Abstract

This TIP proposes extended the [[pid]] command to provide more
control over native processes in Tcl.

~ Rationale

Certain process control functions have shown themselves to be portable
and of high usefulness to Tcl programmers.  Most of these already
exist in TclX, but simply requiring that extension isn't always
acceptable.  The [[pid]] command in Tcl is a command that is often
overlooked, and so simple that it lends itself easily to being
enhanced with new syntax.  This TIP proposes adding subcommands to
[[pid]] that extend the process control functionality of pure Tcl.

~ Specification

|   pid ?fileId?
|   pid terminate ?-force? ?--? pid ?pid ...?

The first line is the current definition for [[pid]], which is to
return the name of the current process id, or that attached to a
''fileId'' (as returned by [[open]] or [[socket]]).  I propose to add
only ''terminate'' initially.  This command is adapted almost directly
from TclX's signal handling, but changed to work as a subcommand of
[[pid]].  This is to satisfy one of the most common requests from
users regarding process management - killing a known process.  It also
establishes the framework of extending [[pid]] for future
modifications.  The ?-force? argument causes a forceful termination
(the usage of SIGKILL on Unix, for Windows and Mac termination is
already forceful).

~ Reference Implementation

Although TclX's current documentation denies it, the ''send'' is
already implemented for Windows (as ''kill'' under TclX) as well as
Unix.  Macintosh implementations for OS 9 and below would need to be
created, or the documentation would need to stress that these are not
available there (OS X is Unix based).  Jim Ingham notes that a variant
of ''kill'' could be created for OS 9.  These functions are really
meant to round out the process control functionality in Tcl (started
with ''exec'' and ''open|''), which are already of limited portability
to Mac OS 9 (but undeniable usefulness elsewhere).

File: ''tcl/mac/tclMacChan.c''

File: ''tcl/unix/tclUnixPipe.c''

File: ''tcl/win/tclWinPipe.c''

Function: ''Tcl_PidObjCmd''

~ Future Potential

What this also provides is a blueprint for future process management
functions like these:

|   pid id ?-user ?userIdOrName?? ?-group ?groupIdOrName?? ?-parent parentId?
|   pid wait ?-nohang bool? ?-untraced bool? ?-group bool? ?fileIdOrPid?
|   pid nice ?-level niceLevel? fileIdOrPid
|   pid list ?pattern?
|   pid id ?-session id? ?-processgroup id?
|   pid handle action signal ...
|   pid send signalType fileIdOrPid ?fileIdOrPid ...?

[[pid wait]] was in the initial tip, but it was recommended to rework
it with callback to make it much more useful to the user.  The [[pid
id]] command was intended for Unix only, operating on the current
process id, and would function similar to the [[file attributes]]
command, but Windows NT does have similar functionality.  The
''-user'' and ''-group'' options will return the name if possible,
otherwise the id. The ''-parent'' option would be read-only (like
''-longname'' for [[file attributes]]).  [[pid send]] suffers from
cross-platform portability as well.  On Windows, you can only
''raise'' signals inside of your own process.

[[pid nice]] is easy to implement, while [[pid list]] is very much
platform sensitive.  [[pid handle]] is for signal handling, another
oft-requested feature for the core, and would be based on the TclX
[[signal]] command (perhaps named ''trap'' as in Expect?).  It could
be massaged to various forms.  These aren't to be addressed in this
TIP, but are just ideas for the future.

~ Comments

|   pid kill ?-group bool? ?-signal signalType? fileIdOrPid ?fileIdOrPid ...?

This was the original form for [[pid send]], but it was noted that we
are really sending signals.  While I prefer the specificity of users
recognizing ''kill'' as a command, what this really does is send
specific signals (ANSI C specifies SIGABRT, SIGINT and SIGTERM, and
for Unix we would handle the other POSIX names too).  Thus I changed
it to the ''send'' command documented above.

[[process]] rather than [[pid]] seems a more logical name for this
command, but we are working within the constraints of the existing
commands in order to prevent command bloat.  There is still logic in
the naming, as we are dealing with process ids.

[[pid terminate]] was also recommended to have the ability to
terminate a process ''and'' all its children.  This would be useful,
but is not in the scope of the current tip.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|


|




|


|

|

|
|

|

|
|

|

|

|
|

|

|
|


|
|
|
|
|

|

|

|

|

|




|
|
|
|
|
|
|

|
|
|
|

|
|
|

|

|
|

|



|

|

|

|
|
|
|

|




|
|


|


>

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

# TIP 88: Extend Tcl Process Id Control via 'pid'

	Author:         Jeff Hobbs <[email protected]>
	Author:         Vince Darley <[email protected]>
	State:          Rejected
	Type:           Project
	Vote:           Done
	Created:        11-Mar-2002
	Post-History:   
	Tcl-Version:    8.4
	Obsoleted-By:	240
-----

# Abstract

This TIP proposes extended the [pid] command to provide more
control over native processes in Tcl.

# Rationale

Certain process control functions have shown themselves to be portable
and of high usefulness to Tcl programmers.  Most of these already
exist in TclX, but simply requiring that extension isn't always
acceptable.  The [pid] command in Tcl is a command that is often
overlooked, and so simple that it lends itself easily to being
enhanced with new syntax.  This TIP proposes adding subcommands to
[pid] that extend the process control functionality of pure Tcl.

# Specification

	   pid ?fileId?
	   pid terminate ?-force? ?--? pid ?pid ...?

The first line is the current definition for [pid], which is to
return the name of the current process id, or that attached to a
_fileId_ \(as returned by [open] or [socket]\).  I propose to add
only _terminate_ initially.  This command is adapted almost directly
from TclX's signal handling, but changed to work as a subcommand of
[pid].  This is to satisfy one of the most common requests from
users regarding process management - killing a known process.  It also
establishes the framework of extending [pid] for future
modifications.  The ?-force? argument causes a forceful termination
\(the usage of SIGKILL on Unix, for Windows and Mac termination is
already forceful\).

# Reference Implementation

Although TclX's current documentation denies it, the _send_ is
already implemented for Windows \(as _kill_ under TclX\) as well as
Unix.  Macintosh implementations for OS 9 and below would need to be
created, or the documentation would need to stress that these are not
available there \(OS X is Unix based\).  Jim Ingham notes that a variant
of _kill_ could be created for OS 9.  These functions are really
meant to round out the process control functionality in Tcl \(started
with _exec_ and _open\|_\), which are already of limited portability
to Mac OS 9 \(but undeniable usefulness elsewhere\).

File: _tcl/mac/tclMacChan.c_

File: _tcl/unix/tclUnixPipe.c_

File: _tcl/win/tclWinPipe.c_

Function: _Tcl\_PidObjCmd_

# Future Potential

What this also provides is a blueprint for future process management
functions like these:

	   pid id ?-user ?userIdOrName?? ?-group ?groupIdOrName?? ?-parent parentId?
	   pid wait ?-nohang bool? ?-untraced bool? ?-group bool? ?fileIdOrPid?
	   pid nice ?-level niceLevel? fileIdOrPid
	   pid list ?pattern?
	   pid id ?-session id? ?-processgroup id?
	   pid handle action signal ...
	   pid send signalType fileIdOrPid ?fileIdOrPid ...?

[pid wait] was in the initial tip, but it was recommended to rework
it with callback to make it much more useful to the user.  The [pid
id] command was intended for Unix only, operating on the current
process id, and would function similar to the [file attributes]
command, but Windows NT does have similar functionality.  The
_-user_ and _-group_ options will return the name if possible,
otherwise the id. The _-parent_ option would be read-only \(like
_-longname_ for [file attributes]\).  [pid send] suffers from
cross-platform portability as well.  On Windows, you can only
_raise_ signals inside of your own process.

[pid nice] is easy to implement, while [pid list] is very much
platform sensitive.  [pid handle] is for signal handling, another
oft-requested feature for the core, and would be based on the TclX
[signal] command \(perhaps named _trap_ as in Expect?\).  It could
be massaged to various forms.  These aren't to be addressed in this
TIP, but are just ideas for the future.

# Comments

	   pid kill ?-group bool? ?-signal signalType? fileIdOrPid ?fileIdOrPid ...?

This was the original form for [pid send], but it was noted that we
are really sending signals.  While I prefer the specificity of users
recognizing _kill_ as a command, what this really does is send
specific signals \(ANSI C specifies SIGABRT, SIGINT and SIGTERM, and
for Unix we would handle the other POSIX names too\).  Thus I changed
it to the _send_ command documented above.

[process] rather than [pid] seems a more logical name for this
command, but we are working within the constraints of the existing
commands in order to prevent command bloat.  There is still logic in
the naming, as we are dealing with process ids.

[pid terminate] was also recommended to have the ability to
terminate a process _and_ all its children.  This would be useful,
but is not in the scope of the current tip.

# Copyright

This document has been placed in the public domain.

Name change from tip/89.tip to tip/89.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
136

137
138
139
140
141
142
143
144
145

146
147
148
149
150
151
152
153
154

155
156
157
158
159
160
161
162
163
164
165
166

167
168
169
170
171
172
173
174
175
176
177
178

179
180
181
182
183
184
185
186
187

188
189
190

191
192
193
194
195

196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

224
225
226
227
228
229
230
231
232
233
234
235
236
237
238

239
240

241
242
243

244
245
246
247
248
249
250
251
252

253
254
255
256
257
258
259
260

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277

278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299

300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317

318
319
320
321
322
323
324
325
326
327
328
329

330
331
332
333
334
335
336

337
338
339
340

341
342
343
344
345
346
347
348

349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366

367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392

393
394
395

396
397
398
399
400
401

402
403
404

405
406
407
408
409
410
411
412
413

414

415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446

447
448
449
450
451
452
453

454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482

483
484
485
486
487
488
489
490
491
492
493
494
495
496
497


498
499
500
501
502

503
504
505
506

507
508
509
510
511
512


513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530

531
532
533
534
535

536
537
538
539
540

541
542
543
544
545
546
547

548
549
550
551
552
553
554
555
556
557
558
559
560
561

562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583

584
585
586
587
588
589
590
591
592
593
594

595
596
597
598
599
600
601
602
603
604
605
606
607
608


609
610
611
612
613
614
615
616


617
618
619
620
621
622
623

624
625
626
627

628
629

630
631
632
633
634
635
636
637

638
639
640
641
642
643

644
645
646
647

648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677

678
679
680

TIP:            89
Title:          Try/Catch Exception Handling in the Core
Version:        $Revision: 1.10 $
Author:         Tom Wilkason <[email protected]>
Author:         Frank Pilhofer <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        11-Mar-2002
Post-History:   
Discussions-To: news:comp.lang.tcl
Tcl-Version:    8.6
Obsoleted-By:	329


~ Abstract

This TIP proposes the addition of a
'''try'''...'''catch'''...'''finally''' command to provide a more
robust and powerful exception handling mechanism.

~ Rationale

Exceptions are currently supported very well in Tcl, in fact they are
a major advantage over many other languages.  However the mechanism to
'''catch''' and handle the errors is someone limited and does not
promote the full use of existing error codes.  Wrapper procedures can
be written to improve on this, however both a performance and
compatibility penalty is incurred.

This TIP proposes adding a '''try/catch''' command to the Tcl core (or
C based Tcl library).  This implementation is not unlike those found
in C++, C#, Java and Python (to name a few languages).

An argument to add this to the core is that it modernizes the Tcl
exception handling without impacting performance in any other way.
'''try/catch''' are isolated commands that can easily be added, and do
not interact with other commands or require other changes.
'''try/catch''' is not an isolated extension that is useful for
special purposes only.  These commands, if implemented into the core,
will be useful for any script currently using the catch construct.

~ Specification

I propose the following two commands be added to Tcl:

 * '''throw''' command.

 > '''throw''' ?''type''? ?''message''? ?''info''?

 > A '''throw''' command with ''type'' throws an error exception with
   the errorCode ''type''. The '''throw''' command works as the
   '''error''' command, but the arguments are reordered to encourage
   the use of error-codes. The optional ''message'' and ''info''
   parameters work as they do in the '''error''' command.

 > The throw ''type'' can be any user defined or built in type,
   built-in types include POSIX, ARITH, CORE, REGEXP, WINDOWS, NONE,
   ...  The ''message'' is optional, and is the same as that issued by
   the '''catch''' command, '''error -code error''' "''message''"

 > An instance of '''throw''' with no arguments can be used within a
   '''catch''' block to immediately re-throw the current exception
   that is being handled by the '''catch''' block.  When an error is
   re-thrown in the catch block, the current error is propagated up
   one level following the evaluation of the '''finally''' block (if
   on exists).  Enclosing error handlers can then deal with the error.

 > Note that

|    throw type message info

 > is the same as

|    error message info type

 * '''try''' command.

 > '''try''' ''body'' ?'''catch''' {{''type_list''} ?''ecvar''? ?''msgvar''? ?''infovar''?} ''body ...''? ?'''finally''' ''body''?

 > If one or more '''catch''' blocks are specified, each corresponding
   ''body'' represents a required block of code that is evaluated if
   the resulting errorCode matches the ''type'' condition.  The
   required body of the '''finally''' block is evaluated following the
   '''try''' block and '''catch''' block (if any matches).

 > ''type_list'' represents a list of glob style patterns used to
   match eache of the error-code list conditions.  A match is declared
   if the ''type_list'' patterns or errorCode elements are exhausted
   (whichever comes first) and a mismatch has not occurred.  If a
   match occurs, and ''ecvar'' is specified, the errorCode list will
   be stored in ''ecvar'' within the local scope prior to executing
   the ''body''.  Moreover, if a ''msgvar'' or ''infovar'' are
   specified, the error message and errorInfo contents will be stored
   in the local context.

 > If an error occurs during the '''try''', and no ''catch'' blocks
   are specified, the offending error is rethrown following execution
   of the ''finally'' block (if specified).

 > If an error occurs during execution of a '''catch''' or
   '''finally''' block, this error will take precedence and will
   propagate upwards with a new stack trace.  If an error is rethrown
   within a catch block, the existing stack trace will be preserved
   with the rethrown error.  This allows later discrimination of the
   two different error conditions (rethrown vs. unintended).

 > Note, '''catch''' {''*''}, if specified, will catch all remaining
   errors.  If used, it should be placed last since each of the catch
   blocks are evaluated in the order specified.  ''type'' is that set
   in errorCode, and can be any user defined type, or built-in types
   including POSIX *, ARITH *, CHILD *, CORE, REGEXP, WINDOWS, or
   NONE.

 > If one or more '''catch''' blocks are specified, and no '''catch'''
   block matches the errorCode condition, the error will be propagated
   up to the next level following evaluation of the '''finally'''
   clause (if specified).  An enclosing '''try''' block (or
   '''catch''' command) can then be used to handle the error.

 > The '''finally''' block is used to perform all the clean up code.
   The '''finally''' body is evaluated whether the error occurs or
   not, or whether a '''catch''' block matched the errorCode.  It is
   also evaluated if a ''throw'' statement occurs within the
   '''catch''' clause.

~ Examples

'''throw'''

|    throw DEVICE "Could not write to device"

'''try''' only (no practical use)

|    try {
|       incr i
|    }


'''try - catch'''

|    try {
|       incr i
|    } catch * {
|       set i 0
|    }


'''try - finally'''

|    try {
|       . config -cursor watch
|       #do some busy stuff here, don't care about errors
|    } finally {
|       . config -cursor arrow
|    }


'''try - catch - catch'''

|    try {
|       ;# Some code that will cause an error
|    } catch {{POSIX *} eCode eMessage} {
|       ;# Statements to handle POSIX type errors
|    } catch {NULL eCode eMessage} {
|       ;# Statements to handle NULL (a user created) type errors
|    } catch {* eMessage} {
|       ;# Statements to handle all other errors
|    }


'''try - catch - catch - finally'''

|    try {
|       ;# Some code that will cause an error
|    } catch {POSIX eCode eMessage} {
|       ;# Statements to handle POSIX type errors
|    } catch {* eCode eMessage} {
|       ;# Statements to handle all other errors
|    } finally {
|       ;# Statements to execute whether an error occurred or not
|    }


Re-throw '''try - catch - finally'''

|    try {
|       try {
|          set b [expr {$a/0}]
|       } catch {ARITH} {
|          if {$a == 0} {
|             throw   ;# re-throw to outer try
|          }

|       } finally {
|          set b 1    ;# will execute before throw above
|       }

|    } catch {ARITH eCode eMessage} {
|       ;# This will catch the inner throw
|       puts "$res"
|    }


~ Revisions: Tom Wilkason March 26, 2002

  * Added additional ''ecvar'' and ''infovar'' optional arguments to
    the '''catch''' clause.

  * All uncaught errors are propagated up after execution of the
    finally block (if specified).

  * Unanticipated errors within a '''catch''' or '''finally''' block
    start a new stack trace and are propagated up.

  * Additional ''info'' optional argument added to '''throw''' for
    completeness.

~ Reference Implementation

| /*
|  * Implementation of try/catch and throw commands according to TIP 89
|  */
|
| #include <tcl.h>
|
| /*
|  * We keep a stack of contexts; whenever we have to handle an error,
|  * i.e. are executing a catch {} clause, we store the current error
|  * (errorCode, errorInfo and message), so that a throw with no arguments
|  * can re-throw it.
|  *

|  * This is interpreter-specific data. Each element is a list, with the
|  * last element being the most current one.
|  */
|
| typedef struct {
|   Tcl_Obj * errorCodeStack;
|   Tcl_Obj * errorInfoStack;
|   Tcl_Obj * errorMsgStack;
|   Tcl_Obj * errorCodeName;
|   Tcl_Obj * errorInfoName;
| } TryCatchTsd;
|
| /*
|  * Throw an Exception
|  *

|  * throw ?<type> ?<message>? ?<info>??
|  *

|  * Throws an exception with the errorCode <type>, the message <message>
|  * and the errorInfo <info>.
|  *

|  * An instance of throw with no arguments can be used within a catch or
|  * finally block to immediately re-throw the current exception that is
|  * being handled by the catch block.
|  */
|
| static int
| Tcl_ThrowObjCmd (ClientData clientData, Tcl_Interp *interp,
|                  int objc, Tcl_Obj *CONST objv[])
| {

|   TryCatchTsd * myTsd = (TryCatchTsd *) clientData;
|
|   if (objc < 1 || objc > 4) {
|     Tcl_AppendResult (interp, "wrong # args: should be \"",
|                       Tcl_GetStringFromObj (objv[0], NULL),
|                       " ?<type> ?<message>? ?<info>??\"", NULL);
|     return TCL_ERROR;
|   }

|
|   /*
|    * Re-throw an error
|    */
|
|   if (objc < 2) {
|     Tcl_Obj *errorCode, *errorInfo, *errorMsg;
|     int lastelement;
|
|     Tcl_ListObjLength (interp, myTsd->errorMsgStack, &lastelement);
|
|     if (lastelement < 1) {
|       Tcl_AppendResult (interp, "error: throw with no parameters ",
|                         "outside of a catch",
|                         NULL);
|       return TCL_ERROR;
|     }

|
|     lastelement--;
|     Tcl_ListObjIndex (interp, myTsd->errorMsgStack,
|                       lastelement, &errorMsg);
|     Tcl_ListObjIndex (interp, myTsd->errorCodeStack,
|                       lastelement, &errorCode);
|     Tcl_ListObjIndex (interp, myTsd->errorInfoStack,
|                       lastelement, &errorInfo);
|
|     Tcl_ResetResult (interp);
|     Tcl_SetObjResult (interp, errorMsg);
|     Tcl_SetObjErrorCode (interp, errorCode);
|
| #ifdef _TCLINT
|     Tcl_ObjSetVar2 (interp, myTsd->errorInfoName, NULL, errorInfo,
|                     TCL_GLOBAL_ONLY);
|     interp->flags = ERR_IN_PROGRESS;
| #else
|     Tcl_AddErrorInfo (interp, Tcl_GetStringFromObj (errorInfo, NULL));
| #endif
|     return TCL_ERROR;
|   }

|
|   /*
|    * throw with parameters
|    */
|
|   Tcl_ResetResult (interp);
|
|   if (objc >= 3) {
|     Tcl_SetObjResult (interp, objv[2]);
|   } else {
|     /*
|      * fabricate some error message for human consumption
|      */
|
|     Tcl_AppendResult (interp, "error: ",
|                       Tcl_GetStringFromObj (objv[1], NULL),
|                       NULL);
|   }

|
|   Tcl_SetObjErrorCode (interp, objv[1]);
|
|   if (objc >= 4) {
| #ifdef _TCLINT
|     Tcl_ObjSetVar2 (interp, myTsd->errorInfoName, NULL, objv[3],
|                     TCL_GLOBAL_ONLY);
|     interp->flags = ERR_IN_PROGRESS;
| #else
|     Tcl_AddErrorInfo (interp, Tcl_GetStringFromObj (objv[3], NULL));
| #endif
|   }

|
|   /*
|    * throw error
|    */
|
|   return TCL_ERROR;
| }

|
| /*
|  * exception handling
|  *

|  * try body ?catch {type-list ?ecvar? ?msgvar? ?infovar?} body ...?
|  *          ?finally body?
|  */
|
| static int
| Tcl_TryObjCmd (ClientData clientData, Tcl_Interp *interp,
|                int objc, Tcl_Obj *CONST objv[])
| {

|   TryCatchTsd * myTsd = (TryCatchTsd *) clientData;
|   int currentIndex, finallyIndex, catchInfoLength, hasCatch;
|   char * blockType;
|   int res;
|
|   /*
|    * first check for syntactic correctness before doing anything
|    */
|
|   if (objc < 2) {
|     Tcl_AppendResult (interp, "wrong # args: should be \"",
|                       Tcl_GetStringFromObj (objv[0], NULL),
|                       " body ",
|                       "?catch {type-list ?ecvar? ?msgvar? ?infovar?} ",
|                       "body ...? ",
|                       "?finally body?\"", NULL);
|     return TCL_ERROR;
|   }

|
|   currentIndex = 2;
|   finallyIndex = -1;
|   hasCatch = 0;
|
|   while (currentIndex < objc) {
|     blockType = Tcl_GetStringFromObj (objv[currentIndex], NULL);
|
|     if (strcmp (blockType, "catch") == 0) {
|       Tcl_Obj * typeList;
|       int typeListLength;
|
|       if (currentIndex+2 >= objc ||
|           Tcl_ListObjLength (interp, objv[currentIndex+1],
|                              &catchInfoLength) != TCL_OK ||
|           (catchInfoLength < 1 && catchInfoLength > 4) ||
|           Tcl_ListObjIndex (interp, objv[currentIndex+1],
|                             0, &typeList) != TCL_OK ||
|           Tcl_ListObjLength (interp, typeList,
|                              &typeListLength) != TCL_OK) {
|         Tcl_AppendResult (interp, "invalid syntax in catch clause: ",
|                           "should be \"",
|                           "catch {type-list ?ecvar? ?msgvar? ?infovar?} ",
|                           "body\"", NULL);
|         return TCL_ERROR;
|       }

|       hasCatch = 1;
|       currentIndex += 3;
|     }

|     else if (strcmp (blockType, "finally") == 0) {
|       if (currentIndex+2 != objc) {
|         Tcl_AppendResult (interp, "trailing args after finally clause",
|                           NULL);
|         return TCL_ERROR;
|       }

|       finallyIndex = currentIndex;
|       currentIndex += 2;
|     }

|     else {
|       Tcl_AppendResult (interp, "invalid syntax: should be \"",
|                         Tcl_GetStringFromObj (objv[0], NULL),
|                         " body ",
|                         "?catch {type-list ?ecvar? ?msgvar? ?infovar?} ",
|                         "body ...? ",
|                         "?finally body?\"", NULL);
|       return TCL_ERROR;
|     }

|   }

|
|   /*
|    * Eval main body
|    */
|
|   res = Tcl_EvalObjEx (interp, objv[1], 0);
|
|   /*
|    * In case of error, check the catch clauses
|    */
|
|   if (res == TCL_ERROR) {
|     Tcl_Obj *errorCode, *errorInfo, *errorMsg;
|     int errorCodeLength, stackLength;
|
|     errorMsg = Tcl_GetObjResult (interp);
|     errorCode = Tcl_ObjGetVar2 (interp, myTsd->errorCodeName, NULL,
|                                 TCL_GLOBAL_ONLY);
|     errorInfo = Tcl_ObjGetVar2 (interp, myTsd->errorInfoName, NULL,
|                                 TCL_GLOBAL_ONLY);
|
|     /*
|      * After an error has happened, errorCode and errorInfo should
|      * exist.
|      */
|
|     if (errorCode == NULL || errorInfo == NULL) {
|       Tcl_AppendResult (interp, "assertion error in try: ",
|                         "no errorCode or no errorInfo",
|                         NULL);
|       return TCL_ERROR;
|     }

|
|     if (Tcl_ListObjLength (interp, errorCode, &errorCodeLength) != TCL_OK) {
|       Tcl_AppendResult (interp, "assertion error in try: "
|                         "errorCode is not a list",
|                         NULL);
|       return TCL_ERROR;
|     }

|
|     /*
|      * push error data on stack, so that throw can rethrow the error
|      */
|
|     Tcl_ListObjAppendElement (interp, myTsd->errorMsgStack, errorMsg);
|     Tcl_ListObjAppendElement (interp, myTsd->errorCodeStack, errorCode);
|     Tcl_ListObjAppendElement (interp, myTsd->errorInfoStack, errorInfo);
|
|     /*
|      * Look for a matching clause
|      */
|
|     currentIndex = 2;
|
|     while (currentIndex < objc) {
|       blockType = Tcl_GetStringFromObj (objv[currentIndex], NULL);
|
|       if (strcmp (blockType, "catch") == 0) {
|         int typeListLength, matchIndex;
|         Tcl_Obj *typeList;
|
|         Tcl_ListObjIndex  (interp, objv[currentIndex+1], 0, &typeList);
|         Tcl_ListObjLength (interp, typeList, &typeListLength);
|
|         if (typeListLength > errorCodeLength) {
|           currentIndex += 3;
|           continue;
|         }

|
|         for (matchIndex=0; matchIndex<typeListLength; matchIndex++) {
|           Tcl_Obj *errorCodeItem, *typeListItem;
|           const char *errorCodeItemStr, *typeListItemStr;
|
|           Tcl_ListObjIndex (interp, errorCode, matchIndex, &errorCodeItem);
|           Tcl_ListObjIndex (interp, typeList, matchIndex, &typeListItem);
|
|           errorCodeItemStr = Tcl_GetStringFromObj (errorCodeItem, NULL);
|           typeListItemStr = Tcl_GetStringFromObj (typeListItem, NULL);
|
|           if (!Tcl_StringMatch (errorCodeItemStr, typeListItemStr)) {
|             break;
|           }
|         }


|
|         if (matchIndex >= typeListLength) {
|           /* matching catch clause found */
|           break;
|         }

|
|         /* continue looking */
|         currentIndex += 3;
|       }

|       else {
|         /* not a catch clause - there are no matching catch clauses */
|         currentIndex = objc;
|         break;
|       }
|     }


|
|     /*
|      * Did we find a matching catch clause?
|      */
|
|     if (currentIndex < objc) {
|       Tcl_Obj *ecvar, *msgvar, *infovar;
|
|       Tcl_ListObjLength (interp, objv[currentIndex+1], &catchInfoLength);
|
|       /*
|        * set variables with error data
|        */
|
|       if (catchInfoLength >= 2) {
|         Tcl_ListObjIndex (interp, objv[currentIndex+1], 1, &ecvar);
|         Tcl_ObjSetVar2 (interp, ecvar, NULL, errorCode, 0);
|       }

|
|       if (catchInfoLength >= 3) {
|         Tcl_ListObjIndex (interp, objv[currentIndex+1], 2, &msgvar);
|         Tcl_ObjSetVar2 (interp, msgvar, NULL, errorMsg, 0);
|       }

|
|       if (catchInfoLength >= 4) {
|         Tcl_ListObjIndex (interp, objv[currentIndex+1], 3, &infovar);
|         Tcl_ObjSetVar2 (interp, infovar, NULL, errorInfo, 0);
|       }

|
|       /*
|        * call body; the error code of this body takes precedence
|        */
|
|       res = Tcl_EvalObjEx (interp, objv[currentIndex+2], 0);
|     }

|
|     /*
|      * pop error data from stack
|      */
|
|     Tcl_ListObjLength (interp, myTsd->errorMsgStack, &stackLength);
|     stackLength--;
|     Tcl_ListObjReplace (interp, myTsd->errorMsgStack,
|                         stackLength, 1, 0, NULL);
|     Tcl_ListObjReplace (interp, myTsd->errorCodeStack,
|                         stackLength, 1, 0, NULL);
|     Tcl_ListObjReplace (interp, myTsd->errorInfoStack,
|                         stackLength, 1, 0, NULL);
|   }

|
|   /*
|    * Execute finally body. Preserve errorCode and friends; they might
|    * be corrupted by the code in the body - e.g. by a try in the code,
|    * or in a proc called by the code.
|    */
|
|   if (finallyIndex != -1) {
|     Tcl_Obj *errorCode, *errorInfo, *errorMsg;
|     int finallyres, origres=res;
|
|     errorMsg = Tcl_GetObjResult (interp);
|     Tcl_IncrRefCount (errorMsg);
|
|     if (origres == TCL_ERROR) {
|       errorCode = Tcl_ObjGetVar2 (interp, myTsd->errorCodeName, NULL,
|                                   TCL_GLOBAL_ONLY);
|       errorInfo = Tcl_ObjGetVar2 (interp, myTsd->errorInfoName, NULL,
|                                   TCL_GLOBAL_ONLY);
|       Tcl_IncrRefCount (errorCode);
|       Tcl_IncrRefCount (errorInfo);
|     }

|
|     finallyres = Tcl_EvalObjEx (interp, objv[finallyIndex+1], 0);
|
|     /*
|      * An Error in the finally clause takes precedence, else restore
|      * previous error data
|      */
|
|     if (finallyres != TCL_OK) {
|       res = finallyres;
|     }

|     else {
|       Tcl_SetObjResult (interp, errorMsg);
|
|       if (origres == TCL_ERROR) {
|         Tcl_SetObjErrorCode (interp, errorCode);
| #ifdef _TCLINT
|         Tcl_ObjSetVar2 (interp, myTsd->errorInfoName, NULL, errorInfo,
|                         TCL_GLOBAL_ONLY);
|         interp->flags = ERR_IN_PROGRESS;
| #else
|         Tcl_AddErrorInfo (interp, Tcl_GetStringFromObj (errorInfo, NULL));
| #endif
|       }
|     }


|
|     Tcl_DecrRefCount (errorMsg);
|
|     if (origres == TCL_ERROR) {
|       Tcl_DecrRefCount (errorCode);
|       Tcl_DecrRefCount (errorInfo);
|     }
|   }


|
|   /*
|    * Pass along return code
|    */
|
|   return res;
| }

|
| /*
|  * ----------------------------------------------------------------------
|  *

|  * "Main" function, install our commands in the Tcl interpreter
|  *

|  * ----------------------------------------------------------------------
|  */
|
| #undef TCL_STORAGE_CLASS
| #define TCL_STORAGE_CLASS DLLEXPORT
| EXTERN int
| Trycatch_Init (Tcl_Interp *interp)
| {

|   TryCatchTsd * myTsd;
|
| #ifdef USE_TCL_STUBS
|   if (Tcl_InitStubs (interp, TCL_VERSION, 0) == NULL) {
|     return TCL_ERROR;
|   }

| #else
|   if (Tcl_PkgRequire (interp, "Tcl", TCL_VERSION, 1) == NULL) {
|     return TCL_ERROR;
|   }

| #endif
|
|   /*
|    * Allocate Tsd
|    */
|
|   myTsd = (TryCatchTsd *) Tcl_Alloc (sizeof (TryCatchTsd));
|   myTsd->errorCodeStack = Tcl_NewObj ();
|   myTsd->errorInfoStack = Tcl_NewObj ();
|   myTsd->errorMsgStack  = Tcl_NewObj ();
|   myTsd->errorCodeName  = Tcl_NewStringObj ("errorCode", -1);
|   myTsd->errorInfoName  = Tcl_NewStringObj ("errorInfo", -1);
|
|   /*
|    * add commands
|    */
|
|   Tcl_CreateObjCommand (interp, "throw", Tcl_ThrowObjCmd,
|                         (ClientData) myTsd, NULL);
|   Tcl_CreateObjCommand (interp, "try", Tcl_TryObjCmd,
|                         (ClientData) myTsd, NULL);
|
|   /*
|    * Ready
|    */
|
|   Tcl_PkgProvide (interp, "trycatch", "0.1");
|   return TCL_OK;
| }


~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
|
>

|


|


|



|




|
|
|



|

|



|



|

|

|
|
|
|
|

|

|
|

|
|
|

|
|

|

|

|

|

|

|

|
|
|
|
|

|

|
|
|
|
|



|

|

|
|



|

|

|

|


|

|
|
|

|
|
|
|
|

|

|

|

|

|
|
<
>

|

|
|
|
|
<
|
>
|

|
|
|
|
|
<
|
>
|

|
|
|
|
|
|
|
|
<
|
>
|

|
|
|
|
|
|
|
|
<
|
>
|

|
|
|
|
|
|
<
>
|
|
<
>
|
|
|
<
|
>
|

|
|


|

|


|


|

|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
<
>
|
|
<
>
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
<
>
|
|
|
|
|
<
>
|
|
<
>
|
|
|
|
|
|
|
|
<
>
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
<
<
>
>
|
|
|
|
|
|
<
>
|
|
|
<
>
|
<
>
|
|
|
|
|
|
|
<
>
|
|
|
|
|
<
>
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
|
>
|


>

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
136
137
138
139
140
141
142

143
144
145
146
147
148
149
150
151

152
153
154
155
156
157
158
159
160
161
162
163

164
165
166
167
168
169
170
171
172
173
174
175

176
177
178
179
180
181
182
183
184
185

186
187
188

189
190
191
192

193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

222
223
224
225
226
227
228
229
230
231
232
233
234
235
236

237
238

239
240
241

242
243
244
245
246
247
248
249
250

251
252
253
254
255
256
257
258

259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275

276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297

298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315

316
317
318
319
320
321
322
323
324
325
326
327

328
329
330
331
332
333
334

335
336
337
338

339
340
341
342
343
344
345
346

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364

365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390

391
392
393

394
395
396
397
398
399

400
401
402

403
404
405
406
407
408
409
410
411

412

413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444

445
446
447
448
449
450
451

452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480

481
482
483
484
485
486
487
488
489
490
491
492
493
494


495
496
497
498
499
500

501
502
503
504

505
506
507
508
509


510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528

529
530
531
532
533

534
535
536
537
538

539
540
541
542
543
544
545

546
547
548
549
550
551
552
553
554
555
556
557
558
559

560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581

582
583
584
585
586
587
588
589
590
591
592

593
594
595
596
597
598
599
600
601
602
603
604
605


606
607
608
609
610
611
612
613


614
615
616
617
618
619
620
621

622
623
624
625

626
627

628
629
630
631
632
633
634
635

636
637
638
639
640
641

642
643
644
645

646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674

675
676
677
678
679
680

# TIP 89: Try/Catch Exception Handling in the Core

	Author:         Tom Wilkason <[email protected]>
	Author:         Frank Pilhofer <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        11-Mar-2002
	Post-History:   
	Discussions-To: news:comp.lang.tcl
	Tcl-Version:    8.6
	Obsoleted-By:	329
-----

# Abstract

This TIP proposes the addition of a
**try**...**catch**...**finally** command to provide a more
robust and powerful exception handling mechanism.

# Rationale

Exceptions are currently supported very well in Tcl, in fact they are
a major advantage over many other languages.  However the mechanism to
**catch** and handle the errors is someone limited and does not
promote the full use of existing error codes.  Wrapper procedures can
be written to improve on this, however both a performance and
compatibility penalty is incurred.

This TIP proposes adding a **try/catch** command to the Tcl core \(or
C based Tcl library\).  This implementation is not unlike those found
in C\+\+, C\#, Java and Python \(to name a few languages\).

An argument to add this to the core is that it modernizes the Tcl
exception handling without impacting performance in any other way.
**try/catch** are isolated commands that can easily be added, and do
not interact with other commands or require other changes.
**try/catch** is not an isolated extension that is useful for
special purposes only.  These commands, if implemented into the core,
will be useful for any script currently using the catch construct.

# Specification

I propose the following two commands be added to Tcl:

 * **throw** command.

	 > **throw** ?_type_? ?_message_? ?_info_?

	 > A **throw** command with _type_ throws an error exception with
   the errorCode _type_. The **throw** command works as the
   **error** command, but the arguments are reordered to encourage
   the use of error-codes. The optional _message_ and _info_
   parameters work as they do in the **error** command.

	 > The throw _type_ can be any user defined or built in type,
   built-in types include POSIX, ARITH, CORE, REGEXP, WINDOWS, NONE,
   ...  The _message_ is optional, and is the same as that issued by
   the **catch** command, **error -code error** "_message_"

	 > An instance of **throw** with no arguments can be used within a
   **catch** block to immediately re-throw the current exception
   that is being handled by the **catch** block.  When an error is
   re-thrown in the catch block, the current error is propagated up
   one level following the evaluation of the **finally** block \(if
   on exists\).  Enclosing error handlers can then deal with the error.

	 > Note that

		    throw type message info

	 > is the same as

		    error message info type

 * **try** command.

	 > **try** _body_ ?**catch** \{\{_type\_list_\} ?_ecvar_? ?_msgvar_? ?_infovar_?\} _body ..._? ?**finally** _body_?

	 > If one or more **catch** blocks are specified, each corresponding
   _body_ represents a required block of code that is evaluated if
   the resulting errorCode matches the _type_ condition.  The
   required body of the **finally** block is evaluated following the
   **try** block and **catch** block \(if any matches\).

	 > _type\_list_ represents a list of glob style patterns used to
   match eache of the error-code list conditions.  A match is declared
   if the _type\_list_ patterns or errorCode elements are exhausted
   \(whichever comes first\) and a mismatch has not occurred.  If a
   match occurs, and _ecvar_ is specified, the errorCode list will
   be stored in _ecvar_ within the local scope prior to executing
   the _body_.  Moreover, if a _msgvar_ or _infovar_ are
   specified, the error message and errorInfo contents will be stored
   in the local context.

	 > If an error occurs during the **try**, and no _catch_ blocks
   are specified, the offending error is rethrown following execution
   of the _finally_ block \(if specified\).

	 > If an error occurs during execution of a **catch** or
   **finally** block, this error will take precedence and will
   propagate upwards with a new stack trace.  If an error is rethrown
   within a catch block, the existing stack trace will be preserved
   with the rethrown error.  This allows later discrimination of the
   two different error conditions \(rethrown vs. unintended\).

	 > Note, **catch** \{_\*_\}, if specified, will catch all remaining
   errors.  If used, it should be placed last since each of the catch
   blocks are evaluated in the order specified.  _type_ is that set
   in errorCode, and can be any user defined type, or built-in types
   including POSIX \*, ARITH \*, CHILD \*, CORE, REGEXP, WINDOWS, or
   NONE.

	 > If one or more **catch** blocks are specified, and no **catch**
   block matches the errorCode condition, the error will be propagated
   up to the next level following evaluation of the **finally**
   clause \(if specified\).  An enclosing **try** block \(or
   **catch** command\) can then be used to handle the error.

	 > The **finally** block is used to perform all the clean up code.
   The **finally** body is evaluated whether the error occurs or
   not, or whether a **catch** block matched the errorCode.  It is
   also evaluated if a _throw_ statement occurs within the
   **catch** clause.

# Examples

**throw**

	    throw DEVICE "Could not write to device"

**try** only \(no practical use\)

	    try {
	       incr i

	    }

**try - catch**

	    try {
	       incr i
	    } catch * {
	       set i 0

	    }

**try - finally**

	    try {
	       . config -cursor watch
	       #do some busy stuff here, don't care about errors
	    } finally {
	       . config -cursor arrow

	    }

**try - catch - catch**

	    try {
	       ;# Some code that will cause an error
	    } catch {{POSIX *} eCode eMessage} {
	       ;# Statements to handle POSIX type errors
	    } catch {NULL eCode eMessage} {
	       ;# Statements to handle NULL (a user created) type errors
	    } catch {* eMessage} {
	       ;# Statements to handle all other errors

	    }

**try - catch - catch - finally**

	    try {
	       ;# Some code that will cause an error
	    } catch {POSIX eCode eMessage} {
	       ;# Statements to handle POSIX type errors
	    } catch {* eCode eMessage} {
	       ;# Statements to handle all other errors
	    } finally {
	       ;# Statements to execute whether an error occurred or not

	    }

Re-throw **try - catch - finally**

	    try {
	       try {
	          set b [expr {$a/0}]
	       } catch {ARITH} {
	          if {$a == 0} {
	             throw   ;# re-throw to outer try

	          }
	       } finally {
	          set b 1    ;# will execute before throw above

	       }
	    } catch {ARITH eCode eMessage} {
	       ;# This will catch the inner throw
	       puts "$res"

	    }

# Revisions: Tom Wilkason March 26, 2002

  * Added additional _ecvar_ and _infovar_ optional arguments to
    the **catch** clause.

  * All uncaught errors are propagated up after execution of the
    finally block \(if specified\).

  * Unanticipated errors within a **catch** or **finally** block
    start a new stack trace and are propagated up.

  * Additional _info_ optional argument added to **throw** for
    completeness.

# Reference Implementation

	 /*
	  * Implementation of try/catch and throw commands according to TIP 89
	  */
	
	 #include <tcl.h>
	
	 /*
	  * We keep a stack of contexts; whenever we have to handle an error,
	  * i.e. are executing a catch {} clause, we store the current error
	  * (errorCode, errorInfo and message), so that a throw with no arguments
	  * can re-throw it.

	  *
	  * This is interpreter-specific data. Each element is a list, with the
	  * last element being the most current one.
	  */
	
	 typedef struct {
	   Tcl_Obj * errorCodeStack;
	   Tcl_Obj * errorInfoStack;
	   Tcl_Obj * errorMsgStack;
	   Tcl_Obj * errorCodeName;
	   Tcl_Obj * errorInfoName;
	 } TryCatchTsd;
	
	 /*
	  * Throw an Exception

	  *
	  * throw ?<type> ?<message>? ?<info>??

	  *
	  * Throws an exception with the errorCode <type>, the message <message>
	  * and the errorInfo <info>.

	  *
	  * An instance of throw with no arguments can be used within a catch or
	  * finally block to immediately re-throw the current exception that is
	  * being handled by the catch block.
	  */
	
	 static int
	 Tcl_ThrowObjCmd (ClientData clientData, Tcl_Interp *interp,
	                  int objc, Tcl_Obj *CONST objv[])

	 {
	   TryCatchTsd * myTsd = (TryCatchTsd *) clientData;
	
	   if (objc < 1 || objc > 4) {
	     Tcl_AppendResult (interp, "wrong # args: should be \"",
	                       Tcl_GetStringFromObj (objv[0], NULL),
	                       " ?<type> ?<message>? ?<info>??\"", NULL);
	     return TCL_ERROR;

	   }
	
	   /*
	    * Re-throw an error
	    */
	
	   if (objc < 2) {
	     Tcl_Obj *errorCode, *errorInfo, *errorMsg;
	     int lastelement;
	
	     Tcl_ListObjLength (interp, myTsd->errorMsgStack, &lastelement);
	
	     if (lastelement < 1) {
	       Tcl_AppendResult (interp, "error: throw with no parameters ",
	                         "outside of a catch",
	                         NULL);
	       return TCL_ERROR;

	     }
	
	     lastelement--;
	     Tcl_ListObjIndex (interp, myTsd->errorMsgStack,
	                       lastelement, &errorMsg);
	     Tcl_ListObjIndex (interp, myTsd->errorCodeStack,
	                       lastelement, &errorCode);
	     Tcl_ListObjIndex (interp, myTsd->errorInfoStack,
	                       lastelement, &errorInfo);
	
	     Tcl_ResetResult (interp);
	     Tcl_SetObjResult (interp, errorMsg);
	     Tcl_SetObjErrorCode (interp, errorCode);
	
	 #ifdef _TCLINT
	     Tcl_ObjSetVar2 (interp, myTsd->errorInfoName, NULL, errorInfo,
	                     TCL_GLOBAL_ONLY);
	     interp->flags = ERR_IN_PROGRESS;
	 #else
	     Tcl_AddErrorInfo (interp, Tcl_GetStringFromObj (errorInfo, NULL));
	 #endif
	     return TCL_ERROR;

	   }
	
	   /*
	    * throw with parameters
	    */
	
	   Tcl_ResetResult (interp);
	
	   if (objc >= 3) {
	     Tcl_SetObjResult (interp, objv[2]);
	   } else {
	     /*
	      * fabricate some error message for human consumption
	      */
	
	     Tcl_AppendResult (interp, "error: ",
	                       Tcl_GetStringFromObj (objv[1], NULL),
	                       NULL);

	   }
	
	   Tcl_SetObjErrorCode (interp, objv[1]);
	
	   if (objc >= 4) {
	 #ifdef _TCLINT
	     Tcl_ObjSetVar2 (interp, myTsd->errorInfoName, NULL, objv[3],
	                     TCL_GLOBAL_ONLY);
	     interp->flags = ERR_IN_PROGRESS;
	 #else
	     Tcl_AddErrorInfo (interp, Tcl_GetStringFromObj (objv[3], NULL));
	 #endif

	   }
	
	   /*
	    * throw error
	    */
	
	   return TCL_ERROR;

	 }
	
	 /*
	  * exception handling

	  *
	  * try body ?catch {type-list ?ecvar? ?msgvar? ?infovar?} body ...?
	  *          ?finally body?
	  */
	
	 static int
	 Tcl_TryObjCmd (ClientData clientData, Tcl_Interp *interp,
	                int objc, Tcl_Obj *CONST objv[])

	 {
	   TryCatchTsd * myTsd = (TryCatchTsd *) clientData;
	   int currentIndex, finallyIndex, catchInfoLength, hasCatch;
	   char * blockType;
	   int res;
	
	   /*
	    * first check for syntactic correctness before doing anything
	    */
	
	   if (objc < 2) {
	     Tcl_AppendResult (interp, "wrong # args: should be \"",
	                       Tcl_GetStringFromObj (objv[0], NULL),
	                       " body ",
	                       "?catch {type-list ?ecvar? ?msgvar? ?infovar?} ",
	                       "body ...? ",
	                       "?finally body?\"", NULL);
	     return TCL_ERROR;

	   }
	
	   currentIndex = 2;
	   finallyIndex = -1;
	   hasCatch = 0;
	
	   while (currentIndex < objc) {
	     blockType = Tcl_GetStringFromObj (objv[currentIndex], NULL);
	
	     if (strcmp (blockType, "catch") == 0) {
	       Tcl_Obj * typeList;
	       int typeListLength;
	
	       if (currentIndex+2 >= objc ||
	           Tcl_ListObjLength (interp, objv[currentIndex+1],
	                              &catchInfoLength) != TCL_OK ||
	           (catchInfoLength < 1 && catchInfoLength > 4) ||
	           Tcl_ListObjIndex (interp, objv[currentIndex+1],
	                             0, &typeList) != TCL_OK ||
	           Tcl_ListObjLength (interp, typeList,
	                              &typeListLength) != TCL_OK) {
	         Tcl_AppendResult (interp, "invalid syntax in catch clause: ",
	                           "should be \"",
	                           "catch {type-list ?ecvar? ?msgvar? ?infovar?} ",
	                           "body\"", NULL);
	         return TCL_ERROR;

	       }
	       hasCatch = 1;
	       currentIndex += 3;

	     }
	     else if (strcmp (blockType, "finally") == 0) {
	       if (currentIndex+2 != objc) {
	         Tcl_AppendResult (interp, "trailing args after finally clause",
	                           NULL);
	         return TCL_ERROR;

	       }
	       finallyIndex = currentIndex;
	       currentIndex += 2;

	     }
	     else {
	       Tcl_AppendResult (interp, "invalid syntax: should be \"",
	                         Tcl_GetStringFromObj (objv[0], NULL),
	                         " body ",
	                         "?catch {type-list ?ecvar? ?msgvar? ?infovar?} ",
	                         "body ...? ",
	                         "?finally body?\"", NULL);
	       return TCL_ERROR;

	     }

	   }
	
	   /*
	    * Eval main body
	    */
	
	   res = Tcl_EvalObjEx (interp, objv[1], 0);
	
	   /*
	    * In case of error, check the catch clauses
	    */
	
	   if (res == TCL_ERROR) {
	     Tcl_Obj *errorCode, *errorInfo, *errorMsg;
	     int errorCodeLength, stackLength;
	
	     errorMsg = Tcl_GetObjResult (interp);
	     errorCode = Tcl_ObjGetVar2 (interp, myTsd->errorCodeName, NULL,
	                                 TCL_GLOBAL_ONLY);
	     errorInfo = Tcl_ObjGetVar2 (interp, myTsd->errorInfoName, NULL,
	                                 TCL_GLOBAL_ONLY);
	
	     /*
	      * After an error has happened, errorCode and errorInfo should
	      * exist.
	      */
	
	     if (errorCode == NULL || errorInfo == NULL) {
	       Tcl_AppendResult (interp, "assertion error in try: ",
	                         "no errorCode or no errorInfo",
	                         NULL);
	       return TCL_ERROR;

	     }
	
	     if (Tcl_ListObjLength (interp, errorCode, &errorCodeLength) != TCL_OK) {
	       Tcl_AppendResult (interp, "assertion error in try: "
	                         "errorCode is not a list",
	                         NULL);
	       return TCL_ERROR;

	     }
	
	     /*
	      * push error data on stack, so that throw can rethrow the error
	      */
	
	     Tcl_ListObjAppendElement (interp, myTsd->errorMsgStack, errorMsg);
	     Tcl_ListObjAppendElement (interp, myTsd->errorCodeStack, errorCode);
	     Tcl_ListObjAppendElement (interp, myTsd->errorInfoStack, errorInfo);
	
	     /*
	      * Look for a matching clause
	      */
	
	     currentIndex = 2;
	
	     while (currentIndex < objc) {
	       blockType = Tcl_GetStringFromObj (objv[currentIndex], NULL);
	
	       if (strcmp (blockType, "catch") == 0) {
	         int typeListLength, matchIndex;
	         Tcl_Obj *typeList;
	
	         Tcl_ListObjIndex  (interp, objv[currentIndex+1], 0, &typeList);
	         Tcl_ListObjLength (interp, typeList, &typeListLength);
	
	         if (typeListLength > errorCodeLength) {
	           currentIndex += 3;
	           continue;

	         }
	
	         for (matchIndex=0; matchIndex<typeListLength; matchIndex++) {
	           Tcl_Obj *errorCodeItem, *typeListItem;
	           const char *errorCodeItemStr, *typeListItemStr;
	
	           Tcl_ListObjIndex (interp, errorCode, matchIndex, &errorCodeItem);
	           Tcl_ListObjIndex (interp, typeList, matchIndex, &typeListItem);
	
	           errorCodeItemStr = Tcl_GetStringFromObj (errorCodeItem, NULL);
	           typeListItemStr = Tcl_GetStringFromObj (typeListItem, NULL);
	
	           if (!Tcl_StringMatch (errorCodeItemStr, typeListItemStr)) {
	             break;


	           }
	         }
	
	         if (matchIndex >= typeListLength) {
	           /* matching catch clause found */
	           break;

	         }
	
	         /* continue looking */
	         currentIndex += 3;

	       }
	       else {
	         /* not a catch clause - there are no matching catch clauses */
	         currentIndex = objc;
	         break;


	       }
	     }
	
	     /*
	      * Did we find a matching catch clause?
	      */
	
	     if (currentIndex < objc) {
	       Tcl_Obj *ecvar, *msgvar, *infovar;
	
	       Tcl_ListObjLength (interp, objv[currentIndex+1], &catchInfoLength);
	
	       /*
	        * set variables with error data
	        */
	
	       if (catchInfoLength >= 2) {
	         Tcl_ListObjIndex (interp, objv[currentIndex+1], 1, &ecvar);
	         Tcl_ObjSetVar2 (interp, ecvar, NULL, errorCode, 0);

	       }
	
	       if (catchInfoLength >= 3) {
	         Tcl_ListObjIndex (interp, objv[currentIndex+1], 2, &msgvar);
	         Tcl_ObjSetVar2 (interp, msgvar, NULL, errorMsg, 0);

	       }
	
	       if (catchInfoLength >= 4) {
	         Tcl_ListObjIndex (interp, objv[currentIndex+1], 3, &infovar);
	         Tcl_ObjSetVar2 (interp, infovar, NULL, errorInfo, 0);

	       }
	
	       /*
	        * call body; the error code of this body takes precedence
	        */
	
	       res = Tcl_EvalObjEx (interp, objv[currentIndex+2], 0);

	     }
	
	     /*
	      * pop error data from stack
	      */
	
	     Tcl_ListObjLength (interp, myTsd->errorMsgStack, &stackLength);
	     stackLength--;
	     Tcl_ListObjReplace (interp, myTsd->errorMsgStack,
	                         stackLength, 1, 0, NULL);
	     Tcl_ListObjReplace (interp, myTsd->errorCodeStack,
	                         stackLength, 1, 0, NULL);
	     Tcl_ListObjReplace (interp, myTsd->errorInfoStack,
	                         stackLength, 1, 0, NULL);

	   }
	
	   /*
	    * Execute finally body. Preserve errorCode and friends; they might
	    * be corrupted by the code in the body - e.g. by a try in the code,
	    * or in a proc called by the code.
	    */
	
	   if (finallyIndex != -1) {
	     Tcl_Obj *errorCode, *errorInfo, *errorMsg;
	     int finallyres, origres=res;
	
	     errorMsg = Tcl_GetObjResult (interp);
	     Tcl_IncrRefCount (errorMsg);
	
	     if (origres == TCL_ERROR) {
	       errorCode = Tcl_ObjGetVar2 (interp, myTsd->errorCodeName, NULL,
	                                   TCL_GLOBAL_ONLY);
	       errorInfo = Tcl_ObjGetVar2 (interp, myTsd->errorInfoName, NULL,
	                                   TCL_GLOBAL_ONLY);
	       Tcl_IncrRefCount (errorCode);
	       Tcl_IncrRefCount (errorInfo);

	     }
	
	     finallyres = Tcl_EvalObjEx (interp, objv[finallyIndex+1], 0);
	
	     /*
	      * An Error in the finally clause takes precedence, else restore
	      * previous error data
	      */
	
	     if (finallyres != TCL_OK) {
	       res = finallyres;

	     }
	     else {
	       Tcl_SetObjResult (interp, errorMsg);
	
	       if (origres == TCL_ERROR) {
	         Tcl_SetObjErrorCode (interp, errorCode);
	 #ifdef _TCLINT
	         Tcl_ObjSetVar2 (interp, myTsd->errorInfoName, NULL, errorInfo,
	                         TCL_GLOBAL_ONLY);
	         interp->flags = ERR_IN_PROGRESS;
	 #else
	         Tcl_AddErrorInfo (interp, Tcl_GetStringFromObj (errorInfo, NULL));
	 #endif


	       }
	     }
	
	     Tcl_DecrRefCount (errorMsg);
	
	     if (origres == TCL_ERROR) {
	       Tcl_DecrRefCount (errorCode);
	       Tcl_DecrRefCount (errorInfo);


	     }
	   }
	
	   /*
	    * Pass along return code
	    */
	
	   return res;

	 }
	
	 /*
	  * ----------------------------------------------------------------------

	  *
	  * "Main" function, install our commands in the Tcl interpreter

	  *
	  * ----------------------------------------------------------------------
	  */
	
	 #undef TCL_STORAGE_CLASS
	 #define TCL_STORAGE_CLASS DLLEXPORT
	 EXTERN int
	 Trycatch_Init (Tcl_Interp *interp)

	 {
	   TryCatchTsd * myTsd;
	
	 #ifdef USE_TCL_STUBS
	   if (Tcl_InitStubs (interp, TCL_VERSION, 0) == NULL) {
	     return TCL_ERROR;

	   }
	 #else
	   if (Tcl_PkgRequire (interp, "Tcl", TCL_VERSION, 1) == NULL) {
	     return TCL_ERROR;

	   }
	 #endif
	
	   /*
	    * Allocate Tsd
	    */
	
	   myTsd = (TryCatchTsd *) Tcl_Alloc (sizeof (TryCatchTsd));
	   myTsd->errorCodeStack = Tcl_NewObj ();
	   myTsd->errorInfoStack = Tcl_NewObj ();
	   myTsd->errorMsgStack  = Tcl_NewObj ();
	   myTsd->errorCodeName  = Tcl_NewStringObj ("errorCode", -1);
	   myTsd->errorInfoName  = Tcl_NewStringObj ("errorInfo", -1);
	
	   /*
	    * add commands
	    */
	
	   Tcl_CreateObjCommand (interp, "throw", Tcl_ThrowObjCmd,
	                         (ClientData) myTsd, NULL);
	   Tcl_CreateObjCommand (interp, "try", Tcl_TryObjCmd,
	                         (ClientData) myTsd, NULL);
	
	   /*
	    * Ready
	    */
	
	   Tcl_PkgProvide (interp, "trycatch", "0.1");
	   return TCL_OK;

	 }

# Copyright

This document has been placed in the public domain.

Name change from tip/9.tip to tip/9.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
TIP:            9
Title:          Tk Standard Library
Version:        $Revision: 1.9 $
Author:         Marty Backe <[email protected]>
Author:         Larry W. Virden <[email protected]>
Author:         Jeff Hobbs <[email protected]>
State:          Withdrawn
Type:           Project
Vote:           Pending
Created:        07-Nov-2000
Post-History:   
Tcl-Version:    8.4


~ Abstract

A Tk standard library shall be bundled with the core Tcl/Tk
distribution.  The library will consist of general purpose widgets and
composite widgets for use in constructing Tcl/Tk applications.  The
library of Tk components will be written in Tcl/Tk.

~ Rationale

Although Tcl "ships" with a comprehensive set of native (compiled)
base Tk widgets, it lacks a library of composite widgets, from which
sophisticated applications can readily be built with minimal
reinvention.

Although the Tcl community has created a wealth of general purpose Tk
widgets, generally they are not centrally located or distributed,
making their use problematic. This requires that Tcl programs which
make use of such widgets must either distribute them or direct the end
user on their acquisition and installation. Arguably, the success and
higher visibility of other "competing" scripting languages can be
attributed in some part to their extensive libraries. Tcl/Tk should
continue this trend.

Tcl is perhaps unique in that it is considered both a graphical (Tk)
and non-graphical (Tcl) programming language. Work has begun in
implementing a standard library for Tcl. It could be argued that
Tcl/Tk's largest base, and its largest growth area, is with regards to
graphical applications. To this end, Tcl needs a comprehensive, and
well maintained Tk standard library.

Finally, to lower the barrier of using the Tk libraries, they should
be Tcl/Tk based.  This helps to assure cross platform independence
without requiring the user to compile code against a source
distribution.

~ Specification

 * The standard Tk library will be called "tklibX.Y", where "X.Y" will
   follow the version number of the Tcl/Tk distribution that it's
   compatible with.

 * Major/minor releases of the tklib shall coincide with the
   major/minor releases of Tcl/Tk. That is, if Tcl/Tk version 8.5 is
<
|
<
|
|
|
|
|
|
|
|
|
>

|






|

|













|
|










|








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

# TIP 9: Tk Standard Library

	Author:         Marty Backe <[email protected]>
	Author:         Larry W. Virden <[email protected]>
	Author:         Jeff Hobbs <[email protected]>
	State:          Withdrawn
	Type:           Project
	Vote:           Pending
	Created:        07-Nov-2000
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

A Tk standard library shall be bundled with the core Tcl/Tk
distribution.  The library will consist of general purpose widgets and
composite widgets for use in constructing Tcl/Tk applications.  The
library of Tk components will be written in Tcl/Tk.

# Rationale

Although Tcl "ships" with a comprehensive set of native \(compiled\)
base Tk widgets, it lacks a library of composite widgets, from which
sophisticated applications can readily be built with minimal
reinvention.

Although the Tcl community has created a wealth of general purpose Tk
widgets, generally they are not centrally located or distributed,
making their use problematic. This requires that Tcl programs which
make use of such widgets must either distribute them or direct the end
user on their acquisition and installation. Arguably, the success and
higher visibility of other "competing" scripting languages can be
attributed in some part to their extensive libraries. Tcl/Tk should
continue this trend.

Tcl is perhaps unique in that it is considered both a graphical \(Tk\)
and non-graphical \(Tcl\) programming language. Work has begun in
implementing a standard library for Tcl. It could be argued that
Tcl/Tk's largest base, and its largest growth area, is with regards to
graphical applications. To this end, Tcl needs a comprehensive, and
well maintained Tk standard library.

Finally, to lower the barrier of using the Tk libraries, they should
be Tcl/Tk based.  This helps to assure cross platform independence
without requiring the user to compile code against a source
distribution.

# Specification

 * The standard Tk library will be called "tklibX.Y", where "X.Y" will
   follow the version number of the Tcl/Tk distribution that it's
   compatible with.

 * Major/minor releases of the tklib shall coincide with the
   major/minor releases of Tcl/Tk. That is, if Tcl/Tk version 8.5 is
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

   by the component. A picture is worth a thousand words! The Tk,
   BWidgets, and Iwidgets demos are prime examples to be emulated.

 * Tklib components can be dependent on other tklib components.  If
   tklib and tcllib become coordinated efforts, the tklib components
   can be dependent on tcllib components.

 * The tklib can (and hopefully will) include megawidgets.

 * Tklib components shall be written in Tcl/Tk.

 * Tklib components shall be implemented in their own namespace and
   distributed in package form.

 * Tklib components do not have to be unique with regards to other
   tklib components, although there shall be differentiating
   characteristics between them. There is more then one way to skin a
   cat.

 * The tklib shall not contain applications, IDEs, or development
   tools.

~ Notes

A tklib module has been created next to the aforementioned tcllib at
http://tcllib.sf.net/  This creates the basic infrastructure for
people to work in, but does not set any status related to the core as
yet.

----

''Larry W. Virden writes'':

 > It appears to me that tklib isn't going to be bundled with the tk
   source code distribution any more than tcllib getting distributed
   with the tcl core distribution.

 > If the TCT concurs that this is the case, then I would propose that
   this TIP be withdrawn.  tklib exists now, and to date, submissions
   are extremely rare.

 > Here we are, some time later, and no action still on either
   withdrawing or rejecting this TIP.  Perhaps some action could be
   taken on this TIP?

----

~ Copyright

This document has been placed in the public domain.








|














|


|





|















|


>
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
   by the component. A picture is worth a thousand words! The Tk,
   BWidgets, and Iwidgets demos are prime examples to be emulated.

 * Tklib components can be dependent on other tklib components.  If
   tklib and tcllib become coordinated efforts, the tklib components
   can be dependent on tcllib components.

 * The tklib can \(and hopefully will\) include megawidgets.

 * Tklib components shall be written in Tcl/Tk.

 * Tklib components shall be implemented in their own namespace and
   distributed in package form.

 * Tklib components do not have to be unique with regards to other
   tklib components, although there shall be differentiating
   characteristics between them. There is more then one way to skin a
   cat.

 * The tklib shall not contain applications, IDEs, or development
   tools.

# Notes

A tklib module has been created next to the aforementioned tcllib at
<http://tcllib.sf.net/>  This creates the basic infrastructure for
people to work in, but does not set any status related to the core as
yet.

----

_Larry W. Virden writes_:

 > It appears to me that tklib isn't going to be bundled with the tk
   source code distribution any more than tcllib getting distributed
   with the tcl core distribution.

 > If the TCT concurs that this is the case, then I would propose that
   this TIP be withdrawn.  tklib exists now, and to date, submissions
   are extremely rare.

 > Here we are, some time later, and no action still on either
   withdrawing or rejecting this TIP.  Perhaps some action could be
   taken on this TIP?

----

# Copyright

This document has been placed in the public domain.

Name change from tip/90.tip to tip/90.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248

249
250
251
252
253

254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271

272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297

298
299
300

301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316

317
318
319
320
321


322
323
324
325
326
327
328
329
330
331
332
333
334

335
336

337
338

339
340
341
342
343
344
345
346
347
348
349
350

351
352
353
354
355
356
357
358

359
360
361
362
363


364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415

416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502

TIP:            90
Title:          Enable [return -code] in Control Structure Procs
Version:        $Revision: 1.39 $
Author:         Don Porter <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        15-Mar-2002
Post-History:   
Tcl-Version:    8.5


~ Abstract

This TIP analyzes existing limitations on the coding of control
structure commands as ''proc''s, and presents expanded forms of
''catch'' and ''return'' to remove those limitations.

~ Background

It is a distinguishing feature of Tcl that everything is a command,
including control structure functionality that in many other languages
are part of the language itself, such as ''if'', ''for'', and
''switch''.  The command interface of Tcl, including both a return
code and a result, allows extensions to create their own control
structure commands.

Control structure commands have the feature that one or more of their
arguments is a script, often called a ''body'', meant to be evaluated
in the caller's context.  The control structure command exists to
control whether, when, in what context, or how many times that script
is evaluated.  When the body is evaluated, however, it is intended to
behave as if it were interpreted directly in the place of the control
structure command.

The built-in commands of Tcl provide the ability for scripts
themselves to define new commands.  Notably, the ''proc'' command
makes this possible.  In addition, other commands such as ''catch'',
''return'', ''uplevel'', and ''upvar'' offer enough control and access
to the caller's context that it is possible to create new control
structure commands for Tcl, entirely at the script level.

Almost.

There is one limitation that separates control structure commands
created by ''proc'' from those created in C by a direct call to
''Tcl_Create(Obj)Command''.  It is most easily seen in the following
example that compares the built-in command ''while'' to the command
''control::do'' created by ''proc'' in the control package of tcllib.

|  % package require control
|  % proc a {} {while 1 {return -code error}}
|  % proc b {} {control::do {return -code error} while 1}
|  % catch a
|  1

|  % catch b
|  0


The control structure command ''control::do'' fails to evaluate
''return -code error'' in such a way that it acts the same as if
''return -code error'' was evaluated directly within proc ''b''.

~ Analysis

There are two deficiencies in Tcl's built-in commands that lead to
this incapacity in control structure commands defined by ''proc''.

First, ''catch'' is not able to capture the information.  Consider:

|   %  set code [catch {
|          return -code error -errorinfo foo -errorcode bar baz
|      } message]

After evaluation, ''code'' contains "2" (''TCL_RETURN''), and
''message'' contains "baz", but the other values are locked away in
internal fields of the ''Tcl_Interp'' structure as
''interp->returnCode'', ''interp->errorCode'', and 
''interp->errorInfo''.  The "-errorcode" and "-errorinfo" values
will be copied to the global variables "::errorCode" and 
"::errorInfo", respectively, but there will be no way at the
script level to get at the ''interp->returnCode'' value which
was the value of the original "-code" option.

Second, even if the information were available, there is no built-in
command in Tcl that can be evaluated within the body of a proc to make
the proc itself act as if it were the command ''return -code''.
Stated another way, it is not possible to create a command with
''proc'' that behaves exactly the same as ''return -code''.  Because
of that, it is also not possible to create a command with ''proc''
that behaves exactly the same as ''while'', ''if'', etc. - any
command that evaluates any of its arguments as a script in the
caller's context.

This is a curious, and likely unintentional, limitation.  Tcl goes to
great lengths to be sure I can create my own ''break'' replacement
with ''proc''.

| proc myBreak {} {return -code break}

It would be a welcome completion of Tcl's set of built-in commands to
be able to create a replacement for every one of them using ''proc''.

~ Specification

The ''return'' command shall have syntax:

| return ?option value ...? ?result?

There can be any number of ''option value'' pairs, and
any value at all is acceptable for an ''option'' argument.
The legal values of a ''value'' argument are limited for
some ''option''s, as follows:

 > the ''value'' after a "-code" must be either
   an integer (32-bit only), or one of the strings, "ok",
   "error", "return", "break", or "continue",
   just as in the 8.4 spec for ''return''.  The default ''value''
   for the "-code" option is "0".

 > the ''value'' after a "-level" must be a non-negative integer.
   The default ''value'' for the "-level" option is "1".

 > the ''value'' after a "-options" must be a dictionary ([111]).
   The default ''value'' for the "-options" option is an empty
   dictionary.

The keys and values in the dictionary ''value'' of the "-options"
option are pulled out and treated as additional ''option value''
arguments to the ''return'' command.  Note that this "-options" option
for option expansion is offered only because Tcl itself has no
syntax for argument expansion, as observed many,
many times before (for example, [103]).

The ''result'' argument, if any, is stored in the interp as the
result of the ''return'' command.  In default operation, this
becomes the result of the procedure in which the ''return'' command
is evaluated.

The return code of the ''return'' command is determined by the
''value''s of the "-code" and "-level" options.  If the ''value''
of the "-level" option is non-zero, then the return code of
''return'' is TCL_RETURN.  If the ''value'' of the "-level" option
is "0", then the return code of ''return'' is the ''value'' of the
"-code" option, translated from string, as needed.  In this way,

| return -level 0 -code break

is a synonym for

| break

while

| return -code break

spelled out with defaults filled in as:

| return -level 1 -code break

continues to function as before, causing the procedure in which
the ''return'' is evaluated to return the TCL_BREAK return code.

All ''option value'' arguments to ''return'' are stored in a
return options dictionary kept in the interp, just as the
''result'' argument gets stored in the result of the interp.

The TclUpdateReturnInfo() function is modified, so that each
level of procedure returning decrements the value of the "-level"
key in the return options dictionary.  When the value of the
"-level" key reaches "0", the return code from the current procedure
will be the value of the "-code" key in the return options dictionary.
Otherwise, the return code of the current procedure will be TCL_RETURN.

In this way,

| return -level 2 -code ok

is equivalent to

| return -code return

and should (absent some intervening ''catch'') cause a normal return
to the caller's caller.  Likewise,

| return -level 3 -code ok

would cause a normal return to the caller's caller's caller
(again absent an intervening ''catch''), something
that can't currently be accomplished.

The ''catch'' command shall have syntax:

| catch script ?resultVar? ?optionsVar?

The new argument ''optionsVar'', if present, will be the
name of a variable in which a dictionary of return options
should be stored.  The return options stored in that dictionary
are exactly those needed so that the evaluation of

| catch $script result options
| return -options $options $result

is completely indistinguishable (except for the existence
and values of variables "result" and "options") from the
direct evaluation of ''$script'' by the interpreter.  In
particular, any values of the "::errorCode" and "::errorInfo"
variables are the same as if there were never a ''catch'' in
the first place.

In addition, when the result of ''catch'' is TCL_ERROR, the
value in the ''errorLine'' field of the ''Interp'' struct
will be stored as the value of the "-errorline" key in the
return options dictionary.

This specification may seem a bit complex, but it makes possible
very simple solutions to the problems posed above.

~ Examples

First lets revisit the analysis:

|   %  set code [catch {
|          return -code error -errorinfo foo -errorcode bar baz
|      } message options]

After evaluation, ''code'' contains "2" (''TCL_RETURN''), ''message''
contains "baz", and now ''options'' contains:

| -errorcode bar -errorinfo foo -code 1 -level 1

So, the ''options'' variable now contains the information that
was previously inaccessible.  We can now

| return -options $options $message

to get the same results as if the ''catch'' had never been
there in the first place.

In 8.4 Tcl, it is not possible to implement a replacement
for the ''return'' command as a proc.  After this proposal,
such a replacement is:

| proc myReturn args {
|     set result ""
|     if {[llength $args] % 2} {
|         set result [lindex $args end]
|         set args [lrange $args 0 end-1]
|     }

|     set options [eval [list dict create -level 1] $args]
|     dict incr options -level
|     return -options $options $result
| }


In every way ''myReturn'' should be an equivalent to ''return''.

The new ability to exactly reproduce stack traces makes a
''catch'' of large scripts more attractive.  For example, a
procedure that allocates some resource, then performs operations,
and finally frees the resource before returning.  In order to
be sure the resource is freed, we must ''catch'' any errors
that might cause the procedure to return before the freeing
of the resource.  The solution looks like:

| proc doSomething {} {
|     set resource [allocate]
|     catch {
|          # Arbitrarily long script of operations
|     } result options
|     deallocate $resource
|     return -options $options $result
| }


With that structure, we are confident the resource is always
freed, but any error or exception will be presented to the
caller exactly as if it had never been caught in the first place.

Here are two examples of how to use the new features in a 
control structure proc.  The essence of a control structure
command is its ability to evaluate a script in the caller's
context, preserving the illusion that no additional stack
frame was ever used.  So, a proc replacement for ''eval''
illustrates the technique.

The first approach assumes one knows
the internal details of how the ''uplevel'' command adds to
the stack trace. This is straightforward, but will require a
rewrite if ''uplevel'' ever changes how it manipulates the
stack trace.

| proc myEval script {
|     if {[catch {uplevel 1 $script} result options] == 1} {
|         set stack [dict get $options -errorinfo]
|         regsub {\s+invoked from within\s+"uplevel 1 \$script"$} $stack {} stack
|         regsub {\("uplevel" body line (\d+)\)$} $stack [subst -nobackslashes \
|                 {("[lindex [info level 0] 0]" body line \1)}] stack
|         dict set options -errorinfo $stack
|     }

|     dict incr options -level
|     return -options $options $result
| }


A second, more robust solution is possible, but requires a bit
more context gymnastics.

| namespace eval control {
|     proc eval script {
|         variable result
|         variable options
|         set code [uplevel 1 \
|                 [list ::catch $script [namespace which -variable result] \
|                         [namespace which -variable options]]]
|         if {$code == 1} {
|             set line [dict get $options -errorline]
|             dict append options -errorinfo \
|                     "\n    (\"[lindex [info level 0] 0]\" body line $line)"
|         }

|         dict incr options -level
|         return -options $options $result
|     }
| }



Note that in the second solution we did not have to strip away the
contributions of ''uplevel'' to the stack trace, because we captured
the stack trace before ''uplevel'' added anything.  Then we could add
our own information (drawing in part on the new "-errorline" value
available to us now at the script level).

We confirm that either approach solves the original problem:

| % proc a {} {eval {return -code error}}
| % proc b {} {myEval {return -code error}}
| % proc c {} {control::eval {return -code error}}
| % catch a
| 1

| % catch b
| 1

| % catch c
| 1


Finally, the new features make possible a utility command that
can be of use to people making simple control structure commands,
or doing simple wrapping, where there is no need to augment the
stack trace, or to treat any return codes in a special way:

| namespace eval control {
|     proc ascaller script {
|         if {[info level] < 2} {
|             return -code error \
|                     "[lindex [info level 0] 0] called outside a proc"
|         }

|         variable result
|         variable options
|         set code [uplevel 2 \
|                 [list ::catch $script   [namespace which -variable result] \
|                                         [namespace which -variable options]]]
|         if {$code == 0} {
|             return $result
|         }

|         dict incr options -level 2
|         return -options $options $result
|     }
| }



Within a proc, ''ascaller $script'' will take care of all aspects
of evaluating ''$script'' in the caller context, and exiting as
appropriate for all non-TCL_OK return codes.

~ Extensibility

The ''return -code'' command has always accepted any integer value
as a valid argument, allowing package and application authors to
define their own new return codes as needed by their own control
structure commands.  Now that ''return'' will accept any ''option''
argument, and ''catch'' can capture all ''option value'' argument
pairs passed to the caught ''return'' command, package and application
authors now have the ability to augment their custom return codes
with additional data.  Some prefix convention should be established
to avoid key name conflicts in the return options dictionary.

~ Potential Concerns

Reviewers of drafts of this TIP wondered whether the new
"-level" option to ''return'' raised the possibility of
trouble with an attempt to return more levels than beyond
the top of the call stack.  

It should be understood that ''return -level N'' does not
take any shortcut past the intervening levels.  Each level
of the call stack gets a TCL_RETURN return code, and a "-level"
value, dropping by one each step up the stack.  Any level in
the stack might choose to ''catch'' the TCL_RETURN and treat
it as it wishes.  This is exactly the way the existing
''return -code return'' is handled.  Normally, it would cause
a normal return to the caller's caller, but if the caller
chooses to 'catch' it, then the caller has control.

At the toplevel we run out of callers.  Then the question becomes
how is a TCL_RETURN code at toplevel handled?

| % return -level 0       ;# same as a TCL_OK at toplevel
| % return -level 1       ;# same as [return]
| % return -level 2       ;# same as [return -code return]
| command returned bad code: 2

From the C level, ''Tcl_AllowExceptions()'' can be used to
modify this toplevel behavior.

The following proc will produce the same results as above, but
from any level in the call stack (absent an intervening ''catch''):

| % proc escape level {
|       set x [info level]
|       incr x $level
|       return -level $x
|   }

| % escape 0
| % escape 1
| % escape 2
| command returned bad code: 2

Another concern was whether this proposal gave slave interpreters
any new powers over their masters.  The return code from evaluation
of an untrusted script in a slave interpreter should always be
wrapped in a ''catch'' already, lest a TCL_ERROR in the script
blow the stack.  Given that, the only thing this proposal does is
give the ''catch'' command more information to use to decide
how to handle the misbehaving script.

~ Compatibility

It is the author's belief that this proposal is completely
compatible with prior Tcl 8.X releases.  Any error-free script
that ran before, should continue to run with the same results.
At the C level, only internal changes are made, and no new interfaces
are defined.  Any extension or embedding C program that sticks to the
public stubs interface should see no visible change.  

~ Prototype

This proposal is implemented by Tcl Patch 531640 at SourceForge.

The prototype covers all described functionality, but might be
further improved with more substantial bytecompiling of [return].

~ Future considerations

The main reason the global variables ''::errorInfo'' and
''::errorCode'' exist is to give the script level access to
stack and error code information following the ''catch''
of a script that raises an error.  After this proposal, the
''catch'' command itself provides access to that information,
so the global variables are not required.  One can imagine
deprecating them, asking users of Tcl 8.5 to stop writing
code that accesses them.  They could still have apparent
existence, to satisfy the needs of scripts written for earlier
Tcl 8.X releases, by means of read traces.  In time,
Tcl 9 could either continue the read trace scheme, or not
provide these global variables at all.

One part of Tcl itself that currently makes use of the
''::errorCode'' and ''::errorInfo'' variables is the
''bgerror'' command.  Currently, ''bgerror'' accepts exactly
one argument, the error message.  To make use of stack or
error code information, ''bgerror'' must retrieve them from
the global variables.  The proper values of these global
variables are re-set by ''Tcl_BackgroundError()'' prior to
evaluation of ''bgerror''.

As an alternative, ''Tcl_BackgroundError()'' could first attempt
to call ''bgerror'' with ''two'' arguments, first the message,
then a dictionary of options.  If that call returned TCL_ERROR,
then a second attempt could be made with a single message
argument.  In that way, cleaner ''bgerror'' commands that get
all data from arguments could be supported, while still keeping
support for those ''bgerror'' commands that were defined for
single argument use.

It has been noted several times that the processing of the
value of ''::errorInfo'' is rather difficult because it is
an arbitrary string with no documented structure.  A different,
more structured way of representing stack trace information would
be an improvement.  This proposal does not propose an alternative,
but because it offers an extensible dictionary for storing arbitrary
return options data, it does provide an infrastructure where such
approaches might be tried out.

~ Acknowledgments

This proposal is a synthesis of ideas from many sources.  As best
I can recall, major contributions came from Joe English, Andreas
Leitgeb, Reinhard Max, and Kevin Kenny.  If you like the idea,
give them some credit; it you don't, blame me for combining the
ideas badly.

~ See also

Documentation for tcllib's control package: 
http://tcllib.sf.net/doc/control.html

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
>

|


|
|

|



|
|




|







|
|
|






|
|
|
|

|
|
|
|
<
>
|
<
|
>
|
|
|

|


|

|

|
|
|

|
|
|
|
|


|




|

|
|
|




|
|

|


|

|

|

|

|
|
|
|

|
|

|


|
|

|
|


|
|
|


|

|
|
|


|
|

|
|


|



|



|



|


|

|

|

|




|



|



|

|


|


|


|

|

|




|
|

|
|
|

|


|
|






|



|
|
|

|
|

|

|


|

|



|


|
|
|
|
|
<
>
|
|
|
<
|
>
|


|


|



|
|
|
|
|
|
|
<
>









|



|

|


|
|
|
|
|
|
|
<
>
|
|
<
>




|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
<
<
|
>
>

|
|
|
|



|
|
|
|
<
>
|
<
>
|
<
>






|
|
|
|
|
<
>
|
|
|
|
|
|
|
<
>
|
|
<
<
|
>
>
|
|
|

|

|


|
|
|




|


|



|

|

|

|




|

|
|
|
|

|



|

|
|
|
|
<
>
|
|
|
|




|

|


|








|






|

|
|
|

|









|
|

|

|
|

|
|
|

|

|



|







|







|


|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246

247
248
249
250

251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269

270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295

296
297
298

299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314

315
316
317


318
319
320
321
322
323
324
325
326
327
328
329
330
331
332

333
334

335
336

337
338
339
340
341
342
343
344
345
346
347
348

349
350
351
352
353
354
355
356

357
358
359


360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413

414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502

# TIP 90: Enable [return -code] in Control Structure Procs

	Author:         Don Porter <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        15-Mar-2002
	Post-History:   
	Tcl-Version:    8.5
-----

# Abstract

This TIP analyzes existing limitations on the coding of control
structure commands as _proc_s, and presents expanded forms of
_catch_ and _return_ to remove those limitations.

# Background

It is a distinguishing feature of Tcl that everything is a command,
including control structure functionality that in many other languages
are part of the language itself, such as _if_, _for_, and
_switch_.  The command interface of Tcl, including both a return
code and a result, allows extensions to create their own control
structure commands.

Control structure commands have the feature that one or more of their
arguments is a script, often called a _body_, meant to be evaluated
in the caller's context.  The control structure command exists to
control whether, when, in what context, or how many times that script
is evaluated.  When the body is evaluated, however, it is intended to
behave as if it were interpreted directly in the place of the control
structure command.

The built-in commands of Tcl provide the ability for scripts
themselves to define new commands.  Notably, the _proc_ command
makes this possible.  In addition, other commands such as _catch_,
_return_, _uplevel_, and _upvar_ offer enough control and access
to the caller's context that it is possible to create new control
structure commands for Tcl, entirely at the script level.

Almost.

There is one limitation that separates control structure commands
created by _proc_ from those created in C by a direct call to
_Tcl\_Create\(Obj\)Command_.  It is most easily seen in the following
example that compares the built-in command _while_ to the command
_control::do_ created by _proc_ in the control package of tcllib.

	  % package require control
	  % proc a {} {while 1 {return -code error}}
	  % proc b {} {control::do {return -code error} while 1}
	  % catch a

	  1
	  % catch b

	  0

The control structure command _control::do_ fails to evaluate
_return -code error_ in such a way that it acts the same as if
_return -code error_ was evaluated directly within proc _b_.

# Analysis

There are two deficiencies in Tcl's built-in commands that lead to
this incapacity in control structure commands defined by _proc_.

First, _catch_ is not able to capture the information.  Consider:

	   %  set code [catch {
	          return -code error -errorinfo foo -errorcode bar baz
	      } message]

After evaluation, _code_ contains "2" \(_TCL\_RETURN_\), and
_message_ contains "baz", but the other values are locked away in
internal fields of the _Tcl\_Interp_ structure as
_interp->returnCode_, _interp->errorCode_, and 
_interp->errorInfo_.  The "-errorcode" and "-errorinfo" values
will be copied to the global variables "::errorCode" and 
"::errorInfo", respectively, but there will be no way at the
script level to get at the _interp->returnCode_ value which
was the value of the original "-code" option.

Second, even if the information were available, there is no built-in
command in Tcl that can be evaluated within the body of a proc to make
the proc itself act as if it were the command _return -code_.
Stated another way, it is not possible to create a command with
_proc_ that behaves exactly the same as _return -code_.  Because
of that, it is also not possible to create a command with _proc_
that behaves exactly the same as _while_, _if_, etc. - any
command that evaluates any of its arguments as a script in the
caller's context.

This is a curious, and likely unintentional, limitation.  Tcl goes to
great lengths to be sure I can create my own _break_ replacement
with _proc_.

	 proc myBreak {} {return -code break}

It would be a welcome completion of Tcl's set of built-in commands to
be able to create a replacement for every one of them using _proc_.

# Specification

The _return_ command shall have syntax:

	 return ?option value ...? ?result?

There can be any number of _option value_ pairs, and
any value at all is acceptable for an _option_ argument.
The legal values of a _value_ argument are limited for
some _option_s, as follows:

 > the _value_ after a "-code" must be either
   an integer \(32-bit only\), or one of the strings, "ok",
   "error", "return", "break", or "continue",
   just as in the 8.4 spec for _return_.  The default _value_
   for the "-code" option is "0".

 > the _value_ after a "-level" must be a non-negative integer.
   The default _value_ for the "-level" option is "1".

 > the _value_ after a "-options" must be a dictionary \([[111]](111.md)\).
   The default _value_ for the "-options" option is an empty
   dictionary.

The keys and values in the dictionary _value_ of the "-options"
option are pulled out and treated as additional _option value_
arguments to the _return_ command.  Note that this "-options" option
for option expansion is offered only because Tcl itself has no
syntax for argument expansion, as observed many,
many times before \(for example, [[103]](103.md)\).

The _result_ argument, if any, is stored in the interp as the
result of the _return_ command.  In default operation, this
becomes the result of the procedure in which the _return_ command
is evaluated.

The return code of the _return_ command is determined by the
_value_s of the "-code" and "-level" options.  If the _value_
of the "-level" option is non-zero, then the return code of
_return_ is TCL\_RETURN.  If the _value_ of the "-level" option
is "0", then the return code of _return_ is the _value_ of the
"-code" option, translated from string, as needed.  In this way,

	 return -level 0 -code break

is a synonym for

	 break

while

	 return -code break

spelled out with defaults filled in as:

	 return -level 1 -code break

continues to function as before, causing the procedure in which
the _return_ is evaluated to return the TCL\_BREAK return code.

All _option value_ arguments to _return_ are stored in a
return options dictionary kept in the interp, just as the
_result_ argument gets stored in the result of the interp.

The TclUpdateReturnInfo\(\) function is modified, so that each
level of procedure returning decrements the value of the "-level"
key in the return options dictionary.  When the value of the
"-level" key reaches "0", the return code from the current procedure
will be the value of the "-code" key in the return options dictionary.
Otherwise, the return code of the current procedure will be TCL\_RETURN.

In this way,

	 return -level 2 -code ok

is equivalent to

	 return -code return

and should \(absent some intervening _catch_\) cause a normal return
to the caller's caller.  Likewise,

	 return -level 3 -code ok

would cause a normal return to the caller's caller's caller
\(again absent an intervening _catch_\), something
that can't currently be accomplished.

The _catch_ command shall have syntax:

	 catch script ?resultVar? ?optionsVar?

The new argument _optionsVar_, if present, will be the
name of a variable in which a dictionary of return options
should be stored.  The return options stored in that dictionary
are exactly those needed so that the evaluation of

	 catch $script result options
	 return -options $options $result

is completely indistinguishable \(except for the existence
and values of variables "result" and "options"\) from the
direct evaluation of _$script_ by the interpreter.  In
particular, any values of the "::errorCode" and "::errorInfo"
variables are the same as if there were never a _catch_ in
the first place.

In addition, when the result of _catch_ is TCL\_ERROR, the
value in the _errorLine_ field of the _Interp_ struct
will be stored as the value of the "-errorline" key in the
return options dictionary.

This specification may seem a bit complex, but it makes possible
very simple solutions to the problems posed above.

# Examples

First lets revisit the analysis:

	   %  set code [catch {
	          return -code error -errorinfo foo -errorcode bar baz
	      } message options]

After evaluation, _code_ contains "2" \(_TCL\_RETURN_\), _message_
contains "baz", and now _options_ contains:

	 -errorcode bar -errorinfo foo -code 1 -level 1

So, the _options_ variable now contains the information that
was previously inaccessible.  We can now

	 return -options $options $message

to get the same results as if the _catch_ had never been
there in the first place.

In 8.4 Tcl, it is not possible to implement a replacement
for the _return_ command as a proc.  After this proposal,
such a replacement is:

	 proc myReturn args {
	     set result ""
	     if {[llength $args] % 2} {
	         set result [lindex $args end]
	         set args [lrange $args 0 end-1]

	     }
	     set options [eval [list dict create -level 1] $args]
	     dict incr options -level
	     return -options $options $result

	 }

In every way _myReturn_ should be an equivalent to _return_.

The new ability to exactly reproduce stack traces makes a
_catch_ of large scripts more attractive.  For example, a
procedure that allocates some resource, then performs operations,
and finally frees the resource before returning.  In order to
be sure the resource is freed, we must _catch_ any errors
that might cause the procedure to return before the freeing
of the resource.  The solution looks like:

	 proc doSomething {} {
	     set resource [allocate]
	     catch {
	          # Arbitrarily long script of operations
	     } result options
	     deallocate $resource
	     return -options $options $result

	 }

With that structure, we are confident the resource is always
freed, but any error or exception will be presented to the
caller exactly as if it had never been caught in the first place.

Here are two examples of how to use the new features in a 
control structure proc.  The essence of a control structure
command is its ability to evaluate a script in the caller's
context, preserving the illusion that no additional stack
frame was ever used.  So, a proc replacement for _eval_
illustrates the technique.

The first approach assumes one knows
the internal details of how the _uplevel_ command adds to
the stack trace. This is straightforward, but will require a
rewrite if _uplevel_ ever changes how it manipulates the
stack trace.

	 proc myEval script {
	     if {[catch {uplevel 1 $script} result options] == 1} {
	         set stack [dict get $options -errorinfo]
	         regsub {\s+invoked from within\s+"uplevel 1 \$script"$} $stack {} stack
	         regsub {\("uplevel" body line (\d+)\)$} $stack [subst -nobackslashes \
	                 {("[lindex [info level 0] 0]" body line \1)}] stack
	         dict set options -errorinfo $stack

	     }
	     dict incr options -level
	     return -options $options $result

	 }

A second, more robust solution is possible, but requires a bit
more context gymnastics.

	 namespace eval control {
	     proc eval script {
	         variable result
	         variable options
	         set code [uplevel 1 \
	                 [list ::catch $script [namespace which -variable result] \
	                         [namespace which -variable options]]]
	         if {$code == 1} {
	             set line [dict get $options -errorline]
	             dict append options -errorinfo \
	                     "\n    (\"[lindex [info level 0] 0]\" body line $line)"

	         }
	         dict incr options -level
	         return -options $options $result


	     }
	 }

Note that in the second solution we did not have to strip away the
contributions of _uplevel_ to the stack trace, because we captured
the stack trace before _uplevel_ added anything.  Then we could add
our own information \(drawing in part on the new "-errorline" value
available to us now at the script level\).

We confirm that either approach solves the original problem:

	 % proc a {} {eval {return -code error}}
	 % proc b {} {myEval {return -code error}}
	 % proc c {} {control::eval {return -code error}}
	 % catch a

	 1
	 % catch b

	 1
	 % catch c

	 1

Finally, the new features make possible a utility command that
can be of use to people making simple control structure commands,
or doing simple wrapping, where there is no need to augment the
stack trace, or to treat any return codes in a special way:

	 namespace eval control {
	     proc ascaller script {
	         if {[info level] < 2} {
	             return -code error \
	                     "[lindex [info level 0] 0] called outside a proc"

	         }
	         variable result
	         variable options
	         set code [uplevel 2 \
	                 [list ::catch $script   [namespace which -variable result] \
	                                         [namespace which -variable options]]]
	         if {$code == 0} {
	             return $result

	         }
	         dict incr options -level 2
	         return -options $options $result


	     }
	 }

Within a proc, _ascaller $script_ will take care of all aspects
of evaluating _$script_ in the caller context, and exiting as
appropriate for all non-TCL\_OK return codes.

# Extensibility

The _return -code_ command has always accepted any integer value
as a valid argument, allowing package and application authors to
define their own new return codes as needed by their own control
structure commands.  Now that _return_ will accept any _option_
argument, and _catch_ can capture all _option value_ argument
pairs passed to the caught _return_ command, package and application
authors now have the ability to augment their custom return codes
with additional data.  Some prefix convention should be established
to avoid key name conflicts in the return options dictionary.

# Potential Concerns

Reviewers of drafts of this TIP wondered whether the new
"-level" option to _return_ raised the possibility of
trouble with an attempt to return more levels than beyond
the top of the call stack.  

It should be understood that _return -level N_ does not
take any shortcut past the intervening levels.  Each level
of the call stack gets a TCL\_RETURN return code, and a "-level"
value, dropping by one each step up the stack.  Any level in
the stack might choose to _catch_ the TCL\_RETURN and treat
it as it wishes.  This is exactly the way the existing
_return -code return_ is handled.  Normally, it would cause
a normal return to the caller's caller, but if the caller
chooses to 'catch' it, then the caller has control.

At the toplevel we run out of callers.  Then the question becomes
how is a TCL\_RETURN code at toplevel handled?

	 % return -level 0       ;# same as a TCL_OK at toplevel
	 % return -level 1       ;# same as [return]
	 % return -level 2       ;# same as [return -code return]
	 command returned bad code: 2

From the C level, _Tcl\_AllowExceptions\(\)_ can be used to
modify this toplevel behavior.

The following proc will produce the same results as above, but
from any level in the call stack \(absent an intervening _catch_\):

	 % proc escape level {
	       set x [info level]
	       incr x $level
	       return -level $x

	   }
	 % escape 0
	 % escape 1
	 % escape 2
	 command returned bad code: 2

Another concern was whether this proposal gave slave interpreters
any new powers over their masters.  The return code from evaluation
of an untrusted script in a slave interpreter should always be
wrapped in a _catch_ already, lest a TCL\_ERROR in the script
blow the stack.  Given that, the only thing this proposal does is
give the _catch_ command more information to use to decide
how to handle the misbehaving script.

# Compatibility

It is the author's belief that this proposal is completely
compatible with prior Tcl 8.X releases.  Any error-free script
that ran before, should continue to run with the same results.
At the C level, only internal changes are made, and no new interfaces
are defined.  Any extension or embedding C program that sticks to the
public stubs interface should see no visible change.  

# Prototype

This proposal is implemented by Tcl Patch 531640 at SourceForge.

The prototype covers all described functionality, but might be
further improved with more substantial bytecompiling of [return].

# Future considerations

The main reason the global variables _::errorInfo_ and
_::errorCode_ exist is to give the script level access to
stack and error code information following the _catch_
of a script that raises an error.  After this proposal, the
_catch_ command itself provides access to that information,
so the global variables are not required.  One can imagine
deprecating them, asking users of Tcl 8.5 to stop writing
code that accesses them.  They could still have apparent
existence, to satisfy the needs of scripts written for earlier
Tcl 8.X releases, by means of read traces.  In time,
Tcl 9 could either continue the read trace scheme, or not
provide these global variables at all.

One part of Tcl itself that currently makes use of the
_::errorCode_ and _::errorInfo_ variables is the
_bgerror_ command.  Currently, _bgerror_ accepts exactly
one argument, the error message.  To make use of stack or
error code information, _bgerror_ must retrieve them from
the global variables.  The proper values of these global
variables are re-set by _Tcl\_BackgroundError\(\)_ prior to
evaluation of _bgerror_.

As an alternative, _Tcl\_BackgroundError\(\)_ could first attempt
to call _bgerror_ with _two_ arguments, first the message,
then a dictionary of options.  If that call returned TCL\_ERROR,
then a second attempt could be made with a single message
argument.  In that way, cleaner _bgerror_ commands that get
all data from arguments could be supported, while still keeping
support for those _bgerror_ commands that were defined for
single argument use.

It has been noted several times that the processing of the
value of _::errorInfo_ is rather difficult because it is
an arbitrary string with no documented structure.  A different,
more structured way of representing stack trace information would
be an improvement.  This proposal does not propose an alternative,
but because it offers an extensible dictionary for storing arbitrary
return options data, it does provide an infrastructure where such
approaches might be tried out.

# Acknowledgments

This proposal is a synthesis of ideas from many sources.  As best
I can recall, major contributions came from Joe English, Andreas
Leitgeb, Reinhard Max, and Kevin Kenny.  If you like the idea,
give them some credit; it you don't, blame me for combining the
ideas badly.

# See also

Documentation for tcllib's control package: 
<http://tcllib.sf.net/doc/control.html>

# Copyright

This document has been placed in the public domain.

Name change from tip/91.tip to tip/91.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

TIP:		91
Title:		Backward Compatibility for Channel Types with 32-bit SeekProcs
State:		Final
Type:		Project
Tcl-Version:	8.4
Vote:		Done
Post-History:	
Version:	$Revision: 1.5 $
Author:		Donal K. Fellows <[email protected]>
Created:	03-May-2002


~ Abstract

[72] broke backward-compatibility for channels that supported the
[[seek]] command, and this TIP adds the ability for old-style channels
to work with the underlying 64-bit architecture.

~ Rationale

Although the ability to work with large files (as added by [72]) is
crucially useful in many situations, it has introduced a few problems,
one of which being that it broke backward compatibility for channel
types (see
http://sourceforge.net/tracker/?func=detail&atid=410295&aid=551677&group_id=34191
for details.)  Following discussion with the people concerned, I
believe it is possible to modify the channel type structure so that
old-style channels - i.e. those compiled against Tcl 8.3 - can still
be supported (though with a limited range of operation.)

~ Proposed Change

The ''Tcl_ChannelType'' structure will have an extra field appended of
type ''Tcl_DriverWideSeekProc'' called ''wideSeekProc'', which shall
be guaranteed to be present (though possibly NULL) whenever the
version of the ''Tcl_ChannelType'' structure is at least
''TCL_CHANNEL_VERSION_3''.  The type ''Tcl_DriverSeekProc'' shall be
reverted to its pre-[72] version, with the current type of
''Tcl_DriverSeekProc'' being transferred to the type
''Tcl_DriverWideSeekProc''.  In order to facilitate stacked channels,
an additional requirement shall be imposed that if a channel driver
implements a ''wideSeekProc'', then it shall also implement a
''seekProc'', so allowing stacked channels to work entirely in one
domain or the other (well, in simple cases at least.)

Semantically, the core will handle seeks by preferring to use a
''wideSeekProc'' if present, and using the ''seekProc'' otherwise.
Considering just the case where the ''seekProc'' is used, if the
offset argument exceeds that which is representable in a ''long'',
''Tcl_Seek'' will fail, simulating a system error of EOVERFLOW.

The only Tcl core channel which will need modification is the ''file''
channel; this will be adapted to generate an error of EOVERFLOW when
the resulting offset in a file would otherwise exceed that which can
be expressed in a ''long'' (which has the downside of making the seek
operation no longer atomic when using the old interface, since the
file offset will need to be restored to its old position in such
cases.)  On 64-bit platforms, both ''seekProc'' and ''wideSeekProc''
will be the same function.

~ Rejected Alternatives

I considered overloading the ''seekProc'' field to have different
types depending on the value of the ''version'' field, but that's
remarkably ugly and forces people to adapt rapidly at a source level.
I don't know about everyone else, but I don't use a lot of programs at
the moment that actually need access to files larger than 2GB.

I also considered allowing code to only implement the ''wideSeekProc''
but it was easier to code the way I ended up doing it and I don't
think there are that many people writing channel drivers that support
seeking anway.

~ Copyright

This document has been placed in the public domain.

<
|
|
|
|
|
|
<
|
|
>

|

|
|


|

|


|
|
|


|

|

|
|
|
|
|
|
|
|

|
|
|


|
|
|
|

|


|


|


|

|
|




|




|


>

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

# TIP 91: Backward Compatibility for Channel Types with 32-bit SeekProcs
	State:		Final
	Type:		Project
	Tcl-Version:	8.4
	Vote:		Done
	Post-History:	

	Author:		Donal K. Fellows <[email protected]>
	Created:	03-May-2002
-----

# Abstract

[[72]](72.md) broke backward-compatibility for channels that supported the
[seek] command, and this TIP adds the ability for old-style channels
to work with the underlying 64-bit architecture.

# Rationale

Although the ability to work with large files \(as added by [[72]](72.md)\) is
crucially useful in many situations, it has introduced a few problems,
one of which being that it broke backward compatibility for channel
types \(see
<http://sourceforge.net/tracker/?func=detail&atid=410295&aid=551677&group\_id=34191>
for details.\)  Following discussion with the people concerned, I
believe it is possible to modify the channel type structure so that
old-style channels - i.e. those compiled against Tcl 8.3 - can still
be supported \(though with a limited range of operation.\)

# Proposed Change

The _Tcl\_ChannelType_ structure will have an extra field appended of
type _Tcl\_DriverWideSeekProc_ called _wideSeekProc_, which shall
be guaranteed to be present \(though possibly NULL\) whenever the
version of the _Tcl\_ChannelType_ structure is at least
_TCL\_CHANNEL\_VERSION\_3_.  The type _Tcl\_DriverSeekProc_ shall be
reverted to its pre-[[72]](72.md) version, with the current type of
_Tcl\_DriverSeekProc_ being transferred to the type
_Tcl\_DriverWideSeekProc_.  In order to facilitate stacked channels,
an additional requirement shall be imposed that if a channel driver
implements a _wideSeekProc_, then it shall also implement a
_seekProc_, so allowing stacked channels to work entirely in one
domain or the other \(well, in simple cases at least.\)

Semantically, the core will handle seeks by preferring to use a
_wideSeekProc_ if present, and using the _seekProc_ otherwise.
Considering just the case where the _seekProc_ is used, if the
offset argument exceeds that which is representable in a _long_,
_Tcl\_Seek_ will fail, simulating a system error of EOVERFLOW.

The only Tcl core channel which will need modification is the _file_
channel; this will be adapted to generate an error of EOVERFLOW when
the resulting offset in a file would otherwise exceed that which can
be expressed in a _long_ \(which has the downside of making the seek
operation no longer atomic when using the old interface, since the
file offset will need to be restored to its old position in such
cases.\)  On 64-bit platforms, both _seekProc_ and _wideSeekProc_
will be the same function.

# Rejected Alternatives

I considered overloading the _seekProc_ field to have different
types depending on the value of the _version_ field, but that's
remarkably ugly and forces people to adapt rapidly at a source level.
I don't know about everyone else, but I don't use a lot of programs at
the moment that actually need access to files larger than 2GB.

I also considered allowing code to only implement the _wideSeekProc_
but it was easier to code the way I ended up doing it and I don't
think there are that many people writing channel drivers that support
seeking anway.

# Copyright

This document has been placed in the public domain.

Name change from tip/92.tip to tip/92.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
136
137
138

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

TIP:		92
Title:		Move Package Load Decisions to Application Developer
Version:	$Revision: 1.3 $
Author:		Clif Flynt <[email protected]>
State:		Withdrawn
Type:		Project
Vote:		Pending
Created:	13-May-2002
Post-History: 
Tcl-Version:	8.4
Keywords:	package require, namespace, pkg_mkIndex


~ Abstract

This TIP makes the loading of packages far more flexible, so as to
better support their use by application authors in situations above
and beyond those foreseen by the developer of the package.

~ Overview

I believe that we've been misdirecting our efforts in solutions to
the Package issue.

 * The modifications to ''pkg_mkIndex'' give the library author (or
   package builder) the ability to define when a package will be
   loaded (immediate or deferred), which restricts an application
   developer to the decisions made by the library author.

 * If a package is built to be loaded immediately, it is loaded into
   the top-level namespace.  This breaks previous tricks to force a
   package to load inside an existing namespace.

These techniques limit the application writer to the behavior (and
uses) envisioned by the package author and is counter to the concept
that application developer best understands how they need a tool to
perform for their application.  The Tcl community, in particular, has
grown largely because the tools have had applications far beyond those
imagined by their initial developers.

Moving the decisions about when and how to load a package from
''pkg_mkIndex'' to the ''package require'' command allows the
application writer the freedom to find new styles of use that the
package author may not have conceived.

Being able to force an immediate load into the current namespace
rather than always loading packages into the global scope provides
support for lightweight object style data structures without the need
for extensions like Incr Tcl, OOTcl, etc.

Loading a package/namespace into the current namespace provides
mechanisms for lightweight inheritance, and since namespaces can
contain both code and data, loading a namespace multiple times (in
separate namespaces) is a lightweight aggregation model.

I do not propose that this power removes the need for full object
oriented programming models within the Tcl community.  However, I
believe that putting the power to develop these lightweight models
into the application developer provides the developer with a more
versatile tool kit than they currently have.  (One that I've been
using for several years, with workarounds.)

This proposal is to add new flags to the package require command,
allowing an application developer to determine when and how to load a
package.

 -current: Load the package into the current namespace rather than the
	global space.  Implies immediate.

 -multiple: Allow loading multiple copies of this package, for use
	with ''-current'' when the application programmer wishes to
	create multiple nested copies of a package.

 -immediate: Load immediately, rather than defer loading the package
	until needed.  This is the default behavior with Tcl 8.3 and
	later.

 -defer: Load package when required.  The default with Tcl 8.2 and
	earlier, or when ''pkg_mkIndex -lazy'' used with Tcl 8.3.

 -exact: No change to this option.  Requires an exact Major/Minor
	revision match to be an acceptable package.

~ Script Example

The code below implements a simple stack object that can be merged
into other namespaces to create objects that contain individual
stacks.

| package provide stack 1.0
| namespace eval stack {
|     namespace export push pop peek size
|     variable stack ""
|     
|     proc push {val} {
|         variable stack;
|         lappend stack $val
|     }

|      
|     proc pop {} {
|         variable stack;
|         set rtn [lindex $stack end]
|         set stack [lrange $stack 0 end-1]
|         return $rtn
|         }

| 
|     proc peek {{pos end}} {
|         variable stack;
|         return [lindex $stack $pos]
|     }

|      
|     proc size {} {
|         variable stack;
|         return [llength $stack]
|     }

|      
| }

|  

With this data structure available, the guts of a Tower of Hanoi
puzzle becomes simple:

| namespace eval left {
|         package require -current -multiple  stack 1.0
|         namespace import [namespace current]::stack::*
|     }   

| namespace eval center {
|         package require -current -multiple  stack 1.0
|         namespace import [namespace current]::stack::*
|     }

| namespace eval right {
|         package require -current -multiple  stack 1.0
|         namespace import [namespace current]::stack::*
|     }

|      
| proc move {from to} {
|         ${to}::push [${from}::pop]
|     }


This creates 3 'objects' each of which contains a private stack with
the stack methods.

~ Reference Implementation

A reference implementation of the ''-current'' and ''-multiple''
flags has been created for Tcl 8.4a4 and is available at
http://noucorp.com/PkgPatch8.4.zip

The implementation required these modifications to
''generic/tclPkg.c'':

 * ''Tcl_PackageObjCmd'' needs to be able to parse the new options and
   set the bitmapped flag.

 * ''Tcl_PkgRequireEx'' is modified to accept a bitmapped flag instead
   of the ''exact'' option.

 * The 0x0001 bitmap position is used to map for ''exact'' preserving
   the existing behavior of the ''Tcl_PackageObjCmd'' and
   ''Tcl_PkgRequireEx'' functions.

 * These bitmapped flags are defined exact, current, and multiple:

|#define PKG_EXACT    0x01   /* Use the exact version - as used for exact */
|#define PKG_CURRENT  0x02   /* Load into current namespace, not GLOBAL */
|#define PKG_MULTIPLE 0x04   /* Allow loading multiple copies of a package */

 * ''Tcl_PkgRequireEx'' is modified to process the MULTIPLE and
   CURRENT flags.

 * The Tcl tests have been reworked to understand the new error
   returns, etc.  Running "make tests" will accept the new code.

Minimal testing has been done using pure Tcl packages.  

<
|
<
|
|
|
|
|
|
|
|
>

|





|




|
|
|






|
|






|










|
|





|
|









|







|




|





|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
<
>
|
<
>
|




|
|
|
<
>
|
|
|
<
>
|
|
|
<
>
|
|
|
<
|
>



|

|

|


|

|


|
|

|
|
|



|
|
|

|






>

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

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

# TIP 92: Move Package Load Decisions to Application Developer

	Author:		Clif Flynt <[email protected]>
	State:		Withdrawn
	Type:		Project
	Vote:		Pending
	Created:	13-May-2002
	Post-History: 
	Tcl-Version:	8.4
	Keywords:	package require, namespace, pkg_mkIndex
-----

# Abstract

This TIP makes the loading of packages far more flexible, so as to
better support their use by application authors in situations above
and beyond those foreseen by the developer of the package.

# Overview

I believe that we've been misdirecting our efforts in solutions to
the Package issue.

 * The modifications to _pkg\_mkIndex_ give the library author \(or
   package builder\) the ability to define when a package will be
   loaded \(immediate or deferred\), which restricts an application
   developer to the decisions made by the library author.

 * If a package is built to be loaded immediately, it is loaded into
   the top-level namespace.  This breaks previous tricks to force a
   package to load inside an existing namespace.

These techniques limit the application writer to the behavior \(and
uses\) envisioned by the package author and is counter to the concept
that application developer best understands how they need a tool to
perform for their application.  The Tcl community, in particular, has
grown largely because the tools have had applications far beyond those
imagined by their initial developers.

Moving the decisions about when and how to load a package from
_pkg\_mkIndex_ to the _package require_ command allows the
application writer the freedom to find new styles of use that the
package author may not have conceived.

Being able to force an immediate load into the current namespace
rather than always loading packages into the global scope provides
support for lightweight object style data structures without the need
for extensions like Incr Tcl, OOTcl, etc.

Loading a package/namespace into the current namespace provides
mechanisms for lightweight inheritance, and since namespaces can
contain both code and data, loading a namespace multiple times \(in
separate namespaces\) is a lightweight aggregation model.

I do not propose that this power removes the need for full object
oriented programming models within the Tcl community.  However, I
believe that putting the power to develop these lightweight models
into the application developer provides the developer with a more
versatile tool kit than they currently have.  \(One that I've been
using for several years, with workarounds.\)

This proposal is to add new flags to the package require command,
allowing an application developer to determine when and how to load a
package.

 -current: Load the package into the current namespace rather than the
	global space.  Implies immediate.

 -multiple: Allow loading multiple copies of this package, for use
	with _-current_ when the application programmer wishes to
	create multiple nested copies of a package.

 -immediate: Load immediately, rather than defer loading the package
	until needed.  This is the default behavior with Tcl 8.3 and
	later.

 -defer: Load package when required.  The default with Tcl 8.2 and
	earlier, or when _pkg\_mkIndex -lazy_ used with Tcl 8.3.

 -exact: No change to this option.  Requires an exact Major/Minor
	revision match to be an acceptable package.

# Script Example

The code below implements a simple stack object that can be merged
into other namespaces to create objects that contain individual
stacks.

	 package provide stack 1.0
	 namespace eval stack {
	     namespace export push pop peek size
	     variable stack ""
	     
	     proc push {val} {
	         variable stack;
	         lappend stack $val

	     }
	      
	     proc pop {} {
	         variable stack;
	         set rtn [lindex $stack end]
	         set stack [lrange $stack 0 end-1]
	         return $rtn

	         }
	 
	     proc peek {{pos end}} {
	         variable stack;
	         return [lindex $stack $pos]

	     }
	      
	     proc size {} {
	         variable stack;
	         return [llength $stack]

	     }
	      

	 }
	  

With this data structure available, the guts of a Tower of Hanoi
puzzle becomes simple:

	 namespace eval left {
	         package require -current -multiple  stack 1.0
	         namespace import [namespace current]::stack::*

	     }   
	 namespace eval center {
	         package require -current -multiple  stack 1.0
	         namespace import [namespace current]::stack::*

	     }
	 namespace eval right {
	         package require -current -multiple  stack 1.0
	         namespace import [namespace current]::stack::*

	     }
	      
	 proc move {from to} {
	         ${to}::push [${from}::pop]

	     }

This creates 3 'objects' each of which contains a private stack with
the stack methods.

# Reference Implementation

A reference implementation of the _-current_ and _-multiple_
flags has been created for Tcl 8.4a4 and is available at
<http://noucorp.com/PkgPatch8.4.zip>

The implementation required these modifications to
_generic/tclPkg.c_:

 * _Tcl\_PackageObjCmd_ needs to be able to parse the new options and
   set the bitmapped flag.

 * _Tcl\_PkgRequireEx_ is modified to accept a bitmapped flag instead
   of the _exact_ option.

 * The 0x0001 bitmap position is used to map for _exact_ preserving
   the existing behavior of the _Tcl\_PackageObjCmd_ and
   _Tcl\_PkgRequireEx_ functions.

 * These bitmapped flags are defined exact, current, and multiple:

		#define PKG_EXACT    0x01   /* Use the exact version - as used for exact */
		#define PKG_CURRENT  0x02   /* Load into current namespace, not GLOBAL */
		#define PKG_MULTIPLE 0x04   /* Allow loading multiple copies of a package */

 * _Tcl\_PkgRequireEx_ is modified to process the MULTIPLE and
   CURRENT flags.

 * The Tcl tests have been reworked to understand the new error
   returns, etc.  Running "make tests" will accept the new code.

Minimal testing has been done using pure Tcl packages.  

Name change from tip/93.tip to tip/93.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181

182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236

TIP:            93
Title:          Get/Delete Enhancement for the Tk Text Widget
Version:        $Revision: 1.8 $
Author:         Craig Votava <[email protected]>
Author:         Donal K. Fellows <[email protected]>
Author:         Jeff Hobbs <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        28-Dec-2001
Post-History:   
Tcl-Version:    8.4


~ Abstract

The Tk Text widget provides text tags, which are a very powerful
thing.  However, the current implementation does not provide an
efficient way for a Tk Text widget programmer to extract (get) all of
the actual text that has a given text tag.  This TIP proposes to
enhance the Tk Text widget to provide this functionality.

~ Rationale

While writing applications using the Tk Text widget, I find myself
wanting to extract all of the text that has a given text tag.
Although this is possible with the existing functionality of the Tk
Text widget, it can become extremely inefficient, depending on your
application.

Consider the example where we load a text widget with say, the
contents of a scene from a play, and we tag all of the spoken passages
with the name of the character that utters them.  How can we provide
an efficient way to allow an end user to print out all the spoken text
for a single given character?

My initial impulse was to design something like this (please excuse
the use of Perl-Tk syntax, that's what I'm most comfortable with):

|   $txt->tagGet($tag);

The problem with this design is what should this return? A string?  An
list? If a list, should it be a list of each tagged character?  A list
of strings containing all contiguous characters? In addition, Steve
Lidie points out that the corresponding tagDelete() command would
also have to be modified to mimic this change as well. This line of
thought got icky pretty fast.

My second impulse was to try to induce this functionality with as much
existing stuff as possible.  The ''tagRanges'' command returns a list
of index pairs for all contiguous characters with a given tag.  The
thought here was to combine that command with the ''get'' command to
get all the text with a given tag:

|   $txt->get( $txt->tagRanges($tag) );

This design seems to fit in well with much of the existing
functionality of the text widget.  The main problem here is that the
existing ''get'' command only allows for either one or two arguments,
and returns a single string.  For this design to be implemented, the
get interface would need to be enhanced.  This is the design I chose
to implement as a reference (prototype) implementation.  I believe
that the functionality should be provided in the Tk Text widget, and
believe that this prototype solution could be turned into a production
solution.  However those decisions I happily leave up to the Tk
developers who are more knowledgeable about the Tk Text implementation
than myself.

An additional concern here involves the corresponding text delete
command. Should the delete command also be modified in a similar way so
that it has this same functionality too? It seems like it should.

~ Specification

This specification will only describe how the reference implementation
was produced.  If it is decided that an alternate design is needed for
the final production solution, this specification can be scrapped.

The goal of this design is to enhance the Tk Text ''get'' command from
accepting only one or two arguments, to accepting any number of 1
(+NULL) or 2 arguments sets.  The Tcl-Tk manual page description would
change from this:

|   $t get i1 ?i2?

to something like this:

|   $t get i1 ?i2? ?(i3 ?i4? ...)?

By providing this enhancement, we give the programmer with the ability
to efficiently ''get'' all of the text that is tagged with a given
tag.  The programmer would do this by using a compound statement
utilizing the existing ''tag ranges'' command along with the enhanced
''get'' command, as follows (the examples are using the Perl-Tk
syntax):

|   $txt->get( $txt->tagRanges($tag) );

In addition, the enhancement will preserve compatibility with all of
the existing Tk ''get'' commands currently in use.

Currently, the ''get'' command simply returns a single string
containing all of the characters specified by the first and
(optionally) the second argument(s).  The enhanced ''get'' command
will preserve this existing functionality:

|   my $chr = $text->get('1.0');

 > This command functions exactly the same as the original ''get''
   command.  It will return a string containing the first character
   from the first line.

|   my $str = $text->get('1.0', '1.0 lineend');

 > This command functions exactly the same as the original ''get''
   command.  It will return a string containing all of the characters
   on the first line.

However, if the programmer provides more than one or two argument(s),
the enhanced ''get'' command will return a list of strings, just as if
the original ''get'' command was called multiple times and the results
were loaded into a programmer-defined list:

|   my @lines = $text->get('1.0', '1.0 lineend', '2.0');

 > This command returns a list whose first element (''$lines[[0]]'')
   is a string containing all of the characters from the first line,
   and the second element (''$lines[[1]]'') is a string containing
   just the first character of the second line.

|   my @lines = $text->get('1.0', '', '2.0', '2.0 lineend');

 > This command returns a list whose first element (''$lines[[0]]'')
   is a string containing just the first character from the first
   line, and the second element (''$lines[[1]]'') is a string
   containing all of the characters on the second line.

|   my @lines = $text->get('1.0', '1.0 lineend', '2.0', '2.0 lineend');

 > This command returns a list whose first element (''$lines[[0]]'')
   is a string containing the all of the characters from the first
   line, and the second element (''$lines[[1]]'') is a string
   containing all of the characters from the second line.

All of this paves the way for the programmer to use the compound command:

|   my @lines = $txt->get( $txt->tagRanges($tag) );

 > This command returns a list whose elements are strings of all the
   contiguous characters tagged with a given tag.

~ Example

The following Perl-Tk code illustrates how the enhanced ''get''
command could be used with the existing ''tag ranges'' command to
efficiently extract all of the text that is tagged with a given tag.

|   #! /usr/local/bin/perl -w
|   
|   require 5.005;
|   
|   use strict;
|   use English;
|   
|   use Tk;
|   
|   # Create main window with button and text widget in it...
|   my $top = MainWindow->new;
|   my $btn = $top->Button(-text=>'print odd lines')->pack;
|   my $txt = $top->Scrolled('Text', -relief=>'sunken', -borderwidth=>'2',
|	-setgrid=>'true', -height=>'30', -scrollbars=>'e');
|   $txt->pack(-expand=>'yes', -fill=>'both');
|   $btn->configure(-command=>sub{&GetText($txt)} );
|   
|   # Populate text widget with lines tagged odd and even...
|   my $lno;
|   my $oddeven;
|   foreach $lno (1..20) {
|	if($lno % 2) { $oddeven = "odd" } else { $oddeven = "even" };
|	$lno = "Line $lno ($oddeven)\n";
|	$txt->insert ('end', $lno, $oddeven);
|   }

|   
|   # Do the main processing loop...
|   MainLoop();
|   
|   sub GetText {
|	my $txtobj = shift;
|
|	$txtobj->tag('configure', 'odd', -background=>'lightblue');
|	$txtobj->tag('configure', 'even', -background=>'lightgreen');
|
|	# This is the goal of all the work...
|	my @lines = $txtobj->get($txtobj->tagRanges('odd'));
|
|	print STDERR join("", @lines);
|   }


~ Reference Implementation

The patch for this reference implementation has been posted to the ptk
mailing list. An archived version is available at:

http://faqchest.dynhost.com/prgm/ptk-l/ptk-01/ptk-0112/ptk-011201/ptk01122716_24437.html

I have written and run a single benchmark test (in Perl-Tk) to compare
this reference implementation against a traditional method of
extracting all text with a specific tag.  The results of this specific
benchmark test (tagging odd lines ''odd'' and even lines ''even'' in a
text window with 2000 entries), run on my computer are as follows:

|Reference Implementation   0.105 CPU Seconds (average over 10 runs)
|Traditional Method         0.443 CPU Seconds (average over 10 runs)

I believe that both the CPU the efficiency, and the coding efficiency
that this reference implementation provides, merit the change to the
Tk Widget.  In addition to the ''get'' enhancement, the symmetrical changes would be make to the ''delete'' subcommand.

''The patch has received little testing so far, so any testing is
encouraged.''

~ Notes on Equivalent Behaviour in Tcl/Tk

Tcl has less of a need for this than Perl because it has a striding
[[foreach]] allowing the list of indices returned by the [[$t tag
ranges]] subcommand to be traversed in a straight-forward fashion, but
this sort of functionality is still useful.  The motivating examples
above become (in order):

|   set lines [$t get 1.0 "1.0 lineend" 2.0]
|   set lines [$t get 1.0 {} 2.0 "2.0 lineend"]
|   set lines [$t get 1.0 "1.0 lineend" 2.0 "2.0 lineend"]
|   set lines [eval $t get [$t tag ranges]]

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|



|



|













|
|

|




|




|

|


|



|


|










|





|

|


|



|


|

|
|
|

|


|

|

|


|

|



|

|



|
|
|


|

|

|


|

|

|


|

|

|




|




|

|
|


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
|
>
|




|

|


|
|

|
|



|

|
|

|


|
|

|

|
|
|
|

|


>

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194

195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236

# TIP 93: Get/Delete Enhancement for the Tk Text Widget

	Author:         Craig Votava <[email protected]>
	Author:         Donal K. Fellows <[email protected]>
	Author:         Jeff Hobbs <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        28-Dec-2001
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

The Tk Text widget provides text tags, which are a very powerful
thing.  However, the current implementation does not provide an
efficient way for a Tk Text widget programmer to extract \(get\) all of
the actual text that has a given text tag.  This TIP proposes to
enhance the Tk Text widget to provide this functionality.

# Rationale

While writing applications using the Tk Text widget, I find myself
wanting to extract all of the text that has a given text tag.
Although this is possible with the existing functionality of the Tk
Text widget, it can become extremely inefficient, depending on your
application.

Consider the example where we load a text widget with say, the
contents of a scene from a play, and we tag all of the spoken passages
with the name of the character that utters them.  How can we provide
an efficient way to allow an end user to print out all the spoken text
for a single given character?

My initial impulse was to design something like this \(please excuse
the use of Perl-Tk syntax, that's what I'm most comfortable with\):

	   $txt->tagGet($tag);

The problem with this design is what should this return? A string?  An
list? If a list, should it be a list of each tagged character?  A list
of strings containing all contiguous characters? In addition, Steve
Lidie points out that the corresponding tagDelete\(\) command would
also have to be modified to mimic this change as well. This line of
thought got icky pretty fast.

My second impulse was to try to induce this functionality with as much
existing stuff as possible.  The _tagRanges_ command returns a list
of index pairs for all contiguous characters with a given tag.  The
thought here was to combine that command with the _get_ command to
get all the text with a given tag:

	   $txt->get( $txt->tagRanges($tag) );

This design seems to fit in well with much of the existing
functionality of the text widget.  The main problem here is that the
existing _get_ command only allows for either one or two arguments,
and returns a single string.  For this design to be implemented, the
get interface would need to be enhanced.  This is the design I chose
to implement as a reference \(prototype\) implementation.  I believe
that the functionality should be provided in the Tk Text widget, and
believe that this prototype solution could be turned into a production
solution.  However those decisions I happily leave up to the Tk
developers who are more knowledgeable about the Tk Text implementation
than myself.

An additional concern here involves the corresponding text delete
command. Should the delete command also be modified in a similar way so
that it has this same functionality too? It seems like it should.

# Specification

This specification will only describe how the reference implementation
was produced.  If it is decided that an alternate design is needed for
the final production solution, this specification can be scrapped.

The goal of this design is to enhance the Tk Text _get_ command from
accepting only one or two arguments, to accepting any number of 1
\(\+NULL\) or 2 arguments sets.  The Tcl-Tk manual page description would
change from this:

	   $t get i1 ?i2?

to something like this:

	   $t get i1 ?i2? ?(i3 ?i4? ...)?

By providing this enhancement, we give the programmer with the ability
to efficiently _get_ all of the text that is tagged with a given
tag.  The programmer would do this by using a compound statement
utilizing the existing _tag ranges_ command along with the enhanced
_get_ command, as follows \(the examples are using the Perl-Tk
syntax\):

	   $txt->get( $txt->tagRanges($tag) );

In addition, the enhancement will preserve compatibility with all of
the existing Tk _get_ commands currently in use.

Currently, the _get_ command simply returns a single string
containing all of the characters specified by the first and
\(optionally\) the second argument\(s\).  The enhanced _get_ command
will preserve this existing functionality:

	   my $chr = $text->get('1.0');

 > This command functions exactly the same as the original _get_
   command.  It will return a string containing the first character
   from the first line.

	   my $str = $text->get('1.0', '1.0 lineend');

 > This command functions exactly the same as the original _get_
   command.  It will return a string containing all of the characters
   on the first line.

However, if the programmer provides more than one or two argument\(s\),
the enhanced _get_ command will return a list of strings, just as if
the original _get_ command was called multiple times and the results
were loaded into a programmer-defined list:

	   my @lines = $text->get('1.0', '1.0 lineend', '2.0');

 > This command returns a list whose first element \(_$lines[[0]](0.md)_\)
   is a string containing all of the characters from the first line,
   and the second element \(_$lines[[1]](1.md)_\) is a string containing
   just the first character of the second line.

	   my @lines = $text->get('1.0', '', '2.0', '2.0 lineend');

 > This command returns a list whose first element \(_$lines[[0]](0.md)_\)
   is a string containing just the first character from the first
   line, and the second element \(_$lines[[1]](1.md)_\) is a string
   containing all of the characters on the second line.

	   my @lines = $text->get('1.0', '1.0 lineend', '2.0', '2.0 lineend');

 > This command returns a list whose first element \(_$lines[[0]](0.md)_\)
   is a string containing the all of the characters from the first
   line, and the second element \(_$lines[[1]](1.md)_\) is a string
   containing all of the characters from the second line.

All of this paves the way for the programmer to use the compound command:

	   my @lines = $txt->get( $txt->tagRanges($tag) );

 > This command returns a list whose elements are strings of all the
   contiguous characters tagged with a given tag.

# Example

The following Perl-Tk code illustrates how the enhanced _get_
command could be used with the existing _tag ranges_ command to
efficiently extract all of the text that is tagged with a given tag.

	   #! /usr/local/bin/perl -w
	   
	   require 5.005;
	   
	   use strict;
	   use English;
	   
	   use Tk;
	   
	   # Create main window with button and text widget in it...
	   my $top = MainWindow->new;
	   my $btn = $top->Button(-text=>'print odd lines')->pack;
	   my $txt = $top->Scrolled('Text', -relief=>'sunken', -borderwidth=>'2',
		-setgrid=>'true', -height=>'30', -scrollbars=>'e');
	   $txt->pack(-expand=>'yes', -fill=>'both');
	   $btn->configure(-command=>sub{&GetText($txt)} );
	   
	   # Populate text widget with lines tagged odd and even...
	   my $lno;
	   my $oddeven;
	   foreach $lno (1..20) {
		if($lno % 2) { $oddeven = "odd" } else { $oddeven = "even" };
		$lno = "Line $lno ($oddeven)\n";
		$txt->insert ('end', $lno, $oddeven);

	   }
	   
	   # Do the main processing loop...
	   MainLoop();
	   
	   sub GetText {
		my $txtobj = shift;
	
		$txtobj->tag('configure', 'odd', -background=>'lightblue');
		$txtobj->tag('configure', 'even', -background=>'lightgreen');
	
		# This is the goal of all the work...
		my @lines = $txtobj->get($txtobj->tagRanges('odd'));
	
		print STDERR join("", @lines);

	   }

# Reference Implementation

The patch for this reference implementation has been posted to the ptk
mailing list. An archived version is available at:

<http://faqchest.dynhost.com/prgm/ptk-l/ptk-01/ptk-0112/ptk-011201/ptk01122716\_24437.html>

I have written and run a single benchmark test \(in Perl-Tk\) to compare
this reference implementation against a traditional method of
extracting all text with a specific tag.  The results of this specific
benchmark test \(tagging odd lines _odd_ and even lines _even_ in a
text window with 2000 entries\), run on my computer are as follows:

	Reference Implementation   0.105 CPU Seconds (average over 10 runs)
	Traditional Method         0.443 CPU Seconds (average over 10 runs)

I believe that both the CPU the efficiency, and the coding efficiency
that this reference implementation provides, merit the change to the
Tk Widget.  In addition to the _get_ enhancement, the symmetrical changes would be make to the _delete_ subcommand.

_The patch has received little testing so far, so any testing is
encouraged._

# Notes on Equivalent Behaviour in Tcl/Tk

Tcl has less of a need for this than Perl because it has a striding
[foreach] allowing the list of indices returned by the [$t tag
ranges] subcommand to be traversed in a straight-forward fashion, but
this sort of functionality is still useful.  The motivating examples
above become \(in order\):

	   set lines [$t get 1.0 "1.0 lineend" 2.0]
	   set lines [$t get 1.0 {} 2.0 "2.0 lineend"]
	   set lines [$t get 1.0 "1.0 lineend" 2.0 "2.0 lineend"]
	   set lines [eval $t get [$t tag ranges]]

# Copyright

This document has been placed in the public domain.

Name change from tip/94.tip to tip/94.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

TIP:		94
Title:		Add Listbox -activestyle Option
Version:	$Revision: 1.5 $
Author:		Jeff Hobbs <[email protected]>
State:		Final
Type:		Project
Created:	29-May-2002
Tcl-Version:	8.4
Vote:		Done
Post-History:	


~ Abstract

This TIP proposes to add a [[-activestyle]] option to the [[listbox]]
widget that would control what style the active element has when the
widget has focus (currently hard-coded to be underlined).

~ Rationale

Tk has always had an underline on the active item in listboxes, which
is shown when the listbox has focus.  However this in incompatible
with the style of listboxes on Windows, especially as used in drop-down
boxes.  They instead have a thin dotted line to indicate the active
item.  In order to improve native look and feel, we would allow the
user to request the style which indicates the active item.

~ Specification

|    $listbox configure -activestyle none|underline|dotbox

The default would be underline, which stays consistent with the
current behavior.  ''dotbox'' is the Windows style, which is
essentially the dotted focus ring that any item with focus receives.
While Windows does have a special API (''DrawFocusRect'') to draw
this, it should be possible with the features of the dash patch to
emulate on Unix.  It may not be possible to draw a dotbox easily on
MacOS, in which case the option will be allowed, but nothing would be
drawn (rather than dropping back to underline).

~ Reference Implementation

This implementation is simple and would only extend one check in
''DisplayListbox'' for whether the underline should be drawn.

File: ''tcl/generix/tkListbox.c''

Function: ''DisplayListbox''

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|

|

|








|

|


|

|



|

|


|

|

|

|


>

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

# TIP 94: Add Listbox -activestyle Option

	Author:		Jeff Hobbs <[email protected]>
	State:		Final
	Type:		Project
	Created:	29-May-2002
	Tcl-Version:	8.4
	Vote:		Done
	Post-History:	
-----

# Abstract

This TIP proposes to add a [-activestyle] option to the [listbox]
widget that would control what style the active element has when the
widget has focus \(currently hard-coded to be underlined\).

# Rationale

Tk has always had an underline on the active item in listboxes, which
is shown when the listbox has focus.  However this in incompatible
with the style of listboxes on Windows, especially as used in drop-down
boxes.  They instead have a thin dotted line to indicate the active
item.  In order to improve native look and feel, we would allow the
user to request the style which indicates the active item.

# Specification

	    $listbox configure -activestyle none|underline|dotbox

The default would be underline, which stays consistent with the
current behavior.  _dotbox_ is the Windows style, which is
essentially the dotted focus ring that any item with focus receives.
While Windows does have a special API \(_DrawFocusRect_\) to draw
this, it should be possible with the features of the dash patch to
emulate on Unix.  It may not be possible to draw a dotbox easily on
MacOS, in which case the option will be allowed, but nothing would be
drawn \(rather than dropping back to underline\).

# Reference Implementation

This implementation is simple and would only extend one check in
_DisplayListbox_ for whether the underline should be drawn.

File: _tcl/generix/tkListbox.c_

Function: _DisplayListbox_

# Copyright

This document has been placed in the public domain.

Name change from tip/95.tip to tip/95.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

TIP:            95
Title:          Add [wm attributes] Command
Version:        $Revision: 1.5 $
Author:         Jeff Hobbs <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        29-May-2002
Post-History:   
Tcl-Version:    8.4


~ Abstract

This TIP proposes adding a [[wm attributes]] command in order to
control platform-specific aspects of a toplevel.  In addition, it
proposes making [[wm]] a ''Tcl_Obj''-based command and centralizing
the common functionality.

~ Rationale

While Tk has been proven useful over time as a cross-platform toolkit,
it has some serious drawbacks in acceptance due to small, but
important, lacking functionality in the handling of toplevel windows
on certain platforms.  Having a toplevel stay on top on Windows is a
prime example of a commonly requested feature for which there is no
core support.  Mac/Tk has long had a special unknown command to
support special styles needed for proper "look and feel" there.  I
hereby propose a [[wm attributes]] command (like the [[file
attributes]] command) to providing platform-specific functionality for
toplevel windows.

~ Specification

|   wm attributes $toplevel ...
|   [[WINDOWS]]
|        ?-disabled ?bool??
|        ?-toolwindow ?bool??
|        ?-topmost ?bool??
|        ?-minimizebox ?bool??
|        ?-maximizebox ?bool??
|        ?-sysmenu ?bool??
|   [[MAC]]
|        ?-style ?alert|moveablealert|modal|moveablemodal|
|                 floating|document ...??
|   [[UNIX]]
|        <empty at this time>

Because Tk started off on Unix, most potential attributes are already
in the wm command, whether they really make sense across platforms or
not (some equivalent has been emulated in most cases).  If someone
feels that there are some X window attributes that Tk does not
support, this would be the place to put them.

On Windows, most of the attribute settings can be combined (they are
OR-ed bits of special style fields on a toplevel), which is why they
are set or retrieved as booleans.  The names reflect their Win32 API
bits.  For Windows and the Mac, the naming of attributes and/or styles
mirrors the native API as closely as possible, as we are exposing
native platform functionality in this command.  More specifics about
Windows styles can be seen here:

 > http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwui/html/msdn_styles32.asp

For Macs, styles are mutually exclusive, so you set one of a list of
available styles.  MacOS has nine standard window types and eight
standard floating window types.  More information can be seen here:

 > http://developer.apple.com/techpubs/quicktime/qtdevdocs/INMAC/MACWIN/imWindowMgrRef.3.htm

~ Reference Implementation

Mac/Tk has a reference implementation already that would just adapt
the existing ''unsupported1'' code to ''wm attributes''.  There are
two variant patches for the Windows work in Tk patch 553926 at SF.

File: ''tk/mac/tkMacWm.c''

File: ''tk/win/tkWinWm.c''

File: ''tk/unix/tkUnixWm.c''

Function: ''Tk_WmCmd''

~ Comments

Several names have been used for a command with similar functionality.
Mac/Tk uses the ''style'' command, as does Tk Patch 553926.  This is
only for platform-specific configuration of toplevel windows, and it
not necessarily limited to style.  I considered ''wm configure'', but
I chose ''wm attributes'' because that worked just as well and had the
equivalent of ''file attributes'' to support the naming.

Windows toplevels could have more special styles like
''-transparent'', Windows scrollbars on the toplevel and a few other
window styles that the Win32 API supports.  Only the styles that have
had user requests are supported at this time.  We may want to add
''-caption'' and ''-dialogmodal'' support if these seem useful.

It was recommended that commonality be reached where possible, but
this tip addresses most specifically what isn't common across the
minute aspects of toplevel window handing on different platforms.  For
examples, for Windows to allow TOPMOST, it keeps a special list of the
topmost windows.  This manager-level support is necessary to avoid
contention amongst topmost windows.  Macintosh has many special dialog
and window styles to represent both changing UI design over time, as
well as the latest in UI design that can be reached standard for Mac
toplevels but not Unix or Windows ones.

It may be that certain functionality will become cross-platform as
native APIs develop, but this is meant to allow access to key native
look and feel features that Tk lacks for serious developers now.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|

|


|








|
|


|

|
|
|
|
|
|
|
|
|
|
|
|
|



|



|
|






|





|

|


|


|

|

|

|

|


|

|
|
|


|


|















|


>

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

# TIP 95: Add [wm attributes] Command

	Author:         Jeff Hobbs <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        29-May-2002
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

This TIP proposes adding a [wm attributes] command in order to
control platform-specific aspects of a toplevel.  In addition, it
proposes making [wm] a _Tcl\_Obj_-based command and centralizing
the common functionality.

# Rationale

While Tk has been proven useful over time as a cross-platform toolkit,
it has some serious drawbacks in acceptance due to small, but
important, lacking functionality in the handling of toplevel windows
on certain platforms.  Having a toplevel stay on top on Windows is a
prime example of a commonly requested feature for which there is no
core support.  Mac/Tk has long had a special unknown command to
support special styles needed for proper "look and feel" there.  I
hereby propose a [wm attributes] command \(like the [file
attributes] command\) to providing platform-specific functionality for
toplevel windows.

# Specification

	   wm attributes $toplevel ...
	   [[WINDOWS]]
	        ?-disabled ?bool??
	        ?-toolwindow ?bool??
	        ?-topmost ?bool??
	        ?-minimizebox ?bool??
	        ?-maximizebox ?bool??
	        ?-sysmenu ?bool??
	   [[MAC]]
	        ?-style ?alert|moveablealert|modal|moveablemodal|
	                 floating|document ...??
	   [[UNIX]]
	        <empty at this time>

Because Tk started off on Unix, most potential attributes are already
in the wm command, whether they really make sense across platforms or
not \(some equivalent has been emulated in most cases\).  If someone
feels that there are some X window attributes that Tk does not
support, this would be the place to put them.

On Windows, most of the attribute settings can be combined \(they are
OR-ed bits of special style fields on a toplevel\), which is why they
are set or retrieved as booleans.  The names reflect their Win32 API
bits.  For Windows and the Mac, the naming of attributes and/or styles
mirrors the native API as closely as possible, as we are exposing
native platform functionality in this command.  More specifics about
Windows styles can be seen here:

 > <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwui/html/msdn\_styles32.asp>

For Macs, styles are mutually exclusive, so you set one of a list of
available styles.  MacOS has nine standard window types and eight
standard floating window types.  More information can be seen here:

 > <http://developer.apple.com/techpubs/quicktime/qtdevdocs/INMAC/MACWIN/imWindowMgrRef.3.htm>

# Reference Implementation

Mac/Tk has a reference implementation already that would just adapt
the existing _unsupported1_ code to _wm attributes_.  There are
two variant patches for the Windows work in Tk patch 553926 at SF.

File: _tk/mac/tkMacWm.c_

File: _tk/win/tkWinWm.c_

File: _tk/unix/tkUnixWm.c_

Function: _Tk\_WmCmd_

# Comments

Several names have been used for a command with similar functionality.
Mac/Tk uses the _style_ command, as does Tk Patch 553926.  This is
only for platform-specific configuration of toplevel windows, and it
not necessarily limited to style.  I considered _wm configure_, but
I chose _wm attributes_ because that worked just as well and had the
equivalent of _file attributes_ to support the naming.

Windows toplevels could have more special styles like
_-transparent_, Windows scrollbars on the toplevel and a few other
window styles that the Win32 API supports.  Only the styles that have
had user requests are supported at this time.  We may want to add
_-caption_ and _-dialogmodal_ support if these seem useful.

It was recommended that commonality be reached where possible, but
this tip addresses most specifically what isn't common across the
minute aspects of toplevel window handing on different platforms.  For
examples, for Windows to allow TOPMOST, it keeps a special list of the
topmost windows.  This manager-level support is necessary to avoid
contention amongst topmost windows.  Macintosh has many special dialog
and window styles to represent both changing UI design over time, as
well as the latest in UI design that can be reached standard for Mac
toplevels but not Unix or Windows ones.

It may be that certain functionality will become cross-platform as
native APIs develop, but this is meant to allow access to key native
look and feel features that Tk lacks for serious developers now.

# Copyright

This document has been placed in the public domain.

Name change from tip/96.tip to tip/96.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

TIP:		96
Title:		Add [tk caret] Command and Tk_SetCaretPos API
Version:	$Revision: 1.4 $
Author:		Jeff Hobbs <[email protected]>
State:		Final
Type:		Project
Created:	29-May-2002
Tcl-Version:	8.4
Vote:		Done
Post-History:	


~ Abstract

This TIP proposes to add a [[tk caret]] command and [[Tk_SetCaretPos]]
C API to manage ''carets'' in Tk.  ''caret'' is the term for where
text of graphics will be inserted.  It is necessary for correct
accessibility functionality (to know where to shift focus), and for
location the IME or XIM input box to handle complex character input
(e.g. Asian character sets).

~ Rationale

Tk has up until now not managed the caret within its windows.  This
has led to it being not Windows Accessibility certifiable.  On
Windows, this also cause the IME window to show in the top-left corner
of the window (somewhat OK for entries, bad for text widgets).  On X,
this meant that Tk had to use the root-window style XIM input, which
is a poor second to over-the-spot XIM input.  Managing the caret
corrects these problems.

Exposing the functionality at the Tcl level allows extension writers
to use the functionality without having to make Tk version API checks.
A simple

|   catch {tk caret $w -x $x -y $y}

will suffice to work across versions.

~ Specification

|   tk caret window ?-x xPos? ?-y yPos? ?-height height?
|   void Tk_SetCaretPos (Tk_Window tkwin, int x, int y, int height)

''-height'' specifies the height of the input line and is important
because Windows and X interpret the x,y coordinates differently
(top-left and bottom-left respectively), so it must be adjusted by
height for X.  If no height is specified, the height of the window
passed in will be used.

I chose to use the ''-option value'' format because it allows for
future extensibility.  There are APIs to control the font and other
aspects of the IME/XIM input window that appears, but management of
these is not covered in this tip.

~ Reference Implementation

The Tk_SetCaretPos implementation is currently in the core.  It needs
to be modified to move the caret information to be per display,
instead of per process.

File: ''tk/mac/tkMacXStubs.c''

File: ''tk/win/tkWinX.c''

File: ''tk/unix/tkUnixKey.c''

Function: ''Tk_SetCaretPos''

~ Comments

The current implementation at the C level was implemented with the
assistance of Keiichi Takahashi (BitWalk), Koiichi Yamamoto, Moo Kim
(NCR), and Mike Fabian (SuSE).  It has been tested on Windows
98/2000/XP and SuSE 7.3 using kinput/canna2.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|

|
|

|

|

|




|








|



|

|
|

|

|



|




|

|



|

|

|

|

|


|
|


|


>

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

# TIP 96: Add [tk caret] Command and Tk_SetCaretPos API

	Author:		Jeff Hobbs <[email protected]>
	State:		Final
	Type:		Project
	Created:	29-May-2002
	Tcl-Version:	8.4
	Vote:		Done
	Post-History:	
-----

# Abstract

This TIP proposes to add a [tk caret] command and [Tk_SetCaretPos]
C API to manage _carets_ in Tk.  _caret_ is the term for where
text of graphics will be inserted.  It is necessary for correct
accessibility functionality \(to know where to shift focus\), and for
location the IME or XIM input box to handle complex character input
\(e.g. Asian character sets\).

# Rationale

Tk has up until now not managed the caret within its windows.  This
has led to it being not Windows Accessibility certifiable.  On
Windows, this also cause the IME window to show in the top-left corner
of the window \(somewhat OK for entries, bad for text widgets\).  On X,
this meant that Tk had to use the root-window style XIM input, which
is a poor second to over-the-spot XIM input.  Managing the caret
corrects these problems.

Exposing the functionality at the Tcl level allows extension writers
to use the functionality without having to make Tk version API checks.
A simple

	   catch {tk caret $w -x $x -y $y}

will suffice to work across versions.

# Specification

	   tk caret window ?-x xPos? ?-y yPos? ?-height height?
	   void Tk_SetCaretPos (Tk_Window tkwin, int x, int y, int height)

_-height_ specifies the height of the input line and is important
because Windows and X interpret the x,y coordinates differently
\(top-left and bottom-left respectively\), so it must be adjusted by
height for X.  If no height is specified, the height of the window
passed in will be used.

I chose to use the _-option value_ format because it allows for
future extensibility.  There are APIs to control the font and other
aspects of the IME/XIM input window that appears, but management of
these is not covered in this tip.

# Reference Implementation

The Tk\_SetCaretPos implementation is currently in the core.  It needs
to be modified to move the caret information to be per display,
instead of per process.

File: _tk/mac/tkMacXStubs.c_

File: _tk/win/tkWinX.c_

File: _tk/unix/tkUnixKey.c_

Function: _Tk\_SetCaretPos_

# Comments

The current implementation at the C level was implemented with the
assistance of Keiichi Takahashi \(BitWalk\), Koiichi Yamamoto, Moo Kim
\(NCR\), and Mike Fabian \(SuSE\).  It has been tested on Windows
98/2000/XP and SuSE 7.3 using kinput/canna2.

# Copyright

This document has been placed in the public domain.

Name change from tip/97.tip to tip/97.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

TIP:		97
Title:		Moving Vertices of Canvas Items
Version:	$Revision: 1.10 $
Author:		Agnar Renolen <[email protected]>
Author:		Donal K. Fellows <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Created:	07-Jun-2002
Post-History:	
Keywords:	Tk


~ Abstract

This TIP proposes a canvas subcommand (or possibly two) that allows for
replacing characters in text objects and to move individual vertices of line
and polygon items.

~ Rationale

Interactive graphics programs often allow users to modify shapes of objects by
selecting and dragging the vertices. Moving one vertex of a canvas item in the
current version of Tk, (at least as far as I can find out from the
documentation), can only be done by first removing the coordinate by
'''dchars''' and then insert the new one by '''insert''', or for geometric
items like lines and polygons using the '''coords''' command to obtain and
reset the coordinates, after having modified the coordinate list by
'''lreplace'''.

The most important issue here, I think, is performance. I believe that the
current way of moving a vertex can be slow in some scenarios.

The '''rchars''' canvas subcommand is proposed merely to conform with the
'''dchars''' and '''insert''' commands, which both operate on lines, polygons
and text items, hence '''rchars''' should do that as well.

~ Specification

Two canvas widget subcommands are proposed: '''imove''' and '''rchars'''. The
following subcommand is proposed to move a vertex of any canvas item:

 > ''canvas'' '''imove''' ''tagOrID index x y''

This subcommand will move the ''index''th coordinate of the items identified by
''tagOrID'' to the new position given by ''x'' and ''y''. The ''index'' value
will be processed according to normal canvas index rules (see the INDICES
section of the '''canvas''' manual). The subcommand will only work for line
and polygon items (or any third party items that set the TK_MOVABLE_POINTS
flag).

The following command provides a similar functionality, but conforms to the
model of the current '''insert''' and '''dchars''' subcommands.

 > ''canvas'' '''rchars''' ''tagOrID first last string''

This command will:

 for text items: replace the characters in the range ''first'' and ''last''
    (inclusive) with the characters in ''string''.

 for line and polygon items: replace the coordinates in the range ''first''
    and ''last'' (inclusive) with the coordinate list specified in ''string''
    (subject to the requirement that the coordinate list is an even number of
    floating point numbers).

In both cases, ''first'' and ''last'' will be processed according to the rules
in the INDICES section of the '''canvas''' manual page.

At the C level, the only change is the addition of a new flag,
'''TK_MOVABLE_POINTS'''. If this flag is set in the ''alwaysRedraw'' field of
the item type structure, it implies that the item supplies non-NULL
''dcharsProc'', ''indexProc'' and ''insertProc'' fields, and gives them
semantics equivalent to the line and polygon items (i.e. that the methods will
work with the coordinate list). Note that text items, despite having all the
required methods, do not set the flag because those methods work with
character indices.

~~ Notes

The '''imove''' subcommand is not strictly necessary as the '''rchars'''
subcommand can be used to obtain the same result. However, I believe that a
separate '''imove''' subcommand will be easier to understand for users than
the '''rchars''' subcommand, though the latter is still necessary as it allows
for more complex processing such as insertion or deletion of points.

~ Reference Implementation

See Patch 2157629[https://sourceforge.net/support/tracker.php?aid=2157629].

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
|
|
>

|

|



|



|
|
|
|

|




|
|
|

|

|


|

|
|
|
|
|
|


|

|



|
|

|
|
|
|

|
|


|

|
|
|



|

|

|
|


|

|

|


>

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

# TIP 97: Moving Vertices of Canvas Items

	Author:		Agnar Renolen <[email protected]>
	Author:		Donal K. Fellows <[email protected]>
	State:		Final
	Type:		Project
	Tcl-Version:	8.6
	Vote:		Done
	Created:	07-Jun-2002
	Post-History:	
	Keywords:	Tk
-----

# Abstract

This TIP proposes a canvas subcommand \(or possibly two\) that allows for
replacing characters in text objects and to move individual vertices of line
and polygon items.

# Rationale

Interactive graphics programs often allow users to modify shapes of objects by
selecting and dragging the vertices. Moving one vertex of a canvas item in the
current version of Tk, \(at least as far as I can find out from the
documentation\), can only be done by first removing the coordinate by
**dchars** and then insert the new one by **insert**, or for geometric
items like lines and polygons using the **coords** command to obtain and
reset the coordinates, after having modified the coordinate list by
**lreplace**.

The most important issue here, I think, is performance. I believe that the
current way of moving a vertex can be slow in some scenarios.

The **rchars** canvas subcommand is proposed merely to conform with the
**dchars** and **insert** commands, which both operate on lines, polygons
and text items, hence **rchars** should do that as well.

# Specification

Two canvas widget subcommands are proposed: **imove** and **rchars**. The
following subcommand is proposed to move a vertex of any canvas item:

 > _canvas_ **imove** _tagOrID index x y_

This subcommand will move the _index_th coordinate of the items identified by
_tagOrID_ to the new position given by _x_ and _y_. The _index_ value
will be processed according to normal canvas index rules \(see the INDICES
section of the **canvas** manual\). The subcommand will only work for line
and polygon items \(or any third party items that set the TK\_MOVABLE\_POINTS
flag\).

The following command provides a similar functionality, but conforms to the
model of the current **insert** and **dchars** subcommands.

 > _canvas_ **rchars** _tagOrID first last string_

This command will:

 for text items: replace the characters in the range _first_ and _last_
    \(inclusive\) with the characters in _string_.

 for line and polygon items: replace the coordinates in the range _first_
    and _last_ \(inclusive\) with the coordinate list specified in _string_
    \(subject to the requirement that the coordinate list is an even number of
    floating point numbers\).

In both cases, _first_ and _last_ will be processed according to the rules
in the INDICES section of the **canvas** manual page.

At the C level, the only change is the addition of a new flag,
**TK\_MOVABLE\_POINTS**. If this flag is set in the _alwaysRedraw_ field of
the item type structure, it implies that the item supplies non-NULL
_dcharsProc_, _indexProc_ and _insertProc_ fields, and gives them
semantics equivalent to the line and polygon items \(i.e. that the methods will
work with the coordinate list\). Note that text items, despite having all the
required methods, do not set the flag because those methods work with
character indices.

## Notes

The **imove** subcommand is not strictly necessary as the **rchars**
subcommand can be used to obtain the same result. However, I believe that a
separate **imove** subcommand will be easier to understand for users than
the **rchars** subcommand, though the latter is still necessary as it allows
for more complex processing such as insertion or deletion of points.

# Reference Implementation

See Patch 2157629<https://sourceforge.net/support/tracker.php?aid=2157629> .

# Copyright

This document has been placed in the public domain.

Name change from tip/98.tip to tip/98.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

TIP:		98
Title:		Adding Transparency Compositing Rules to Photo Images
Author:		Donal K. Fellows <[email protected]>
Created:	09-Jun-2001
Version:	$Revision: 1.5 $
Type:		Project
State:		Final
Vote:		Done
Tcl-Version:	8.4
Post-History:	


~ Abstract

This TIP adds compositing rules to Tk's photo images to give
programmers better control over what happens when two transparent
images are combined.  This TIP also allows for several frames of an
animated GIF file to be correctly displayed in an image even when the
transparent area is not constant.

~ Rationale

This is a TIP that is inspired by the tkchat application in Tcllib,
and in particular by the image used to represent the LOL smiley.  The
problem with this image is that its transparent area changes over
time, and this is caused by the fact that ''Tk_PhotoPutBlock()'' only
allows one way of compositing a block with an image; it behaves as if
the data being added was on a sheet of cel (the material used to make
hand-drawn animated cartoons) allowing for sophisticated layering
effects.  Unfortunately, for many applications (and animated GIF
images are definitely among these) this sophistication works against
us.  In a GIF image, transparency is treated not as extra information
that is added to each pixel's colour, but rather as a special colour;
a pixel cannot be, for example, red and transparent at the same time.
Support for this requires a different (and indeed simpler) kind of
compositing rule.  And of course, once you have such a facility in the
underlying C code, it should be exposed to scripts.

There are other kinds of compositing rule (for example, acting like
the added block is placed under the image, and many others) but this
TIP does not propose adding anything other than a way to chose between
the current behaviour and the behaviour required for supporting GIF
animation, in the belief that those two compositing rules are the ones
most useful to programmers, and that once the general facility is
there, the other rules will be relatively easy to add in the future.

~ Specification

This TIP adds a ''compositingRule'' argument to ''Tk_PhotoPutBlock''
(and ''Tk_PhotoPutZoomedBlock'') to allow selection between the
current behaviour (overlaying) and the other one I wish to support
(setting/overriding.)  The permitted values of this argument will be
''TK_PHOTO_COMPOSITE_OVERLAY'' (the currently implemented behaviour)
and ''TK_PHOTO_COMPOSITE_SET'' (the behaviour required to support GIF
file animation.)

At the Tcl level, when copying from one image to another (the other
photo image subcommands do not currently support transparency at all)
the ''photo get'' will take an extra option ''-compositingrule'' to
allow selection of the compositing rule.  The permitted values of this
option will be ''overlay'' and ''set'' by analogy with the values
described above.

~ Implementation Notes

Proposed implementation patch:
https://sourceforge.net/tracker/index.php?func=detail&aid=566765&group_id=12997&atid=312997

The proposed implementation of this TIP naturally includes
backward-compatibility functions that allow pre-compiled extensions to
continue to operate without recompilation (provided they use Stubs for
linking.)  Furthermore, extension authors can also define the symbol
''USE_COMPOSITELESS_PHOTO_PUT_BLOCK'' when compiling and have
source-level compatibility with the old functions.

The proposed implementation also creates ''TkSubtractRegion'' as a new
internal function; it is the analogue of ''XSubtractRegion'' as
''TkIntersectRegion'' is the analogue of ''XIntersectRegion''.  It
might be useful to other parts of the core that manipulate regions.

Both the PPM and GIF file readers use the ''set'' compositing rule,
PPM because the format does not support transparency (and ''set''
should at least theoretically be faster) and GIF because it is
required semantically.  Other image formats are not required to do
this, of course.  The ''$img put $data'' photo image subcommand uses
''set'' compositing because it does not support transparency.

~ Copyright

This document is placed in the public domain.

<
|
|
|
<
|
|
|
|
|
>

|







|




|

|
|
|
|



|



|
|






|

|
|
|
|
|
|
|

|
|
|

|


|


|



|
|
|


|
|
|


|
|
|

|
|

|


>

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

# TIP 98: Adding Transparency Compositing Rules to Photo Images
	Author:		Donal K. Fellows <[email protected]>
	Created:	09-Jun-2001

	Type:		Project
	State:		Final
	Vote:		Done
	Tcl-Version:	8.4
	Post-History:	
-----

# Abstract

This TIP adds compositing rules to Tk's photo images to give
programmers better control over what happens when two transparent
images are combined.  This TIP also allows for several frames of an
animated GIF file to be correctly displayed in an image even when the
transparent area is not constant.

# Rationale

This is a TIP that is inspired by the tkchat application in Tcllib,
and in particular by the image used to represent the LOL smiley.  The
problem with this image is that its transparent area changes over
time, and this is caused by the fact that _Tk\_PhotoPutBlock\(\)_ only
allows one way of compositing a block with an image; it behaves as if
the data being added was on a sheet of cel \(the material used to make
hand-drawn animated cartoons\) allowing for sophisticated layering
effects.  Unfortunately, for many applications \(and animated GIF
images are definitely among these\) this sophistication works against
us.  In a GIF image, transparency is treated not as extra information
that is added to each pixel's colour, but rather as a special colour;
a pixel cannot be, for example, red and transparent at the same time.
Support for this requires a different \(and indeed simpler\) kind of
compositing rule.  And of course, once you have such a facility in the
underlying C code, it should be exposed to scripts.

There are other kinds of compositing rule \(for example, acting like
the added block is placed under the image, and many others\) but this
TIP does not propose adding anything other than a way to chose between
the current behaviour and the behaviour required for supporting GIF
animation, in the belief that those two compositing rules are the ones
most useful to programmers, and that once the general facility is
there, the other rules will be relatively easy to add in the future.

# Specification

This TIP adds a _compositingRule_ argument to _Tk\_PhotoPutBlock_
\(and _Tk\_PhotoPutZoomedBlock_\) to allow selection between the
current behaviour \(overlaying\) and the other one I wish to support
\(setting/overriding.\)  The permitted values of this argument will be
_TK\_PHOTO\_COMPOSITE\_OVERLAY_ \(the currently implemented behaviour\)
and _TK\_PHOTO\_COMPOSITE\_SET_ \(the behaviour required to support GIF
file animation.\)

At the Tcl level, when copying from one image to another \(the other
photo image subcommands do not currently support transparency at all\)
the _photo get_ will take an extra option _-compositingrule_ to
allow selection of the compositing rule.  The permitted values of this
option will be _overlay_ and _set_ by analogy with the values
described above.

# Implementation Notes

Proposed implementation patch:
<https://sourceforge.net/tracker/index.php?func=detail&aid=566765&group\_id=12997&atid=312997>

The proposed implementation of this TIP naturally includes
backward-compatibility functions that allow pre-compiled extensions to
continue to operate without recompilation \(provided they use Stubs for
linking.\)  Furthermore, extension authors can also define the symbol
_USE\_COMPOSITELESS\_PHOTO\_PUT\_BLOCK_ when compiling and have
source-level compatibility with the old functions.

The proposed implementation also creates _TkSubtractRegion_ as a new
internal function; it is the analogue of _XSubtractRegion_ as
_TkIntersectRegion_ is the analogue of _XIntersectRegion_.  It
might be useful to other parts of the core that manipulate regions.

Both the PPM and GIF file readers use the _set_ compositing rule,
PPM because the format does not support transparency \(and _set_
should at least theoretically be faster\) and GIF because it is
required semantically.  Other image formats are not required to do
this, of course.  The _$img put $data_ photo image subcommand uses
_set_ compositing because it does not support transparency.

# Copyright

This document is placed in the public domain.

Name change from tip/99.tip to tip/99.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

TIP:            99
Title:          Add 'file link' to Tcl
Version:        $Revision: 1.23 $
Author:         Vince Darley <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        11-Jun-2002
Post-History:   
Tcl-Version:    8.4


~ Abstract

Tcl can read links, but cannot create them.  This TIP proposes adding
a ''file link'' subcommand to allow cross-platform creation of links.

~ Proposal

Add a new subcommand with the following syntax:

|      file link ?-linktype? linkName ?target?

If only one argument is given, that argument is assumed to be
''linkName'', and this command returns the value of the link given by
''linkName'' (i.e. the name of the file it points to).  If
''linkName'' isn't a link or its value cannot be read (as, for
example, seems to be the case with hard links, which look just like
ordinary files), then an error is returned.

If 2 arguments are given, then these are assumed to be ''linkName''
and ''target''.  If ''linkName'' already exists, or if ''target''
doesn't exist, an error will be returned.  Otherwise, Tcl creates a
new link called ''linkName'' which points to the existing filesystem
object at ''target'', where the type of the link is platform-specific
(on Unix a symbolic link will be the default).  This is useful for the
case where the user wishes to create a link in a cross-platform way,
and doesn't care what type of link is created.

If the user wishes to make a link of a ''specific type only'', (and
signal an error if for some reason that is not possible), then the
optional ''linktype'' argument should be given.  Accepted values for
linktype are ''-symbolic'' and ''-hard''.

When creating links on filesystems that either do not support any
links, or do not support the specific type requested, an error message
will be returned (in particular Windows 95, 98 and ME do not support
any symbolic links at present, but Unix, MacOS and Windows NT/2000/XP
(on NTFS drives) do).

The TIP proposes implementing:

|           Unix,MacOSX      Win-NTFS           MacOS
|symbolic:      yes        directories-only      yes
|hard:       files-only     files-only           no

This also leaves the avenue open, in the future, for the addition of
other link types (e.g. Windows shortcuts) through additions to list of
acceptable ''linktype''s.  This TIP only proposes adding the above
options.

This means that a general ''[[file link $linkname $target]]'' should
always succeed on the above platforms (for both files and
directories), but uses of ''-hard'' or ''-symbolic'' could fail,
depending on the current platform, and the type of the path.

~ Rationale

There are many requests on comp.lang.tcl for this functionality (see
http://groups.google.com/groups?dq=&hl=en&lr=&ie=UTF8&oe=UTF8&threadm=4dd3bea3.0206100250.95eeb4e%40posting.google.com&rnum=1&prev=/&frame=on
for a recent thread), and if Tcl can read links (''file readlink'',
''file lstat''), it really ought to be able to write them.

Discussion has shown that both symbolic and hard links are desirable,
and that for cross-platform use a general-purpose ''file link'' which
creates ''something'' is useful.

Some users would prefer hard links to be the default, but on balance
most people commenting seemed to prefer symbolic links as default.
This has the added benefit that symbolic links will then be the
default on MacOS, Unix and Windows for everything, ''except'' files on
WinTcl (where hard-links are required).

~ Alternatives

There is no cross-platform alternative available.  TclX provides a
''link'' command for Unix only, and Unix platforms can also use ''exec
ln ?-s?'' command to achieve the same effect.

~ Reference Implementation

Tcl contains a ''testfilelink'' command in ''generic/tclTest.c'',
which is a partial implementation used by the test suite.  For a full
implementation of this TIP, including the ''-linktype'' switch, see:

''

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


which includes extensive docs and tests.

~ Copyright

This document has been placed in the public domain.

<
|
<
|
|
|
|
|
|
|
>

|


|

|



|


|
|
|

|

|
|

|
|
|



|
|
|
|



|

|



|
|
|


|
|


|
|
|


|

|
|
|
|


|
|




|
|

|


|
|

|

|

|

<
>
|
<
>



|


>

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

# TIP 99: Add 'file link' to Tcl

	Author:         Vince Darley <[email protected]>
	State:          Final
	Type:           Project
	Vote:           Done
	Created:        11-Jun-2002
	Post-History:   
	Tcl-Version:    8.4
-----

# Abstract

Tcl can read links, but cannot create them.  This TIP proposes adding
a _file link_ subcommand to allow cross-platform creation of links.

# Proposal

Add a new subcommand with the following syntax:

	      file link ?-linktype? linkName ?target?

If only one argument is given, that argument is assumed to be
_linkName_, and this command returns the value of the link given by
_linkName_ \(i.e. the name of the file it points to\).  If
_linkName_ isn't a link or its value cannot be read \(as, for
example, seems to be the case with hard links, which look just like
ordinary files\), then an error is returned.

If 2 arguments are given, then these are assumed to be _linkName_
and _target_.  If _linkName_ already exists, or if _target_
doesn't exist, an error will be returned.  Otherwise, Tcl creates a
new link called _linkName_ which points to the existing filesystem
object at _target_, where the type of the link is platform-specific
\(on Unix a symbolic link will be the default\).  This is useful for the
case where the user wishes to create a link in a cross-platform way,
and doesn't care what type of link is created.

If the user wishes to make a link of a _specific type only_, \(and
signal an error if for some reason that is not possible\), then the
optional _linktype_ argument should be given.  Accepted values for
linktype are _-symbolic_ and _-hard_.

When creating links on filesystems that either do not support any
links, or do not support the specific type requested, an error message
will be returned \(in particular Windows 95, 98 and ME do not support
any symbolic links at present, but Unix, MacOS and Windows NT/2000/XP
\(on NTFS drives\) do\).

The TIP proposes implementing:

	           Unix,MacOSX      Win-NTFS           MacOS
	symbolic:      yes        directories-only      yes
	hard:       files-only     files-only           no

This also leaves the avenue open, in the future, for the addition of
other link types \(e.g. Windows shortcuts\) through additions to list of
acceptable _linktype_s.  This TIP only proposes adding the above
options.

This means that a general _[file link $linkname $target]_ should
always succeed on the above platforms \(for both files and
directories\), but uses of _-hard_ or _-symbolic_ could fail,
depending on the current platform, and the type of the path.

# Rationale

There are many requests on comp.lang.tcl for this functionality \(see
<http://groups.google.com/groups?dq=&hl=en&lr=&ie=UTF8&oe=UTF8&threadm=4dd3bea3.0206100250.95eeb4e%40posting.google.com&rnum=1&prev=/&frame=on>
for a recent thread\), and if Tcl can read links \(_file readlink_,
_file lstat_\), it really ought to be able to write them.

Discussion has shown that both symbolic and hard links are desirable,
and that for cross-platform use a general-purpose _file link_ which
creates _something_ is useful.

Some users would prefer hard links to be the default, but on balance
most people commenting seemed to prefer symbolic links as default.
This has the added benefit that symbolic links will then be the
default on MacOS, Unix and Windows for everything, _except_ files on
WinTcl \(where hard-links are required\).

# Alternatives

There is no cross-platform alternative available.  TclX provides a
_link_ command for Unix only, and Unix platforms can also use _exec
ln ?-s?_ command to achieve the same effect.

# Reference Implementation

Tcl contains a _testfilelink_ command in _generic/tclTest.c_,
which is a partial implementation used by the test suite.  For a full
implementation of this TIP, including the _-linktype_ switch, see:


_
<http://sourceforge.net/tracker/index.php?func=detail&aid=562970&group\_id=10894&atid=310894>

_

which includes extensive docs and tests.

# Copyright

This document has been placed in the public domain.