---- '''Can one sugar coat away the set command?''' [LV] I sometimes see people ask about being able to write: a = 124 b = $a + 60 etc. And I wondered, what games could be played for this? The first thing I thought of was something where one created a variable via some kind of '''command'''. This command would, instead of creating a vanilla Tcl variable, create an object/major command (ala [Tk] widget creation) whose name was that of the variable. Within that proc would be sub/minor commands. With this kind of construct, one might write something like: create int a b c a = 123 b = $a + 27 c = $b / $a ; # Result would be 1 a = 3.1415 ; # Result would be 3 create float d d = 3.1415 ; # Result would be 3.1415 ... The problem comes when trying to use these things in other Tcl commands which do not know about them. I've not figured out what to do about that yet... Apparently though, [RS] beat me to the punch - see [Gadgets] and [Radical LAnguage Modification] for more details - also check out [procc]. You might also check out [let]. [RS] replies: In my first years with Tcl, I sometimes longed for that infix style of assignment (that's why I wrote these two pages), but in practical work I have no objections against the [set] command at all. Both of the solutions I offer have limitations and cost performance, so I'm not wild for [set] sugar. Well-readable code is more determined by careful variable and proc naming, and sensible arrangement of statements, than the assignment syntax, I think. ---- '''Why sugar coat Tcl?''' The following code fragment if {$x0 > [lindex $description 1]} { set x0 [lindex $description 1] } if {$x0 < 0} { set x0 0 } is typical Tcl: dollars, brackets, braces, assignments with set. Any Tcl novice will understand it within seconds. And still, after looking at it again, I felt a slightly salty taste, like of sweat (or tears). Such adjusting a variable to upper/lower bounds occurs frequently and could be factored out to a proc - once defined, each call would save 5 out of 6 lines of source code. When designing the (trivial) proc, I experimented with the "API look and feel", and finally wrote this: proc limit {_var "between" lower "and" upper} { upvar $_var var if {$var > $upper} { set var $upper } elseif {$var < $lower} { set var $lower } return $var } The argument list may look surprising. It reads quite natural, but the "parameters" ''between'' and ''and'' are never used. They are just "syntactical sugar" thrown into the arg list (that I marked them with quotes is another sugar that's irrelevant for Tcl, but helpful for the reader), so you can call the proc like limit x0 to 0 .. 1024 After reading this non-pseudocode myself, I thought it kind of sweet, and even more so when I imagined how other people would feel reading this in sources which they did not write but tried to understand. (-: Our software is often self-documenting, because nobody else does it, but this executable code comes close to a good comment :-) ---- Some years later, I have learnt that range constraints can be had simpler in pure Tcl: set x0 [expr {$x0<0? 0: $x0>1024? 1024: $x0}] which is not as nice reading as ''limit'' above, but more efficient "hard-core" Tcl. The advantage is that you don't have to look around for what ''limit'' exactly does. ([RS]) ---- '''The cost of sugar''': Everything has its price. Sugar arguments cost some extra time (about 24 microseconds per call in this case) and some extra bytes in memory. But they might still be worth it - if they save some seconds to people reading code, and maybe even give them a good taste in the mouth. Cf. [upvar sugar], [Steps towards functional programming] -- [Richard Suchenwirth] ---- '''args sugar''': When you collect a varying number of arguments with the args variable, and unpack them with the foreach {x y z} $args {break} construct, remaining arguments are discarded. This means you can add sort of comments in the call, see [A set of Set operations]: if [Set $S has "white" as element] {... ''args'' also helps to save curly braces, e.g. if you don't want to talk to Tcl like to a dog, proc please {args} {uplevel catch [list $args]} please close $f ---- '''Cheap sugar''': If you find yourself typing "expr" more often than you like, give it an alias (thanks to Jeff Hobbs for the tip!) like interp alias {} = {} expr Looks, and does, magic: now expr is also reachable by the equal sign: set a [= $b+$c] (yes, I know about expr{}, and sometimes care ;-) '''RS''' Even cheaper (=free) are fancy variable names, e.g. when using regexp to extract substrings from a string: regexp -nocase {subject: ?(.*)} $header -> subject A variable named "->" is assigned the whole matchstring, which we usually are not interested in. Looks good, costs nothing. ---- '''List access sugar:''' One Perlist once complained on comp.lang.tcl that accessing lists was so clumsy in Tcl, having to say set i [lindex $j 0] for, as they'd say in Perl, $i = $j[0]; If you feel the same, you can say proc $ {_L n} {upvar $_L L; lindex L $i} set i [$ j 0] [GWM] Mar 2008 How long have these typo/bugs been here? The correct proc is: proc $ {_L n} {upvar $_L L; lindex $L $n} set j {1 2 3 4 5 6} set i [$ j 0] Dollar is a legal proc name, if not followed by A-Za-z0-9_. A more elaborate version allows call by name or by value for a single element or a slice: proc $ {_L from {to {}}} { if {$to=={}} {set to $from} if [uplevel "info exists [list $_L]"] { upvar $_L L } else { set L $_L} lrange $L $from $to } so you can say set list {1 2 3 4 5} set i [$ list 1] ==> 2 set i [$ list 3 end] ==> {4 5} set i [$ {a b c d e f g} 2 4] ==> {c d e} Watch out for the space after the dollar, though. -- ''RS'' ---- '''Predicate sugar''': see [Predicates: on being and having] on how to wrap one-argument and element predicates into pretty natural English, like if {[is array A] && [has A 4711]} {...} ---- '''Version sugar''': Having defined the slightly ugly proc version {"of" pkg op vers} { expr [package vcompare [package provide $pkg] $vers] $op 0 } you can further on write (cf. [Unicode file reader]) the beautiful if [version of Tcl >= 8.1] {... BTW: In other languages, this won't be any sweet ;-) ''RS'' version("of","Python",">=","8.1") ---- '''Whitespace sugar''': Here's a trivial algorithm for reading a text file to a list, but note the "whitespace sugar": mentions of a variable are vertically aligned to indicate data flow ;-) proc file:lines {fn} { set f [open $fn r] set t [read $f [file size $fn]] close $f split $t \n } ;#RS ---- '''Either sugar''': Here's a lightweight ''try'' that makes catches, ''info exist'' or other routine tests look more pleasing: proc either {body1 "or" body2} { if {[catch {uplevel $body1} t]||$t==""} {uplevel $body2} } # e.g.: either {set x $y} or {set x 0} ''KBK'' (10 January 2001) -- Watch out for [[break]], [[continue]] and [[return]] in ''body1'' and ''body2''. A production-grade implementation of ''either'' would adapt the code from [try ... finally ...], which handles anything but the problematic [[return -code]]. ---- [Custom curry] is also spicy for incorporating constant arguments into a [proc] or ''[interp] alias'', e.g. interp alias {} -> {} set res -> 0 ;# equivalent to: set res 0 ---- [Math sugar] - [Arts and crafts of Tcl-Tk programming] - [Category Mathematics]