aboutsummaryrefslogtreecommitdiff
path: root/README.namespaces
blob: ef50769f96c9b72ce5a5f48ff2f25071a64b0ae6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
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
Lightweight Namespaces for Jim Tcl
==================================

There are two broad requirements for namespace support in Jim Tcl.

1. To allow code from multiple sources while reducing the chance of name clashes
2. To simplify porting existing Tcl code which uses namespaces

This proposal addresses both of these requirements, with the following
additional requirements imposed by Jim Tcl.

3. Support for namespaces should be optional, with the space and time overhead
   when namespaces are disabled as close to zero as possible.
4. The implementation should be small and reasonably efficient.

To further expand on requirement (2), the goal is not to be able to run
any Tcl scripts using namespaces with no changes. Rather, scripts
which use namespaces in a straightforward manner, should be easily
ported with changes which are compatible with Tcl.

Implicit namespaces
-------------------
Rather than supporting explicit namespaces as Tcl does, Jim Tcl
supports implicit namespaces. Any procedure or variable which
is defined with a name containing ::, is implicitly scoped within
a namespace.

For example, the following procedure and variable are created
in the namespace 'test'

proc ::test::myproc {} {
  puts "I am in namespace [namespace current]"
}
set ::test::myvar 3

This approach allows much of the existing variable and command
resolution machinery to be used with little change. It also means
that it is possible to simply define a namespace-scoped variable
or procedure without first creating the namespace, and similarly,
namespaces "disappear" when all variables and procedures defined
with the namespace scope are deleted.

Namespaces, procedures and call frames
--------------------------------------
When namespace support is enabled (at build time), each procedure has an associated
namespace (based on the procedure name). When the procedure is evaluated,
the namespace for the created call frame is set to the namespace associated
with the procedure.

Command resolution is based on the namespace of the current call frame.
An unscoped command name will first be looked up in the current namespace,
and then in the global namespace.

This also means that commands which do not create a call frame (such as commands
implemented in C) do not have an associated namespace.

Similarly to Tcl, namespace eval introduces a temporary, anonymous
call frame with the associated namespace. For example, the following
will return "::test,1".

namespace eval test {
	puts [namespace current],[info level]
}

Variable resolution
-------------------
The variable command in Jim Tcl has the same syntax as Tcl, but is closer in behaviour to the global command.
The variable command creates a link from a local variable to a namespace variable, possibly initialising it.

For example, the following procedure uses 'variable' to initialise and access myvar.

proc ::test::myproc {} {
  variable myvar 4
  incr myvar
}

Note that there is no automatic resolution of namespace variables.
For example, the following will *not* work.

namespace eval ::test {
  variable myvar 4
}
namespace eval ::test {
  # This will increment a local variable, not ::test::myvar
  incr myvar
}

And similarly, the following will only access local variables

set x 3
namespace eval ::test {
	# This will increment a local variable, not ::x
	incr x
	# This will also increment a local variable
	incr abc::def
}

In the same way that variable resolution does not "fall back" to
global variables, it also does not "fall back" to namespace variables.

This approach allows name resolution to be simpler and more efficient
since it uses the same variable linking mechanism as upvar/global
and it allows namespaces to be implicit. It also solves the "creative
writing" problem where a variable may be created in an unintentional
scope.

The namespace command
---------------------
Currently, the following namespace commands are supported.

* current - returns the current, fully-qualified namespace
* eval - evaluates a script in a namespace (introduces a call frame)
* qualifiers, tail, parent - note that these do not check for existence
* code, inscope - implemented
* delete - deletes all variables and commands with the namespace prefix
* which - implemented
* upvar - implemented

namespace children, exists, path
--------------------------------
With implicit namespaces, the namespace exists and namespace children commands
are expensive to implement and are of limited use. Checking the existence
of a namespace can be better done by checking for the existence of a known procedure
or variable in the namespace.

Command resolution is always done by first looking in the namespace and then
at the global scope, so namespace path is not required.

namespace ensemble
------------------
The namespace ensemble command is not currently supported. A future version
of Jim Tcl will have a general-purpose ensemble creation and manipulation
mechanism and namespace ensemble will be implemented in terms of that mechanism.

namespace import, export, forget, origin
----------------------------------------
Since Jim Tcl namespaces are implicit, there is no location to store export patterns.
Therefore the namespace export command is a dummy command which does nothing.
All procedures in a namespace are considered to be exported.

The namespace import command works by creating aliases to the target namespace
procedures.

namespace forget is not implemented.

namespace origin understands aliases created by namespace import
and can return the original command.

namespace unknown
-----------------
If an undefined command is invoked, the "unknown" command is invoked.
The same namespace resolution rules apply for the unknown command.
This means that in the following example, test::unknown will be invoked
for the missing command rather than the global ::unknown.

proc unknown {args} {
	puts "global unknown"
}

proc test::unknown {args} {
	puts "test unknown"
}

namespace eval test {
	bogus
}

This approach requires no special support and provides enough flexibility that
the namespace unknown command is not implemented.

Porting namespace code from Tcl to Jim Tcl
------------------------------------------
For most code, the following changes will be sufficient to port code.

1. Canonicalise namespace names. For example, ::ns:: should be written
   as ::ns or ns as appropriate, and excess colons should be removed.
   For example ::ns:::blah should be written as ::ns::blah
   (Note that the only "excess colon" case supported is ::::abc
   in order to support [namespace current]::abc in the global namespace)

2. The variable command should be used within namespace eval to link
   to namespace variables, and access to variables in other namespaces
   should be fully qualified

Changes in the core Jim Tcl
---------------------------
Previously Jim Tcl performed no scoping of command names.  i.e. The
::format command was considered different from the format command.

Even if namespace support is disabled, the command resolution will
recognised global scoping of commands and treat these as identical.