Tcl language - namespace
Tcl language - namespace
Table of contents
0 Preface
1 Create a namespace
2 Check the namespace
3 Namespace export and import commands
4 Variables in the namespace
5 Several ways to access namespace variables
5.1 Variables outside the process proc (external variables)
5.2 Variables inside the procedure proc (internal variables)
5.3 Access external variables within the procedure (same namespace)
5.4 Access external variables (different namespaces) inside the procedure
0 Preface
Namespace is a mechanism commonly used in programming languages. The implementation and syntax of the namespace mechanism may be different in different programming languages, butthe core idea is the same, that is:by encapsulating related variables, functions and classes in packages In an independent namespace, avoid naming conflicts and improve the readability and maintainability of the program. For example, namespaces in Ruby are implemented by modules, which can encapsulate variables, methods, and classes; modules and packages in Python can also be regarded as namespaces, which can be used to organize and Manage variables, functions and classes.
In the Tcl language, global variables and procedures can be modified and accessed anywhere, which can lead to naming conflicts . By introducing the namespace mechanism, a group of related variables and procedures can be encapsulated in an independent namespace to avoid conflicts with objects in other namespaces.
Therefore, namespaces have several advantages :
- Make the structure of the program clearer and make different parts of the code easier to understand and modify.
- Provide an isolation mechanism so that different modules can be developed and tested independently, thereby reducing program errors and bugs
1 Create a namespace
Grammatical structures:
2. namespace eval spaceName {
3. # 命名空间内的代码
4. }
namespace eval is used to create a new namespace in the global namespace, and then execute a piece of code inside the new namespace to define variables and procedures. Among them,spaceName is the name of the namespace, which can be any string.
2. proc put {} {
3. puts "Hello from global namespace !"
4. }
5. # 创建命名空间ns1并在内部创建proc
6. namespace eval ns1 {
7. proc put {} {
8. puts "Hello from ns1 !"
9. }
10. }
11. # 创建命名空间ns2并在内部创建proc
12. namespace eval ns2 {
13. proc put {} {
14. puts "Hello from ns2 !"
15. }
16. }
17. # 命名空间嵌套,在命名空间内部在创建子命名空间
18. namespace eval ns3 {
19. namespace eval ns3_1 {
20. proc put {} {
21. puts "Hello from ns3_1 !"
22. }
23. }
24. namespace eval ns3_2 {
25. proc put {} {
26. puts "Hello from ns3_2 !"
27. }
28. }
29. }

Although the above procedure names are all put , defining them in different namespaces will not cause naming conflicts. You only need to call the procedures in the corresponding namespaces. We know that processes defined in the global namespace can be accessed directly using the process name. So how to call procedures that access the interior of other sub-namespaces ?
Namespace separator "double colon" ::
2. put
3. ::put ;#直接以::开头表示访问全局命名空间
4. # 调用ns1命名空间的proc
5. ns1::put
6. # 调用ns3_2命名空间的proc
7. ns3::ns3_2::put
Judging from the above process of creating and accessing a namespace, the namespace has a tree structure. Similar to how we access files in a certain directory, the global namespace is equivalent to the root directory.
2 Check the namespace
Check namespace command Command name | explain |
---|---|
namespace eval | Create namespace |
namespace current | Get the current namespace |
namespace children | Returns the subspaces of the specified namespace |
namespace parent | Returns the parent space of the specified namespace |
namespace exists | Check whether the specified namespace exists |
namespace delete | Delete the specified namespace |
2. puts [namespace current]
3. # namespace eval 创建命名空间
4. namespace eval ns {
5. proc myproc {} {
6. puts "This string from ns."
7. }
8. namespace eval ns_1 {
9. proc myproc {} {
10. puts "This string from ns_1."
11. }
12. }
13. namespace eval ns_2 {
14. proc myproc {} {
15. puts "This string from ns_2."
16. }
17. }
18. }
19. # namespace children 返回指定命名空间的子空间列表
20. puts [namespace children ::]
21. puts [namespace children];# 与上条代码等效
22. puts [namespace children ns]
23. puts [namespace children ns::ns_1]
24. # namespace parent 返回指定命名空间的父空间列表
25. puts [namespace parent ns]
26. puts [namespace parent ::]
27. puts [namespace parent];# 与上条代码等效
28. puts [namespace parent ns::ns_1]
29. # namespace exists 查看命名空间是否存在
30. puts [namespace exists ::];# 返回值是1
31. puts [namespace exists ns::ns_1];# 返回值是1
32. puts [namespace exists ns::ns_3];# 返回值是0
33. # namespace delete 删除指定命名空间及其中的变量和命令
34. namespace delete ns::ns_1
35. puts [namespace exists ns::ns_1];# 返回值是0
36. ns::ns_2::myproc ;# 输出 This string from ns_2.
37. ns::ns_1::myproc ;# 报错 invalid command name "ns::ns_1::myproc"

3 Namespace export and import commands
The export and import namespace commands are usually used in pairs . For example, export a process in a certain sub-namespace and then import it into the global namespace. Then the process can be called directly in the global namespace without adding Namespace delimiter.
2. namespace eval test {
3. # 定义过程
4. proc add {a b} {
5. set sum [expr {$a + $b}]
6. puts "$a+$b=$sum"
7. }
8. proc print {} {
9. puts "Hello,Tcl!"
10. }
11. # 将当前空间的add过程导出;所以要在当前空间执行这条命令
12. # namespace export add
13. # namespace export print
14. # 也可以使用通配符
15. namespace export *
16. }
17. # 在test空间中创建一个test_1的子空间
18. namespace eval test::test_1 {
19. proc diff {a b} {
20. set difference [expr {$a - $b}]
21. puts "$a-$b=$difference"
22. }
23. namespace export diff
24. }
25. # 将add过程导入当前空间;所以要在全局空间执行这条命令
26. # namespace import test::add
27. # namespace import test::print
28. namespace import test::*
29. namespace import test::test_1::diff
30. add 2 3
31. diff 2 1
32. print

