1
0
mirror of https://github.com/adambard/learnxinyminutes-docs.git synced 2025-08-17 20:11:57 +02:00

add filename: learntcl.tcl

This commit is contained in:
Poor Yorick
2015-01-04 23:00:23 -07:00
parent aac20efb70
commit 79b730dcaa

View File

@@ -1,446 +1,447 @@
--- ---
language: Tcl language: Tcl
contributors: contributors:
- ["Poor Yorick", "http://pooryorick.com/"] - ["Poor Yorick", "http://pooryorick.com/"]
--- filename: learntcl.tcl
---
Tcl was created by [John Ousterhout](http://wiki.tcl.tk/John Ousterout) as a
reusable scripting language for chip design tools he was creating. In 1997 he Tcl was created by [John Ousterhout](http://wiki.tcl.tk/John Ousterout) as a
was awarded the [ACM Software System reusable scripting language for chip design tools he was creating. In 1997 he
Award](http://en.wikipedia.org/wiki/ACM_Software_System_Award) for Tcl. Tcl was awarded the [ACM Software System
can be used both as an embeddable scripting language and as a general Award](http://en.wikipedia.org/wiki/ACM_Software_System_Award) for Tcl. Tcl
programming language. It can also be used as a portable C library, even in can be used both as an embeddable scripting language and as a general
cases where no scripting capability is needed, as it provides data structures programming language. It can also be used as a portable C library, even in
such as dynamic strings, lists, and hash tables. The C library also provides cases where no scripting capability is needed, as it provides data structures
portable functionality for loading dynamic libraries, string formatting and such as dynamic strings, lists, and hash tables. The C library also provides
code conversion, filesystem operations, network operations, and more. portable functionality for loading dynamic libraries, string formatting and
Various features of Tcl stand out: code conversion, filesystem operations, network operations, and more.
Various features of Tcl stand out:
* Convenient cross-platform networking API
* Convenient cross-platform networking API
* Fully virtualized filesystem
* Fully virtualized filesystem
* Stackable I/O channels
* Stackable I/O channels
* Asynchronous to the core
* Asynchronous to the core
* Full coroutines
* Full coroutines
* A threading model recognized as robust and easy to use
* A threading model recognized as robust and easy to use
If Lisp is a list processor, then Tcl is a string processor. All values are
strings. A list is a string format. A procedure definition is a string If Lisp is a list processor, then Tcl is a string processor. All values are
format. To achieve performance, Tcl internally caches structured strings. A list is a string format. A procedure definition is a string
representations of these values. The list commands, for example, operate on format. To achieve performance, Tcl internally caches structured
the internal cached representation, and Tcl takes care of updating the string representations of these values. The list commands, for example, operate on
representation if it is ever actually needed in the script. The copy-on-write the internal cached representation, and Tcl takes care of updating the string
design of Tcl allows script authors can pass around large data values without representation if it is ever actually needed in the script. The copy-on-write
actually incurring additional memory overhead. Procedures are automatically design of Tcl allows script authors can pass around large data values without
byte-compiled unless they use the more dynamic commands such as "uplevel", actually incurring additional memory overhead. Procedures are automatically
"upvar", and "trace". byte-compiled unless they use the more dynamic commands such as "uplevel",
"upvar", and "trace".
Tcl is a pleasure to program in. It will appeal to hacker types who find Lisp,
Forth, or Smalltalk interesting, as well as to engineers and scientists who Tcl is a pleasure to program in. It will appeal to hacker types who find Lisp,
just want to get down to business with a tool that bends to their will. Its Forth, or Smalltalk interesting, as well as to engineers and scientists who
discipline of exposing all programmatic functionality as commands, including just want to get down to business with a tool that bends to their will. Its
things like loops and mathematical operations that are usually baked into the discipline of exposing all programmatic functionality as commands, including
syntax of other languages, allows it to fade into the background of whatever things like loops and mathematical operations that are usually baked into the
domain-specific functionality a project needs. It's syntax, which is even syntax of other languages, allows it to fade into the background of whatever
lighter that that of Lisp, just gets out of the way. domain-specific functionality a project needs. It's syntax, which is even
lighter that that of Lisp, just gets out of the way.
```tcl
#! /bin/env tclsh ```tcl
#! /bin/env tclsh
################################################################################
## 1. Guidelines ################################################################################
################################################################################ ## 1. Guidelines
################################################################################
# Tcl is not Bash or C! This needs to be said because standard shell quoting
# habits almost work in Tcl and it is common for people to pick up Tcl and try # Tcl is not Bash or C! This needs to be said because standard shell quoting
# to get by with syntax they know from another language. It works at first, # habits almost work in Tcl and it is common for people to pick up Tcl and try
# but soon leads to frustration with more complex scripts. # to get by with syntax they know from another language. It works at first,
# but soon leads to frustration with more complex scripts.
# Braces are just a quoting mechanism, not a code block constructor or a list
# constructor. Tcl doesn't have either of those things. Braces are used, # Braces are just a quoting mechanism, not a code block constructor or a list
# though, to escape special characters in procedure bodies and in strings that # constructor. Tcl doesn't have either of those things. Braces are used,
# are formatted as lists. # though, to escape special characters in procedure bodies and in strings that
# are formatted as lists.
################################################################################
## 2. Syntax ################################################################################
################################################################################ ## 2. Syntax
################################################################################
# Every line is a command. The first word is the name of the command, and
# subsequent words are arguments to the command. Words are delimited by # Every line is a command. The first word is the name of the command, and
# whitespace. Since every word is a string, in the simple case no special # subsequent words are arguments to the command. Words are delimited by
# markup such as quotes, braces, or backslash, is necessary. Even when quotes # whitespace. Since every word is a string, in the simple case no special
# are used, they are not a string constructor, but just another escaping # markup such as quotes, braces, or backslash, is necessary. Even when quotes
# character. # are used, they are not a string constructor, but just another escaping
# character.
set greeting1 Sal
set greeting2 ut set greeting1 Sal
set greeting3 ations set greeting2 ut
set greeting3 ations
#semicolon also delimits commands
set greeting1 Sal; set greeting2 ut; set greeting3 ations #semicolon also delimits commands
set greeting1 Sal; set greeting2 ut; set greeting3 ations
# Dollar sign introduces variable substitution
set greeting $greeting1$greeting2$greeting3 # Dollar sign introduces variable substitution
set greeting $greeting1$greeting2$greeting3
# Bracket introduces command substitution. The result of the command is
# substituted in place of the bracketed script. When the "set" command is # Bracket introduces command substitution. The result of the command is
# given only the name of a variable, it returns the value of that variable. # substituted in place of the bracketed script. When the "set" command is
set greeting $greeting1$greeting2[set greeting3] # given only the name of a variable, it returns the value of that variable.
set greeting $greeting1$greeting2[set greeting3]
# Command substitution should really be called script substitution, because an
# entire script, not just a command, can be placed between the brackets. The # Command substitution should really be called script substitution, because an
# "incr" command increments the value of a variable and returns its value. # entire script, not just a command, can be placed between the brackets. The
set greeting $greeting[ # "incr" command increments the value of a variable and returns its value.
incr i set greeting $greeting[
incr i incr i
incr i incr i
] incr i
]
# backslash suppresses the special meaning of characters
set amount \$16.42 # backslash suppresses the special meaning of characters
set amount \$16.42
# backslash adds special meaning to certain characters
puts lots\nof\n\n\n\n\n\nnewlines # backslash adds special meaning to certain characters
puts lots\nof\n\n\n\n\n\nnewlines
# A word enclosed in braces is not subject to any special interpretation or
# substitutions, except that a backslash before a brace is not counted when look#ing for the closing brace # A word enclosed in braces is not subject to any special interpretation or
set somevar { # substitutions, except that a backslash before a brace is not counted when look#ing for the closing brace
This is a literal $ sign, and this \} escaped set somevar {
brace remains uninterpreted This is a literal $ sign, and this \} escaped
} brace remains uninterpreted
}
# In a word enclosed in double quotes, whitespace characters lose their special
# meaning # In a word enclosed in double quotes, whitespace characters lose their special
set name Neo # meaning
set greeting "Hello, $name" set name Neo
set greeting "Hello, $name"
#variable names can be any string
set {first name} New #variable names can be any string
set {first name} New
# The brace form of variable substitution handles more complex variable names
set greeting "Hello, ${first name}" # The brace form of variable substitution handles more complex variable names
set greeting "Hello, ${first name}"
# The "set" command can always be used instead of variable substitution
set greeting "Hello, [set {first name}]" # The "set" command can always be used instead of variable substitution
set greeting "Hello, [set {first name}]"
# To promote the words within a word to individual words of the current
# command, use the expansion operator, "{*}". # To promote the words within a word to individual words of the current
set {*}{name Neo} # command, use the expansion operator, "{*}".
set {*}{name Neo}
# is equivalent to
set name Neo # is equivalent to
set name Neo
# An array is a special variable that is a container for other variables.
set person(name) Neo # An array is a special variable that is a container for other variables.
set person(gender) male set person(name) Neo
set greeting "Hello, $person(name)" set person(gender) male
set greeting "Hello, $person(name)"
# A namespace holds commands and variables
namespace eval people { # A namespace holds commands and variables
namespace eval person1 { namespace eval people {
set name Neo namespace eval person1 {
} set name Neo
} }
}
#The full name of a variable includes its enclosing namespace(s), delimited by two colons:
set greeting "Hello $people::person::name" #The full name of a variable includes its enclosing namespace(s), delimited by two colons:
set greeting "Hello $people::person::name"
################################################################################
## 3. A Few Notes ################################################################################
################################################################################ ## 3. A Few Notes
################################################################################
# All other functionality is implemented via commands. From this point on,
# there is no new syntax. Everything else there is to learn about Tcl is about # All other functionality is implemented via commands. From this point on,
# the behaviour of individual commands, and what meaning they assign to their # there is no new syntax. Everything else there is to learn about Tcl is about
# arguments. # the behaviour of individual commands, and what meaning they assign to their
# arguments.
# To end up with an interpreter that can do nothing, delete the global
# namespace. It's not very useful to do such a thing, but it illustrates the # To end up with an interpreter that can do nothing, delete the global
# nature of Tcl. # namespace. It's not very useful to do such a thing, but it illustrates the
namespace delete :: # nature of Tcl.
namespace delete ::
# Because of name resolution behaviour, its safer to use the "variable" command to declare or to assign a value to a namespace.
namespace eval people { # Because of name resolution behaviour, its safer to use the "variable" command to declare or to assign a value to a namespace.
namespace eval person1 { namespace eval people {
variable name Neo namespace eval person1 {
} variable name Neo
} }
}
# The full name of a variable can always be used, if desired.
set people::person1::name Neo # The full name of a variable can always be used, if desired.
set people::person1::name Neo
################################################################################
## 4. Commands ################################################################################
################################################################################ ## 4. Commands
################################################################################
# Math can be done with the "expr" command.
set a 3 # Math can be done with the "expr" command.
set b 4 set a 3
set c [expr {$a + $b}] set b 4
set c [expr {$a + $b}]
# Since "expr" performs variable substitution on its own, brace the expression
# to prevent Tcl from performing variable substitution first. See # Since "expr" performs variable substitution on its own, brace the expression
# "http://wiki.tcl.tk/Brace%20your%20#%20expr-essions" for details. # to prevent Tcl from performing variable substitution first. See
# "http://wiki.tcl.tk/Brace%20your%20#%20expr-essions" for details.
# The "expr" command understands variable and command substitution
set c [expr {$a + [set b]}] # The "expr" command understands variable and command substitution
set c [expr {$a + [set b]}]
# The "expr" command provides a set of mathematical functions
set c [expr {pow($a,$b)}] # The "expr" command provides a set of mathematical functions
set c [expr {pow($a,$b)}]
# Mathematical operators are available as commands in the ::tcl::mathop
# namespace # Mathematical operators are available as commands in the ::tcl::mathop
::tcl::mathop::+ 5 3 # namespace
::tcl::mathop::+ 5 3
# Commands can be imported from other namespaces
namespace import ::tcl::mathop::+ # Commands can be imported from other namespaces
set result [+ 5 3] namespace import ::tcl::mathop::+
set result [+ 5 3]
# New commands can be created via the "proc" command.
proc greet name { # New commands can be created via the "proc" command.
return "Hello, $name!" proc greet name {
} return "Hello, $name!"
}
#multiple parameters can be specified
proc greet {greeting name} { #multiple parameters can be specified
return "$greeting, $name!" proc greet {greeting name} {
} return "$greeting, $name!"
}
# As noted earlier, braces do not construct a code block. Every value, even
# the third argument of the "proc" command, is a string. The previous command # As noted earlier, braces do not construct a code block. Every value, even
# rewritten to not use braces at all: # the third argument of the "proc" command, is a string. The previous command
proc greet greeting\ name return\ \"Hello,\ \$name! # rewritten to not use braces at all:
proc greet greeting\ name return\ \"Hello,\ \$name!
# When the last parameter is the literal value, "args", it collects all extra
# arguments when the command is invoked # When the last parameter is the literal value, "args", it collects all extra
proc fold {cmd args} { # arguments when the command is invoked
set res 0 proc fold {cmd args} {
foreach arg $args { set res 0
set res [cmd $res $arg] foreach arg $args {
} set res [cmd $res $arg]
} }
fold ::tcl::mathop::* 5 3 3 ;# -> 45 }
fold ::tcl::mathop::* 5 3 3 ;# -> 45
# Conditional execution is implemented as a command
if {3 > 4} { # Conditional execution is implemented as a command
puts {This will never happen} if {3 > 4} {
} elseif {4 > 4} { puts {This will never happen}
puts {This will also never happen} } elseif {4 > 4} {
} else { puts {This will also never happen}
puts {This will always happen} } else {
} puts {This will always happen}
}
# Loops are implemented as commands. The first, second, and third
# arguments of the "for" command are treated as mathematical expressions # Loops are implemented as commands. The first, second, and third
for {set i 0} {$i < 10} {incr i} { # arguments of the "for" command are treated as mathematical expressions
set res [expr {$res + $i}] for {set i 0} {$i < 10} {incr i} {
} set res [expr {$res + $i}]
}
# The first argument of the "while" command is also treated as a mathematical
# expression # The first argument of the "while" command is also treated as a mathematical
set i 0 # expression
while {$i < 10} { set i 0
incr i 2 while {$i < 10} {
} incr i 2
}
# A list is a specially-formatted string. In the simple case, whitespace is sufficient to delimit values
set amounts 10\ 33\ 18 # A list is a specially-formatted string. In the simple case, whitespace is sufficient to delimit values
set amount [lindex $amounts 1] set amounts 10\ 33\ 18
set amount [lindex $amounts 1]
# Braces and backslash can be used to format more complex values in a list. A
# list looks exactly like a script, except that the newline character and the # Braces and backslash can be used to format more complex values in a list. A
# semicolon character lose their special meanings. This feature makes Tcl # list looks exactly like a script, except that the newline character and the
# homoiconic. There are three items in the following list. # semicolon character lose their special meanings. This feature makes Tcl
set values { # homoiconic. There are three items in the following list.
set values {
one\ two
one\ two
{three four}
{three four}
five\{six
five\{six
}
}
# Since a list is a string, string operations could be performed on it, at the
# risk of corrupting the formatting of the list. # Since a list is a string, string operations could be performed on it, at the
set values {one two three four} # risk of corrupting the formatting of the list.
set values [string map {two \{} $values] ;# $values is no-longer a \ set values {one two three four}
properly-formatted listwell-formed list set values [string map {two \{} $values] ;# $values is no-longer a \
properly-formatted listwell-formed list
# The sure-fire way to get a properly-formmated list is to use "list" commands
set values [list one \{ three four] # The sure-fire way to get a properly-formmated list is to use "list" commands
lappend values { } ;# add a single space as an item in the list set values [list one \{ three four]
lappend values { } ;# add a single space as an item in the list
# Use "eval" to evaluate a value as a script
eval { # Use "eval" to evaluate a value as a script
set name Neo eval {
set greeting "Hello, $name" set name Neo
} set greeting "Hello, $name"
}
# A list can always be passed to "eval" as a script composed of a single
# command. # A list can always be passed to "eval" as a script composed of a single
eval {set name Neo} # command.
eval [list set greeting "Hello, $name"] eval {set name Neo}
eval [list set greeting "Hello, $name"]
# Therefore, when using "eval", use [list] to build up a desired command
set command {set name} # Therefore, when using "eval", use [list] to build up a desired command
lappend command {Archibald Sorbisol} set command {set name}
eval $command lappend command {Archibald Sorbisol}
eval $command
# A common mistake is not to use list functions when building up a command
set command {set name} # A common mistake is not to use list functions when building up a command
append command { Archibald Sorbisol} set command {set name}
eval $command ;# There is an error here, because there are too many arguments \ append command { Archibald Sorbisol}
to "set" in {set name Archibald Sorbisol} eval $command ;# There is an error here, because there are too many arguments \
to "set" in {set name Archibald Sorbisol}
# This mistake can easily occur with the "subst" command.
set replacement {Archibald Sorbisol} # This mistake can easily occur with the "subst" command.
set command {set name $replacement} set replacement {Archibald Sorbisol}
set command [subst $command] set command {set name $replacement}
eval $command ;# The same error as before: to many arguments to "set" in \ set command [subst $command]
{set name Archibald Sorbisol} eval $command ;# The same error as before: to many arguments to "set" in \
{set name Archibald Sorbisol}
# The proper way is to format the substituted value using use the "list"
# command. # The proper way is to format the substituted value using use the "list"
set replacement [list {Archibald Sorbisol}] # command.
set command {set name $replacement} set replacement [list {Archibald Sorbisol}]
set command [subst $command] set command {set name $replacement}
eval $command set command [subst $command]
eval $command
# It is extremely common to see the "list" command being used to properly
# format values that are substituted into Tcl script templates. There are # It is extremely common to see the "list" command being used to properly
# several examples of this, below. # format values that are substituted into Tcl script templates. There are
# several examples of this, below.
# The "apply" command evaluates a string as a command.
set cmd {{greeting name} { # The "apply" command evaluates a string as a command.
return "$greeting, $name!" set cmd {{greeting name} {
}} return "$greeting, $name!"
apply $cmd Whaddup Neo }}
apply $cmd Whaddup Neo
# The "uplevel" command evaluates a script in some enclosing scope.
proc greet {} { # The "uplevel" command evaluates a script in some enclosing scope.
uplevel {puts "$greeting, $name"} proc greet {} {
} uplevel {puts "$greeting, $name"}
}
proc set_double {varname value} {
if {[string is double $value]} { proc set_double {varname value} {
uplevel [list variable $varname $value] if {[string is double $value]} {
} else { uplevel [list variable $varname $value]
error [list {not a double} $value] } else {
} error [list {not a double} $value]
} }
}
# The "upvar" command links a variable in the current scope to a variable in
# some enclosing scope # The "upvar" command links a variable in the current scope to a variable in
proc set_double {varname value} { # some enclosing scope
if {[string is double $value]} { proc set_double {varname value} {
upvar 1 $varname var if {[string is double $value]} {
set var $value upvar 1 $varname var
} else { set var $value
error [list {not a double} $value] } else {
} error [list {not a double} $value]
} }
}
#get rid of the built-in "while" command.
rename ::while {} #get rid of the built-in "while" command.
rename ::while {}
# Define a new while command with the "proc" command. More sophisticated error
# handling is left as an exercise. # Define a new while command with the "proc" command. More sophisticated error
proc while {condition script} { # handling is left as an exercise.
if {[uplevel 1 [list expr $condition]]} { proc while {condition script} {
uplevel 1 $script if {[uplevel 1 [list expr $condition]]} {
tailcall [namespace which while] $condition $script uplevel 1 $script
} tailcall [namespace which while] $condition $script
} }
}
# The "coroutine" command creates a separate call stack, along with a command
# to enter that call stack. The "yield" command suspends execution in that # The "coroutine" command creates a separate call stack, along with a command
# stack. # to enter that call stack. The "yield" command suspends execution in that
proc countdown {} { # stack.
#send something back to the initial "coroutine" command proc countdown {} {
yield #send something back to the initial "coroutine" command
yield
set count 3
while {$count > 1} { set count 3
yield [incr count -1] while {$count > 1} {
} yield [incr count -1]
return 0 }
} return 0
coroutine countdown1 countdown }
coroutine countdown2 countdown coroutine countdown1 countdown
puts [countdown 1] ;# -> 2 coroutine countdown2 countdown
puts [countdown 2] ;# -> 2 puts [countdown 1] ;# -> 2
puts [countdown 1] ;# -> 1 puts [countdown 2] ;# -> 2
puts [countdown 1] ;# -> 0 puts [countdown 1] ;# -> 1
puts [coundown 1] ;# -> invalid command name "countdown1" puts [countdown 1] ;# -> 0
puts [countdown 2] ;# -> 1 puts [coundown 1] ;# -> invalid command name "countdown1"
puts [countdown 2] ;# -> 1
```
```
## Reference
## Reference
[Official Tcl Documentation](http://www.tcl.tk/man/tcl/)
[Official Tcl Documentation](http://www.tcl.tk/man/tcl/)
[Tcl Wiki](http://wiki.tcl.tk)
[Tcl Wiki](http://wiki.tcl.tk)
[Tcl Subreddit](http://www.reddit.com/r/Tcl)
[Tcl Subreddit](http://www.reddit.com/r/Tcl)