Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Help for newb

4 views
Skip to first unread message

A Ferenstein

unread,
Nov 1, 2004, 1:28:48 AM11/1/04
to
I'm new to TCL so, please be kind... I'm learning from reference document.
I'm having problem with something simple - a script to read contents of
file:
This works:
set ch [open test.tcl]
while {![eof $ch]} {puts [gets $ch]}

However, this doesn't - endless loop after printing the content of file.
set ch [open test.tcl]
while [expr ![eof $ch]] {puts [gets $ch]}

As far as I can see, these are logically TCL equivalent but obviously not.
Why?


David N. Welton

unread,
Nov 1, 2004, 2:10:50 AM11/1/04
to
"A Ferenstein" <epa...@hotmail.com> writes:

> I'm new to TCL so, please be kind... I'm learning from reference document.

Which one, if I may ask?

> I'm having problem with something simple - a script to read contents of
> file:
> This works:
> set ch [open test.tcl]
> while {![eof $ch]} {puts [gets $ch]}

Here, the condition is quoted, so it's passed to the while command to
evaluate it.

Even better, if you don't have an enourmous file:

set ch [open testfile]
puts [read $ch]

> However, this doesn't - endless loop after printing the content of file.
> set ch [open test.tcl]
> while [expr ![eof $ch]] {puts [gets $ch]}

Because the expr is evaluated before it's even passed to while in this
case, not being 'protected' by the {}. So the while command actually
"looks like" the while true line below.

while [expr ![eof $ch]] {puts [gets $ch]}
| |

| __________/
| /
while true {puts ...}

(if you use a fixed width font at least:-)

Does that help?

--
David N. Welton
Personal: http://www.dedasys.com/davidw/
Apache Tcl: http://tcl.apache.org/
Free Software: http://www.dedasys.com/freesoftware/
Linux Incompatibility List: http://www.leenooks.com/

A Ferenstein

unread,
Nov 1, 2004, 2:26:43 AM11/1/04
to
I'm using "TCL/TK Electronic Reference" by Charles Todd (October 1998) which
I downloaded from web.
Thanks for your TCL help.. Very much appreciates.


A Ferenstein

unread,
Nov 1, 2004, 4:05:00 AM11/1/04
to
Can I ask another question...?

What's the relationship between lists and strings inTCL?
I wrote this:
set zz "alex was here"
to me, this isn't a list because there's only one "word", yet, when I
perform
foreach i $zz {puts $i}
I get:
alex
was
here
so, a single "word" is now a list?


David N. Welton

unread,
Nov 1, 2004, 4:30:36 AM11/1/04
to
"A Ferenstein" <epa...@hotmail.com> writes:

When you call foreach with that 'word', it gets treated like (turned
into) a list.

A Ferenstein

unread,
Nov 1, 2004, 4:44:09 AM11/1/04
to
Does this mean that all commands that take "lists" as arguments can take
strings and convert them into lists?

Or is that all strings are lists and spaces are element delimiters?

Victor Wagner

unread,
Nov 1, 2004, 5:12:52 AM11/1/04
to
A Ferenstein <epa...@hotmail.com> wrote:
: Can I ask another question...?

: What's the relationship between lists and strings inTCL?

Relationship between strings and everything else in Tcl is quite simple
- everything is string. More precisely, everything has string
representation, which should be alone sufficient to reconstruct the
object (may be using some internal state of interpreter, such as channel
handles need).

So, numbers are strings, and lists are strings.

But non every string is list, as well as not every string is number.

If string can be broken into number of tokens using Tcl syntax rules, it
is a proper list. Otherwise it is not.

(One should never assume, that arbitrary string read from user (or some
user-supplied file, unless we are sure that some Tcl application wrote
correct string representation of some list there) is a list.

Try to run foreach for instance on string

"some string with unbalanced \{"
or "some string with \"quotes and\"such"

and it would give you an error message.


Donal K. Fellows

unread,
Nov 1, 2004, 5:13:50 AM11/1/04
to
A Ferenstein wrote:
> What's the relationship between lists and strings inTCL?
> I wrote this:
> set zz "alex was here"
> to me, this isn't a list because there's only one "word", yet, when I
> perform
> foreach i $zz {puts $i}
> I get:
> alex
> was
> here
> so, a single "word" is now a list?

In your line:


set zz "alex was here"

there were three words. The third word just had sub-words if you will,
and it is these sub-words that are the words of the list. :^)

If it looks like a list, it is a list. It might simultaneously be many
other things too (in this case, it's also a string - because *absolutely
everything* can be a string - and could even be a valid script if you
happen to have a command called 'alex' defined.) Unlike many other
languages, types in Tcl are more a matter of convention than strict rules.

