[Richard Suchenwirth] 2002-12-16 - For people experienced in other languages, it may be interesting to compare code snippets between [Tcl and other languages], to demonstrate similarities and differences. Please add more from your experience! **[C]** void countdown(int n) { | proc countdown {n} { int i; | for(i=n; i>0; i--) { | for {set i $n} {$i>0} {incr i -1} { printf("%d...\n", i); | puts $i... } | } } | } My alternative loop shows the relation between For and While: void countdown(int n) { proc countdown {n} { subroutine countdown (i) while (n>0) { while {$n>0} { do printf("%d...\n", i); puts $n... write (*,*) n n--; incr n -1 n=n-1 } } while (n>0) } } endsubroutine The main difference is that a FORTRAN while loop is executed at least once; a for loop can terminate before entry. '''[C]''' /* The above could be: */ void countdown(int n) { for (; n>0; n--) printf("%d...\n",n); } [slebetman]: which has an equivalent '''[Tcl]''' construct: proc countdown {n} { for {} {$n>0} {incr n -1} { puts $n } } * Everything is a command in Tcl. Function definitions are done with the [proc] command, assignments with the [set] command, in/decrementation of integers with the [incr] command. * Retrieving the value of a variable goes with prefixed $ sign - while mentioning the name of a variable it is not used * Variable type rarely matters and is not declared. Only [incr] would complain if its first argument is not an integer ''([MG] Well, there isn't really "variable type" - everything is a string. [incr] just expects a var to be set to a string that looks like an integer...)'' * Formatting values into strings goes in simple cases by straight string concatenation like in $i.... for stronger control, [format] is comparable to ''sprintf'' * [puts], unlike ''printf()'', emits a newline by default. **Fortran** [AM] The above proc could look like this in Fortran (90): subroutine countdown( n ) integer :: n integer :: i do i = n,1,-1 write(*,*) i, '...' enddo endsubroutine The main difference with either C or Tcl is that in Fortran the do-loop is very different kind of control construct: it is really an iteration over a ''predefined'' set of values, whereas in C and Tcl the three parts gouverning the iteration can be almost anything. (The Fortran control variable can be an integer only). **[Scheme]** (define foo 42) | set foo 42 (define (square x) (* x x)) | proc square x {expr $x * $x} (define bar (square foo)) | set bar [square $foo] (define grill '(square foo)) | set grill {square $foo} * Functions are also defined with the [proc] command. Their result is the last executed command in the body * Arithmetics is not done with prefix functions, but Infix-style like in C, in the argument(s) to the [expr] command * [set] is used for variables, [proc] for functions - no unified ''define'' in Tcl (except if you write one - see the [Scheme] page ;-) * Tcl commands on toplevel are not enclosed in parens. Embedded commands like the first call to ''square'' go into brackets for eager evaluation; the equivalent to quoting is curly braces around a string (define (abs x) | proc abs x { (cond ((> x 0) x) | expr { $x > 0? $x : ((= x 0) 0) | $x == 0? 0 : ((< x 0) (- x)))) | $x < 0? -$x} | } | or: proc abs x {expr abs($x)} | or: proc abs x {expr {$x<0? -$x: $x}} * [expr] can, with the ?: operator, operate like ''cond'' * It also has built-in math functions that can be exported in a one-liner as shown ([Importing expr functions]) * Tcl needs less parens (which often amount to braces or brackets) (define (abs x) | proc abs x { (if (< x 0) | if {$x < 0} { (- x) | expr -$x x)) | } else {return $x} * [If],[for],[while] take a test expression in infix notation, as used for [expr] * The branches of an [if] must be commands - in place of the ''[return] x'' one might write ''set x'' **[LaTeX]** \IfFileExists{foobar}{ | if {[file exists foobar]} { \saved@cnt=\cnt | set saved@cnt $cnt \input foobar | source foobar \cnt=\numexpr\saved@cnt+1\relax | set cnt [expr {${saved@cnt} + 1}] }{\errmessage{No file foobar}} | } else {error {No file foobar}}} * Tcl and (La)TeX both have braces as the chief ''delimiter'' — one has to do a bit of work to construct a block of code where they are not balanced — and may use them around data just as well as around blocks of code, but in Tcl you ''must'' leave whitespace between a closing "}" and a following "{", whereas in (La)TeX people normally don't, although you may leave whitespace there. * Tcl and (La)TeX both admit, even reward, a functional style of programming: on the Tcl side commands return values which can be used as arguments for other commands, whereas on the (La)TeX side a macro expands to text which can contain other macros. In both cases, assignments have to be requested explicitly and take the form of separate commands. '''Some differences:''' %| Tcl | (La)TeX |% &| Tcl has '''explicit separators''': newlines or semicolons between commands, whitespace between words, etc. Only some forms of variable and backslash substitution exhibit greedy parsing. | '''Parser is greedy''' and considers a syntactic entity to consist of everything up to the first token that cannot be part of it (this is a common source of strange errors and also the reason for most uses of `\relax`). LaTeX often replaces greedy TeX constructions by self-delimited constructions (e.g. `\frac` instead of `\over`), but sometimes the underlying greediness shines through. |& &| Commands and variables are different things. | Variables are mostly a kind of command: macros defined to expand to the values they store. There are some families of ''registers'' which are purely variables, but even these are typically accessed via (and often informally identified with) particular commands. |& &| '''Substitution''' is a '''one-step''' process; one needs an explicit [subst], [eval], or the like to do more than one round of substitution | '''Substitution is unbounded'''; the parser typically expands the next token repeatedly until an unexpandable token is found. |& &| Contexts are tied to command invocations: a proc-local context comes into existence when the proc is called and ceases to exist when the proc returns, a [namespace] context is placed onto the stack by e.g. a [namespace eval] command and is removed when that command returns. [upvar] and [uplevel] give access to contexts other than the current. | Contexts (''groups'') are generally independent of command expansion, although each environment (`\begin{somehting}`…`\end{something}`) also begins and ends a group. It is not possible to access saved values. In order to export a value from a group one must either make a global assignment or operate on tokens past the end-of-group. |& &| Recursion should be used with restraint; recursion depth is often limited. Imperative repetition constructions are preferable. | Tail-end recursion is the main approach to achieve repetition. |& ---- See also [BOOK Programming Language Examples Alike Cookbook], http://www.merd.net/pixel/language-study/scripting-language/ and [CL]'s ill-maintained personal notes on language comparison [http://phaseit.net/claird/comp.lang.misc/language_comparisons.html]. ---- [Tcl and other languages] | [Category Advocacy]