4 Variables in the namespace
- To create a variable in a namespace in Tcl , you can use the following syntax:
2. namespace eval spaceName {
3. variable varName value
4. }
Where spaceName is the namespace name, command variable creates a variable, varName is the variable name, and value is the initial value of the variable.
- To access this variable , you can usethe syntax $spaceName::varName .
2. variable var "Hello,Tcl!"
3. }
4. puts $ns::var
- Access global variables ( global keyword), namespace variables ( variable keyword) and local variables in the namespace****
2. set num 1000 ;# 全局命名空间中的变量
3. namespace eval ns {
4. # ns子命名空间中的变量
5. variable num 100
6. proc print_ns {} {
7. variable num
8. puts "ns_var: $num"
9. }
10.
11. proc print_global {} {
12. global num
13. puts "global_var: $num"
14. }
15.
16. proc print_local {} {
17. # 过程中的变量也叫局部变量
18. set num 0
19. puts "local_var: $num"
20. }
21.
22. }
23. # 在ns命名空间中调用过程
24. ns::print_global ;# 打印全局变量
25. ns::print_ns ;# 打印命名空间变量
26. ns::print_local ;# 打印局部变量

Thinking: We define variables inside the namespace through the variable command, and in the global namespace we use the set command. But there is essentially no difference between the two, except that the global namespace is the parent space. Therefore, it stands to reason that creating variables in the global namespace can also be achieved using the variable command. The following is the experiment done:
2. variable x -100
3. proc print {} {
4. # 在全局空间过程内部定义变量
5. set x 100
6. puts "$x"
7. }
8. print ;# 调用全局命名空间的过程
9. ::print ;# 与上一条代码等价
10. puts $x
11. # 在全局过程内部访问外部变量
12. proc print1 {} {
13. # 需要用global关键字申明
14. global x
15. puts "$x"
16. }
17. print1 ;# 调用全局命名空间的过程

It can be seen from the output results that the thinking is correct, but in actual use, in order to distinguish between global space and subspace, it cannot be used indiscriminately.
Summary : In fact, we can divide variables of different scopes intotwo categories : one isexternal variables , which refer to variables defined outsidethe process . If the external variables are defined in the global namespace, they are global variables.The global keyword declaration is required internallyto achieve access; if the external variable is defined in a subspace other than the global name, it is a namespace variable, andthe variable keyword declaration is required within the process to achieve access. The other type is internal variables, which refer to variables defined inside the processproc . Whether defined in the global space or subspace, they can only be accessed within the process without keyword declaration.
5 Several ways to access namespace variables
5.1 Variables outside the process proc ( external variables )
2. # 全局空间中访问全局变量
3. set x 0
4. puts $x
5. # 子空间中访问子空间变量
6. namespace eval ns {
7. variable y 1
8. puts $y
9. }
10. # 全局空间中访问子空间变量
11. puts $ns::y
12. # 子空间中访问全局变量
13. namespace eval ns {
14. global x
15. puts $x
16. }

5.2 Variables inside the process proc ( internal variables )
- Internal variables of the process do not require keyword declaration when accessed within their respective spaces.
2. # 全局空间过程内部访问
3. proc value {} {
4. set a 1
5. puts "$a"
6. }
7. value ;#调用全局空间过程
8. # 子空间过程内部访问
9. namespace eval NS {
10. proc value {} {
11. set b 9
12. puts "$b"
13. }
14. }
15. NS::value ;# 调用子空间过程
Variables within different procedures cannot access each other:
2. proc proc1 {} {
3. set a 1
4. puts $a
5. }
6. # 过程2
7. proc proc2 {} {
8. set b 9
9. set sum [expr {$a+$b}]
10. puts $sum
11. }
12. proc2
5.3 Access external variables within the procedure ( same namespace )
2. set a 100
3. proc incr {b} {
4. # 需要用global关键字申明
5. global a
6. set sum [expr {$a + $b}]
7. puts $sum
8. }
9. incr 1
10. # 在过程内部访问子空间变量
11. namespace eval ns {
12. variable a 100
13. proc incr {b} {
14. # 需要用variable关键字申明
15. variable a
16. set sum [expr {$a + $b}]
17. puts $sum
18. }
19. }
20. ns::incr 1

5.4 Access external variables ( different namespaces ) inside the procedure
2. namespace eval ns1 {
3. variable a 1
4. }
5. #子空间2
6. namespace eval ns2 {
7. variable b 9
8. proc add {} {
9. variable b
10. # 通过namespace upvar命令应用命名空间ns1中的变量,要注意分隔符的使用::ns1
11. namespace upvar ::ns1 a A
12. set sum [expr {$A + $b}]
13. puts $sum
14. }
15. }
16. ns2::add

Summary: One thing that is often unclear here is that when calling procedures and variables, I always don’t know whether to add a dollar sign. It was later discovered that the two commands spaceName procName and spaceName varName are accessed procedure names and variable names.
Because when calling a process, the process name is returned. Sometimes the puts command is defined in the process and the results are output directly. When calling a variable, the program will not directly output the results when the variable name is returned, so you need to use the puts ${spaceName varName}
command. Output the results directly.
Of course, there are other contents of the namespace. Because the author is currently in the beginner stage of knowledge, I will not delve into it further! If this article is helpful to you, please give it a follow , thank you!