CDevel
CDevel

Reputation: 25

apparent inconsistency read/write variable

I'm learning about Tcl just now. I've seen just a bit of it, I see for instance to create a variable (and initialize it) you can do

    set varname value

I am familiarizing with the fact that basically everything is a string, such as "value" above, but "varname" gets kind of a special treatment I guess because of the "set" built-in function, so varname is not interpreted as a string but rather as a name. I can later on access the value with $varname, and this is fine to me, it is used to specify varname is not to be considered as a string. I'm now reading about lists and a couple commands make me a bit confused

    set colors {"aqua" "maroon" "cyan"}
    puts "list length is [llength $colors]"
    lappend colors "purple"

So clearly "lappend" is another one of such functions like set that can interpret the first argument as a name and not a string, but then why didn't they make it llength the same (no need for $)?

I'm thinking that it's just a convention that, in general, when you "read" a variable you need the $ while you don't for "writing".

Upvotes: 0

Views: 53

Answers (2)

glenn jackman
glenn jackman

Reputation: 246932

A different look at the question: what Tcl commands are appropriate for list literals?

It's valid to count the elements of a list literal:

llength {my dog has fleas}

But it doesn't make sense to append a new element to a literal

lappend {my dog has fleas} and ticks

(That is actually valid Tcl, but it sets the odd variable ${my dog has fleas})

this is more sensible:

set mydog {my dog has fleas}
lappend mydog and ticks

Upvotes: 2

Donal Fellows
Donal Fellows

Reputation: 137627

Names are strings. Or rather a string is a name because it is used as a name. And $ in Tcl means “read this variable right now”, unlike in some other languages where it really means “here is a variable name”.

The $blah syntax for reading from a variable is convenient syntax that approximately stands in for doing [set blah] (with just one argument). For simple names, they become the same bytecode, but the $… form doesn't handle all the weird edge cases (usually with generated names) that the other one does. If a command (such as set, lappend, unset or incr) takes a variable name, it's because it is going to write to that variable and it will typically be documented to take a varName (variable name, of course) or something like that. Things that just read the value (e.g., llength or lindex) will take the value directly and not the name of a variable, and it is up to the caller to provide the value using whatever they want, perhaps $blah or [call something].

In particular, if you have:

proc ListRangeBy {from to {by 1}} {
    set result {}
    for {set x $from} {$x <= $to} {incr x $by} {
        lappend result $x
    }
    return $result
}

then you can do:

llength [ListRangeBy 3 77 8]

and

set listVar [ListRangeBy 3 77 8]
llength $listVar

and get exactly the same value out of the llength. The llength doesn't need to know anything special about what is going on.

Upvotes: 1

Related Questions