If you're going to go back and forth between lists and strings a lot,
you probably want to look at the [split] and [join] commands. These help
stop you getting tripped up by the fact that not all strings are lists,
and other such stuff.

PS, it's good to see that you're trying these things out in a shell and
asking questions here on c.l.t; these are two of the very best ways of
learning.

Donal.

Donal K. Fellows

unread,
Nov 1, 2004, 5:19:11 AM11/1/04
to
A Ferenstein wrote:
> Does this mean that all commands that take "lists" as arguments can take
> strings and convert them into lists?

Yes. Lists are specially formatted strings.

> Or is that all strings are lists and spaces are element delimiters?

No. Here's a string (in quotes) that isn't a list: "a \{b c"

Donal.

Cameron Laird

unread,
Nov 1, 2004, 7:08:03 AM11/1/04
to
In article <87fz3u8...@dedasys.com>,
.
.
.
Even after that fix, I believe Mr. Ferenstein will be printing out a pair of
extra lines: <URL: http://phaseit.net/claird/comp.lang.tcl/fmm.html#eof >.

Bryan Oakley

unread,
Nov 1, 2004, 10:39:19 AM11/1/04
to
A Ferenstein wrote:
> Does this mean that all commands that take "lists" as arguments can take
> strings and convert them into lists?
>

No, not always. The general rule is "all lists are strings but not all
strings are lists". It is possible to construct strings that cannot be
converted into lists (at least, not through tcl's automatic
list-to-string conversion facilities).

> Or is that all strings are lists and spaces are element delimiters?

Spaces are treated as element delimiters in a normal case. If you have a
well formed list where one of the elements has a space in it, then
obviously (?) that space won't be treated as a delimiter then.

The best rule of thumb is to never use list commands on strings. You can
often get lucky but it's best not to rely on that luck. Better to
explicitly convert a string to a list unless you know for a fact that a
string is a well formed list.

sheila miguez

unread,
Nov 1, 2004, 11:28:02 AM11/1/04
to

Once you get through all of the other replies in this thread, take a
look at the wiki page on "shimmering." <http://wiki.tcl.tk/shimmer>

Based on which command you use to access a variable, you will access
different internal representations. e.g. switching between the "fast"
and the string internal representation inside of a loop may bog down
your script.


--
sheila

Donald Arseneau

unread,
Nov 1, 2004, 8:37:56 PM11/1/04
to
sheila miguez <s...@nospam.pobox.com.invalid> writes:
> Once you get through all of the other replies in this thread, take a
> look at the wiki page on "shimmering." <http://wiki.tcl.tk/shimmer>

This has prompted me to ask something I have put off for some time:

Is there an efficient command for testing equality of whole lists?

I have been using [string equal] which, despite the shimmering,
is much faster than element-by-element comparison in a [foreach]
loop. Also, [string equal] is inappropriate for lists of numbers.

I could really go for a comparison that compares each element
based on its internal representation (if both numeric, then uses
numeric comparison; else string comparison).


Donald Arseneau as...@triumf.ca

Donal K. Fellows

unread,
Nov 2, 2004, 6:11:29 AM11/2/04
to
Donald Arseneau wrote:
> Is there an efficient command for testing equality of whole lists?

Good question. I don't have a good answer though. Instead, I'd start by
focussing on the issue of what equality of lists actually means. After
all, you want to have the right type of equality, yes? :^)

> I have been using [string equal] which, despite the shimmering,
> is much faster than element-by-element comparison in a [foreach]
> loop. Also, [string equal] is inappropriate for lists of numbers.
>
> I could really go for a comparison that compares each element
> based on its internal representation (if both numeric, then uses
> numeric comparison; else string comparison).

And it seems you're taking the same sort of approach that I do. :^)

If you have lists of strings, it might be fastest to do one of these:
expr {[lrange $list1 0 end] eq [lrange $list2 0 end]}
(and you can optimize that quite a lot if one list is relatively static,
which is often the case.)

Otherwise you have to do an element-wise comparison. For example, here's
a basic comparator for numeric lists (ignoring float-comparison issues):
proc numlisteq {list1 list2} {
# Do this check first; it's fast!
if {[llength $list1] != [llength $list2]} {
return 0
}
foreach i1 $list1 i2 $list2 {
if {$i1 != $i2} {return 0}
}
return 1
}

For general numeric values, that's probably optimal. (And no, this isn't
simple to solve in other languages either. Well, not unless you're lucky
enough to be able to use someone else's pre-built solution.)

Donal.

0 new messages