diff options
author | Poor Yorick <com.github.pooryorick.learnsinyminutes@pooryorick.com> | 2015-01-04 23:00:23 -0700 |
---|---|---|
committer | Poor Yorick <com.github.pooryorick.learnsinyminutes@pooryorick.com> | 2015-01-04 23:00:23 -0700 |
commit | 79b730dcaa8994cb6b58af1e25a5aa9e06f48471 (patch) | |
tree | 4e372a2daaa846417c36ee4ad489aa9c4ee714cf | |
parent | aac20efb70dbd10383c9bfa4dd9108d8a4fda9ce (diff) |
add filename: learntcl.tcl
-rwxr-xr-x | tcl.html.markdown | 893 |
1 files changed, 447 insertions, 446 deletions
diff --git a/tcl.html.markdown b/tcl.html.markdown index 44805b5c..f2d92fcd 100755 --- a/tcl.html.markdown +++ b/tcl.html.markdown @@ -1,446 +1,447 @@ ----
-language: Tcl
-contributors:
- - ["Poor Yorick", "http://pooryorick.com/"]
----
-
-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
-was awarded the [ACM Software System
-Award](http://en.wikipedia.org/wiki/ACM_Software_System_Award) for Tcl. Tcl
-can be used both as an embeddable scripting language and as a general
-programming language. It can also be used as a portable C library, even in
-cases where no scripting capability is needed, as it provides data structures
-such as dynamic strings, lists, and hash tables. The C library also provides
-portable functionality for loading dynamic libraries, string formatting and
-code conversion, filesystem operations, network operations, and more.
-Various features of Tcl stand out:
-
-* Convenient cross-platform networking API
-
-* Fully virtualized filesystem
-
-* Stackable I/O channels
-
-* Asynchronous to the core
-
-* Full coroutines
-
-* 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
-format. To achieve performance, Tcl internally caches structured
-representations of these values. The list commands, for example, operate on
-the internal cached representation, and Tcl takes care of updating the string
-representation if it is ever actually needed in the script. The copy-on-write
-design of Tcl allows script authors can pass around large data values without
-actually incurring additional memory overhead. Procedures are automatically
-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
-just want to get down to business with a tool that bends to their will. Its
-discipline of exposing all programmatic functionality as commands, including
-things like loops and mathematical operations that are usually baked into the
-syntax of other languages, allows it to fade into the background of whatever
-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
-
-################################################################################
-## 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
-# 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,
-# though, to escape special characters in procedure bodies and in strings that
-# are formatted as lists.
-
-
-################################################################################
-## 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
-# whitespace. Since every word is a string, in the simple case no special
-# markup such as quotes, braces, or backslash, is necessary. Even when quotes
-# are used, they are not a string constructor, but just another escaping
-# character.
-
-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
-
-
-# Bracket introduces command substitution. The result of the command is
-# substituted in place of the bracketed script. When the "set" command is
-# 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
-# "incr" command increments the value of a variable and returns its value.
-set greeting $greeting[
- incr i
- incr i
- incr i
-]
-
-
-# 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
-
-
-# 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
-set somevar {
- This is a literal $ sign, and this \} escaped
- brace remains uninterpreted
-}
-
-
-# In a word enclosed in double quotes, whitespace characters lose their special
-# meaning
-set name Neo
-set greeting "Hello, $name"
-
-
-#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 "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, "{*}".
-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
-set person(gender) male
-set greeting "Hello, $person(name)"
-
-
-# A namespace holds commands and variables
-namespace eval people {
- 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"
-
-
-
-################################################################################
-## 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
-# 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
-# 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 {
- namespace eval person1 {
- variable name Neo
- }
-}
-
-
-# The full name of a variable can always be used, if desired.
-set people::person1::name Neo
-
-
-
-################################################################################
-## 4. Commands
-################################################################################
-
-# Math can be done with the "expr" command.
-set a 3
-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
-# "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 provides a set of mathematical functions
-set c [expr {pow($a,$b)}]
-
-
-# Mathematical operators are available as commands in the ::tcl::mathop
-# namespace
-::tcl::mathop::+ 5 3
-
-# Commands can be imported from other namespaces
-namespace import ::tcl::mathop::+
-set result [+ 5 3]
-
-
-# New commands can be created via the "proc" command.
-proc greet name {
- return "Hello, $name!"
-}
-
-#multiple parameters can be specified
-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
-# 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
-proc fold {cmd args} {
- set res 0
- foreach arg $args {
- set res [cmd $res $arg]
- }
-}
-fold ::tcl::mathop::* 5 3 3 ;# -> 45
-
-
-# Conditional execution is implemented as a command
-if {3 > 4} {
- puts {This will never happen}
-} elseif {4 > 4} {
- puts {This will also never 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
-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
-set i 0
-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
-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
-# semicolon character lose their special meanings. This feature makes Tcl
-# homoiconic. There are three items in the following list.
-set values {
-
- one\ two
-
- {three four}
-
- 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.
-set values {one two three four}
-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]
-lappend values { } ;# add a single space as an item in the list
-
-
-# Use "eval" to evaluate a value as a script
-eval {
- set name Neo
- set greeting "Hello, $name"
-}
-
-
-# A list can always be passed to "eval" as a script composed of a single
-# command.
-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}
-lappend command {Archibald Sorbisol}
-eval $command
-
-
-# A common mistake is not to use list functions when building up a command
-set command {set name}
-append command { 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}
-set command {set name $replacement}
-set command [subst $command]
-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.
-set replacement [list {Archibald Sorbisol}]
-set command {set name $replacement}
-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
-# several examples of this, below.
-
-
-# The "apply" command evaluates a string as a command.
-set cmd {{greeting name} {
- return "$greeting, $name!"
-}}
-apply $cmd Whaddup Neo
-
-
-# The "uplevel" command evaluates a script in some enclosing scope.
-proc greet {} {
- uplevel {puts "$greeting, $name"}
-}
-
-proc set_double {varname value} {
- if {[string is double $value]} {
- uplevel [list variable $varname $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
-proc set_double {varname value} {
- if {[string is double $value]} {
- upvar 1 $varname var
- set var $value
- } else {
- error [list {not a double} $value]
- }
-}
-
-
-#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.
-proc while {condition script} {
- if {[uplevel 1 [list expr $condition]]} {
- 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
-# stack.
-proc countdown {} {
- #send something back to the initial "coroutine" command
- yield
-
- set count 3
- while {$count > 1} {
- yield [incr count -1]
- }
- return 0
-}
-coroutine countdown1 countdown
-coroutine countdown2 countdown
-puts [countdown 1] ;# -> 2
-puts [countdown 2] ;# -> 2
-puts [countdown 1] ;# -> 1
-puts [countdown 1] ;# -> 0
-puts [coundown 1] ;# -> invalid command name "countdown1"
-puts [countdown 2] ;# -> 1
-
-
-```
-
-## Reference
-
-[Official Tcl Documentation](http://www.tcl.tk/man/tcl/)
-
-[Tcl Wiki](http://wiki.tcl.tk)
-
-[Tcl Subreddit](http://www.reddit.com/r/Tcl)
+--- +language: Tcl +contributors: + - ["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 +was awarded the [ACM Software System +Award](http://en.wikipedia.org/wiki/ACM_Software_System_Award) for Tcl. Tcl +can be used both as an embeddable scripting language and as a general +programming language. It can also be used as a portable C library, even in +cases where no scripting capability is needed, as it provides data structures +such as dynamic strings, lists, and hash tables. The C library also provides +portable functionality for loading dynamic libraries, string formatting and +code conversion, filesystem operations, network operations, and more. +Various features of Tcl stand out: + +* Convenient cross-platform networking API + +* Fully virtualized filesystem + +* Stackable I/O channels + +* Asynchronous to the core + +* Full coroutines + +* 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 +format. To achieve performance, Tcl internally caches structured +representations of these values. The list commands, for example, operate on +the internal cached representation, and Tcl takes care of updating the string +representation if it is ever actually needed in the script. The copy-on-write +design of Tcl allows script authors can pass around large data values without +actually incurring additional memory overhead. Procedures are automatically +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 +just want to get down to business with a tool that bends to their will. Its +discipline of exposing all programmatic functionality as commands, including +things like loops and mathematical operations that are usually baked into the +syntax of other languages, allows it to fade into the background of whatever +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 + +################################################################################ +## 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 +# 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, +# though, to escape special characters in procedure bodies and in strings that +# are formatted as lists. + + +################################################################################ +## 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 +# whitespace. Since every word is a string, in the simple case no special +# markup such as quotes, braces, or backslash, is necessary. Even when quotes +# are used, they are not a string constructor, but just another escaping +# character. + +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 + + +# Bracket introduces command substitution. The result of the command is +# substituted in place of the bracketed script. When the "set" command is +# 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 +# "incr" command increments the value of a variable and returns its value. +set greeting $greeting[ + incr i + incr i + incr i +] + + +# 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 + + +# 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 +set somevar { + This is a literal $ sign, and this \} escaped + brace remains uninterpreted +} + + +# In a word enclosed in double quotes, whitespace characters lose their special +# meaning +set name Neo +set greeting "Hello, $name" + + +#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 "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, "{*}". +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 +set person(gender) male +set greeting "Hello, $person(name)" + + +# A namespace holds commands and variables +namespace eval people { + 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" + + + +################################################################################ +## 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 +# 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 +# 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 { + namespace eval person1 { + variable name Neo + } +} + + +# The full name of a variable can always be used, if desired. +set people::person1::name Neo + + + +################################################################################ +## 4. Commands +################################################################################ + +# Math can be done with the "expr" command. +set a 3 +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 +# "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 provides a set of mathematical functions +set c [expr {pow($a,$b)}] + + +# Mathematical operators are available as commands in the ::tcl::mathop +# namespace +::tcl::mathop::+ 5 3 + +# Commands can be imported from other namespaces +namespace import ::tcl::mathop::+ +set result [+ 5 3] + + +# New commands can be created via the "proc" command. +proc greet name { + return "Hello, $name!" +} + +#multiple parameters can be specified +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 +# 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 +proc fold {cmd args} { + set res 0 + foreach arg $args { + set res [cmd $res $arg] + } +} +fold ::tcl::mathop::* 5 3 3 ;# -> 45 + + +# Conditional execution is implemented as a command +if {3 > 4} { + puts {This will never happen} +} elseif {4 > 4} { + puts {This will also never 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 +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 +set i 0 +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 +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 +# semicolon character lose their special meanings. This feature makes Tcl +# homoiconic. There are three items in the following list. +set values { + + one\ two + + {three four} + + 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. +set values {one two three four} +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] +lappend values { } ;# add a single space as an item in the list + + +# Use "eval" to evaluate a value as a script +eval { + set name Neo + set greeting "Hello, $name" +} + + +# A list can always be passed to "eval" as a script composed of a single +# command. +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} +lappend command {Archibald Sorbisol} +eval $command + + +# A common mistake is not to use list functions when building up a command +set command {set name} +append command { 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} +set command {set name $replacement} +set command [subst $command] +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. +set replacement [list {Archibald Sorbisol}] +set command {set name $replacement} +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 +# several examples of this, below. + + +# The "apply" command evaluates a string as a command. +set cmd {{greeting name} { + return "$greeting, $name!" +}} +apply $cmd Whaddup Neo + + +# The "uplevel" command evaluates a script in some enclosing scope. +proc greet {} { + uplevel {puts "$greeting, $name"} +} + +proc set_double {varname value} { + if {[string is double $value]} { + uplevel [list variable $varname $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 +proc set_double {varname value} { + if {[string is double $value]} { + upvar 1 $varname var + set var $value + } else { + error [list {not a double} $value] + } +} + + +#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. +proc while {condition script} { + if {[uplevel 1 [list expr $condition]]} { + 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 +# stack. +proc countdown {} { + #send something back to the initial "coroutine" command + yield + + set count 3 + while {$count > 1} { + yield [incr count -1] + } + return 0 +} +coroutine countdown1 countdown +coroutine countdown2 countdown +puts [countdown 1] ;# -> 2 +puts [countdown 2] ;# -> 2 +puts [countdown 1] ;# -> 1 +puts [countdown 1] ;# -> 0 +puts [coundown 1] ;# -> invalid command name "countdown1" +puts [countdown 2] ;# -> 1 + + +``` + +## Reference + +[Official Tcl Documentation](http://www.tcl.tk/man/tcl/) + +[Tcl Wiki](http://wiki.tcl.tk) + +[Tcl Subreddit](http://www.reddit.com/r/Tcl) |