- Data/code duality.
- String/integer duality.
- String/list duality.
RS: The (outer) curlies are not part of the list - they are added, or parsed away, when needed.Tcl lists are not fundamentally different from strings, rather, I'd say they are a "view" on strings. Just as "42" can be viewed as string, or integer, it can also be viewed as a one-element list. Except if you introduce your own tagging convention, there is no way of telling whether a list is in reality a string - in the other direction, only strings that cannot be parsed as lists (unbalanced braces, quotes..) cannot be viewed as lists. But for your concrete error-printing problem: if you simplify the interface to "a list of one or more error messages", you can have the desired effect with
puts [join $errormessages \n]Just make sure that the "one message" case is properly nested, e.g.
errorprint {{This is a one-liner}}
errorprint "{This too, with a $variable reference}" ;# braces in quoted strings allow substitution
errorprint [list "another $variable reference"]
errorprint {{Two messages:} {This is the second}}The following discussion was extracted from Tcl Oddities
(escargo 10/25/2002)-- Rather than start a new page for this, since this will be for something I consider to be a Tcl Oddity, I thought I would start the discussion here. (10/27/2002 -- I'm fine with the discussion moving to this new page).Here is my issue. Some things in Tcl are values. Other things in Tcl are variables (or other holders of values). Some values are special (like identifiers for open files in Tcl and perhaps for other open channels). Most Tcl commands take expressions that evaluate to values for their arguments (with the notable exception of lappend).Some other programming languages have the notions of lvalue and rvalue [2], which I believe I first read about in association with the BCPL programming language [3].The lvalue was (at least conceptually) the address where a value was assigned. The rvalue was the value in an address. The terms lvalue and rvalue came from the order in which they were ordered in an assignment statement:
value1 := value2Implicity the address of value1 was assigned the value from the contents of the address of value2. I believe in Tcl this would be equivalent to
set value1 $value2where the $ sign signifies get the value of.So here's the deal. In commands like the list operations or array operations, where does it really make sense from a implementation standpoint to use an rvalue or an lvalue? Is it (or would it be) 'more efficient for something like, say lindex, to take an expression that evaluates to a list (an rvalue) instead of an lvalue (the name of a variable whose value is a list)?moth You seem to be asking whether [lindex {set of known choices} $i] should be made illegal?escargo I'm asking a question of efficiency. You are asking about implications of making a language change that I am not proposing. I often seem to have trouble helping people understand what I am saying, either because I express myself poorly, or because the assumptions that I make when I am expressing an idea do not match the assumptions of the readers. I am trying to get at some implications of Tcl's implementation. I am not trying to change the language. -- 10/26/2002moth I actually asked that question wrong. Let's take a step back... an lvalue is a symbol, an rvalue is a value which might be referred to by a symbol. However, in tcl it's conceivable that any value can be used as a symbol. So one of the implications of tcl's implementation is: you can use a wider variety of constructs in an rvalue context than in an lvalue context. More generally, using an lvalue in tcl doesn't give you efficiency gains -- it does allow you to modify the symbol. Under the covers, an rvalue is a pointer and an lvalue is a pointer. The lvalue is a pointer to a symbol which itself refers to another pointer which refers to what we're calling an rvalue. Passing an lvalue instead of an rvalue either defers this step slightly (if you had an lvalue already), or requires the additional steps of creating the lvalue and then dereferencing the lvalue.escargo I think I follow that argument. However, it was not clear to me that in cases where the rvalue can be gotten by the dereference of the lvalue, whether doing it outside the command or inside the command was more efficient. (10/27/2002)
escargo Is there a significant runtime burden to create a list value from an explicit deference when evaluating command argument or is there some kind of lazy evaluation so that the value of the list is only generated if it is needed? (Amended 10/27/2002 to make my question more clear.)moth I can't figure out this question: lindex always needs the value of the list -- what am I missing?escargo The value of the list can be gotten two different ways and potentially at two slightly different times, depending on language semantics and implementation. (I have done a lot of programming in Icon, where procedure parameters are passed either by value for primitive types or reference for structure types. That allows the procedure to modify the structure types by side effect, since it does not have to return a value that might get assigned to one of the arguments by the caller. I presume this design choice was made to avoid a lot of copying of structures when passing parameters. Contrasting this with Tcl, I understood Tcl to be doing a lot of copying of values -- rvalues -- when invoking procs. That copying would seem to be a source of inefficiency, both in terms of performance and memory consumption.--10/27/2002)If I understand Tcl's implementation now, for lindex the arguments are expanded before the command gets them. That is, the command takes a rvalue of a list. What if, instead, the other way was true. What if lindex took the lvalue of the list (in Tcl the name of the variable whose value is the list) instead. Is there any performance benefits to having commands that worked that way instead? (I can see where in some cases there might be, and other cases not. I just can't tell if there has ever been any discussion and explanations about it.)moth See WHD's discussion, below. Essentially, tcl data can be represented, under the covers, in more than one format, and tcl tends to hang onto data in the format it most recently needed to use. That is: if you've been manipulating the data as a list, tcl uses a different internal representation than if you've been manipulating the data as a string. Conversion between these representations is automatic, when needed.Note also that all data in tcl is considered immutable, in a sort of copy-on-write fashion. You can change what a symbol refers to, but any other references to that data are left alone. It's physically possible to violate this rule, but that's classified as a bug.Finally, note that there are efficiency issues in tcl with lists. In particular, because of the needs of error recovery, the fact that lreplace takes an rvalue can be significantly less efficient than someone might think. That is, if you're doing
set l [lreplace $l $j $j $newvalue]The current bytecode compiler tries to allow for the possibility that there could be an error between the invocation of lreplace and the invocation of set. Thus, two copies of the list l are needed (one before, one after). For more discussion of this topic, see Shuffle a list, and lset.
escargo 10/30/2002 -- I have wondered whether there might be any use or advantage to being able to declare a tcl variable as immutable (kind of like final in Java, I suppose). I was thinking how hard it is to really guarentee that a variable has a value that does not change. My conclusion what that it is not easy to determine.(My reason for wondering has its roots in this structure:
if {0} {
commentary....
}It's not obvious what the intent of the commentary was. However, if you had something like this:
final {set docstring 0}
if {$docstring} {
inline documentation
}
final {set local_debugging 0}
if {$local_debugging} {
# local debugging code; enable for debugging info
}If the JIT compiler could rely on docstring and local_debugging to always be 0, then these blocks could be optimized away. I don't know if the JIT compiler could do this or not, but I was wondering.)escargo Consider if dictionary was implemented with references instead of rvalues. That would mean that passing a reference (a handle?) by value to a proc would mean that the proc could easily modify the dictionary without having to do an upvar to get at it. Is that true, or just fuzzy thinking on my part?moth Uh... you mean, imagine if tcl implemented arrays rather than dictionaries? Why are you asking this question?escargo (I don't understand this response. Tcl implements array now and dictionary is only proposed. Since dictionary is not implemented yet, the semantics of it are not yet determined. It could be different from array in several respects.)moth dictionary is implemented, it's just not Batteries Included. While I've not played with the implementation, according to the docs I've read, it uses rvalues -- that's the whole point, the thing which distinguishes dictionaries from arrays is that dictionaries can be rvalues while arrays can't. There has been no implemented notation to properly express an array as an rvalue: tcl can't freely convert an array to string form and back again.escargo You mean that there is an implementation of dictionary but that it is not in the core of Tcl? What should that mean for TIP #111?http://www.purl.org/net/bonnet/pub/dictionary.tar.gz
escargo Is this (the notion that some or more commands should take rvalues instead of lvalues) outside the mainstream in the way of thinking about Tcl: everything is a string and everything is passed to procs by value? (Clarification added 10/27/2002)moth I can't figure out what you're asking. Perhaps because what you seem to be asking is whether Tcl is outside the mainstream of Tcl.(The seeming is only because our communication is not yet clear enough. I still need to express myself more clearly. I hope I am not asking for anything contradictory; I'm really just trying to figure out why so many things are passed by value instead of by reference. The answer might be, "Because we have always done it that way." I don't know yet. -- 10/26/2002)WHD: You ask, "What if lindex took the lvalue of the list (in Tcl the name of the variable whose value is the list) instead. Is there any performance benefit....?" The answer is no, and here's why:
set mylist {a b c d} ;# Creates a new Tcl string object
set v1 [lindex $mylist 0] ;# mylist expands to a string, which is then
;# interpreted as a list. A new Tcl list object
;# is created.
set v2 [lindex $mylist 1] ;# mylist expands to a Tcl list object (i.e.,
;# a pointer).The list creation expense is paid the first time the thing is viewed as a list, and not again (unless something is done to break that representation. Now, suppose lindex took an lvalue--that is, a variable name--instead. In Tcl, that would be expressed:
set mylist {a b c d} ;# Creates a new Tcl string object
set v1 [lindex mylist 0] ;# mylist expands to a string, which is then
;# interpreted as a list. A new Tcl list object
;# is created.
set v2 [lindex mylist 1] ;# mylist expands to a Tcl list object (i.e.,
;# a pointer).The only difference between the two cases that I can see is that in the latter case the first argument to lindex has to be a variable name, rather than possibly some more general expression.Tcl is actually very like C in that regard: everything is passed by value, with variable names standing in for C pointers. The difference is that unlike C there are no "anonymous" lvalues--perhaps that's what you're keying on?Your concern seems to be that $mylist expands to {a b c d}, which must then be turned into a new list. In the old pre-8.0 days, that was true.escargo Yes, I think that addresses my concern. I was not appreciating the advantages of the new "dual-ported" internal organization of Tcl, post 8.0.