The following three switch statements will all behave differently:
switch -exact -- foo {
bar {puts bars}
# three word comment
default {puts lose}
}
...and...
switch -exact -- foo {
bar {puts bars}
# four word comment line
default {puts lose}
}
...and...
switch -exact -- foo {
bar {puts bar}
# this foo junk
default {puts lose}
}
The first will print the string "lose", as one would expect.
The second, fails, with the error:
extra switch pattern with no body
The third also fails, and says:
invalid command name "junk"
I don't know about anyone else, but this strikes me as being incorrect, or
at least silly.
After poking through the source, I found that Tcl doesn't strip comments
from the body of a switch statement, which is what causes this anomalous
behaviour.
Any opinions?
_____________________________________________________________________
| My opinions may have changed, but | When someone says "I want a |
| the fact that I am correct has not. | programming language in which |
| - random cool quote | I need only say what I want |
|=====================================| done," give him a lollipop. |
| "Share and Enjoy" "jabanero" |===============================|
| Aaron Goldstein - bred...@andrew.cmu.edu - mo...@cs.cmu.edu |
|_____________________________________________________________________|
You have discovered basic rule #12 of Tcl: don't put comments inside
switch statements. Don't feel bad, Dr. John actually slipped up on
this one in the release version of Tk4.2 (fixed in p2).
--
Jeffrey Hobbs jho...@cs.uoregon.edu,@or.cadix.com
Software Engineer, Oregon R&D office: 541.683.7891
CADIX International, Inc. fax: 541.683.8325
URL: http://www.cs.uoregon.edu/~jhobbs/
From a Tcl man page:
If the first non-blank character in a command is #, then
everything from the # up through the next newline character
is treated as a comment and ignored.
This implies that you can only put comments in a place, where tcl
expects a command eg:
puts var val ;# assign val to var
/Flemming
According to Flemming Madsen <f...@cci.dk>:
:In article <Pine.SOL.3.95L.97040...@unix14.andrew.cmu.edu>,
Okay, but how does this explain why a varying comment line causes 3
different behaviors in the script? I will grit my teeth and attempt
to stand this behavior (which causes the folk for whom tcl was intended
no small amount of grief). But, I think that it is not unfair to expect
in return that Tcl behave consistently.
--
Larry W. Virden INET: lvi...@cas.org
<URL:http://www.teraform.com/%7Elvirden/> <*> O- "We are all Kosh."
Unless explicitly stated to the contrary, nothing in this posting should
be construed as representing my employer's opinions.
Flemming Madsen <f...@cci.dk>:
:From a Tcl man page:
:
: If the first non-blank character in a command is #, then
: everything from the # up through the next newline character
: is treated as a comment and ignored.
:
:This implies that you can only put comments in a place, where tcl
:expects a command eg:
lvirden <lvi...@cas.org>:
:Okay, but how does this explain why a varying comment
:line causes 3 different behaviors in the script? I will
:grit my teeth and attempt to stand this behavior (which
:causes the folk for whom tcl was intended no small amount
:of grief). But, I think that it is not unfair to expect
:in return that Tcl behave consistently. -- Larry
Tcl IS behaving consistently. In the three cases you refer to, the #
did NOT start a comment (because the # was where a *pattern* was
expected).
I happen to think the rule for # is brain-dead, but at least it's
applied consistently.
-- Nick Reingold
Is this brain-dead behaviour preserved in 8.0? That is, does 8.0
continue to treat # as a command, or does the compiler have a lexical
phase that throws away comments in the usual way? I can not believe that
anyone WANTS # to be a command!!
--
Marc H. Graham ma...@neovision.com
VP Software Engineering 412 621 8333
NeoVision Hypersystems 412 621 8337 (fax)
5001 Baum Blvd
Pittsburgh, PA 15213
And what, exactly, is inconsistent with this behavior? Wait! Don't
answer that; I will. What is inconsistent is that the switch statement
and comment processing is different for tcl than for many other
languages. The switch statement and comment processing within tcl is
100% consistent with the rest of tcl.
One has to remember that there is no such thing as a comment in tcl.
There is a comment _command_, but it's not really a comment. Just a
no-op command. As such, it can only be used where commands can be used.
In this case one should also remember that the switch statement simply
takes a list of patterns and bodies. There must be a body for each
pattern, and the body must be executable. When one does something like
this:
switch -exact -- foo {
bar {puts bars}
# three word comment
default {puts lose}
}
The "#" is a pattern, and "three" is the body for that pattern. It may
*look* like a comment, but it's not. It's really no different that
something like
set foo "some string with a # sign in it"
Now, you don't really expect '# sign in it'" to be treated as a comment
do you? Of course not. The simple argument is "because it's inside
quotes". Well, '# three word comment' in the above switch statement is
inside quotes too. Only the quote character is a curly brace instead of
a double quote mark and thus #, three, word and comment are all treated
as members of a list.
(wow, talk about quoting hell... more single quotes, double quotes and
the word "quote" than squashed armadillos on a texas state highway :-)
The problem is, while tcl is (arguably) syntacticly pure, humans are
not. Even though we know in our hearts that # is just a command, we wish
it to be otherwise. We *think* it is a real comment and thus expect it
to behave as one; only, it doesn't.
--
Bryan Oakley mailto:oak...@healthcare.com
Software Engineer http://www1.clearlight.com/~oakley/
Healthcare Communications, Inc. http://www.healthcare.com/
I do. Or at least, I'm perfectly happy with it being a command. One of
the most wonderful things about tcl is how few parsing rules there are
to remember. Sure, adding one more rule for comments wouldn't be that
bad, but it's also not necessary. Tcl is absolutely rock-solid in how it
interprets things which makes it quite easy to figure out what a line of
code will do.
The problem is that this will be an incompatible change, and we're trying
as hard as we can to keep Tcl 8.0 backwards compatible, even if doing so
preserves warts like the current commenting mechanism. For example,
if there are switch commands that actually use the string "#" as the
switch pattern, they would break if we start treating "#" as a comment in
that situation.
Any chance you could introduct a *new* commenting mechanism to go along
with the old? Perhaps using the ! or @ character or (*gasp*) //. That
way we could all migrate to the new mechanism at our leisure.
FWIW: I really applaud your attempt at backwards compatibility. I think
it's crucial to get acceptance of 8.0. I know we'll be very hesitant to
move our product over, but the fewer incompatibilities there are, the
more likely we are to upgrade. Incompatibilities can come at 8.1 or 8.2,
but I think it's important to get as many people migrated to 8.0 as soon
as possible.
There are such switches. In real, live code.
Most who care probably already know this, but
perhaps there's value in making it explicit.
--
Cameron Laird http://starbase.neosoft.com/~claird/home.html
cla...@NeoSoft.com +1 713 623 8000 #227
+1 713 996 8546 FAX
There are such switches. In real, live code.
Making "#" be handled specially would not only break real live switches
but it would break similar constructions. Consider:
expect {
pattern1 action1
# foo
pattern2 action2
}
In this example "#" is a pattern to be matched! So if you contemplate
"fixing" Tcl, you potentially break any proc that anyone has ever
written. Some people would argue, of course, that this is a good
thing but the fact is that there's no way for Tcl to know whether
anything in a string is a comment or not. Consider this:
set x {
pattern1 action1
# foo
pattern2 action2
}
Whether "# foo" is a comment or literal data depends upon later use of $x.
Selecting different characters (//) doesn't help at all.
Don
: Any chance you could introduct a *new* commenting mechanism to go along
: with the old? Perhaps using the ! or @ character or (*gasp*) //. That
: way we could all migrate to the new mechanism at our leisure.
:
: FWIW: I really applaud your attempt at backwards compatibility.
By introducing *any* new comment character or string *you* break backward
compatibility!
: Incompatibilities can come at 8.1 or 8.2, but I think it's important to
: get as many people migrated to 8.0 as soon as possible.
Incompatibilities should happen at major releases only (9.0), not minor
releases, and best be avoided at all. IMHO never worth for comments!
Bye, Heribert (da...@ifk20.mach.uni-karlsruhe.de)
According to Nick Reingold <rein...@corona.research.att.com>:
:Tcl IS behaving consistently. In the three cases you refer to, the #
:did NOT start a comment (because the # was where a *pattern* was
:expected).
Okay, I am sorry for being dense here. But if someone would have
the patience to explain (feel free to use email if necessary) the
above statement that's been made several times in this thread I would
love to hear how getting 3 different results is 'consistent behavior'.
I understand about # being a command. I've been around this newsgroup
since the beginning of it, and see this problem at least every month -
sometimes every day. I provide a limited amount of support for tcl
for a large group of non-programmers who have to use tcl daily.
The inconsistency I speak of is between the last two cases. Why
is Tcl behaving consistently to generate one error when the # pattern
has 4 arguments than when it has 3?
Here to refresh your memory is the account:
From: Aaron G Goldstein <bred...@andrew.cmu.edu>
Message-ID: <Pine.SOL.3.95L.97040...@unix14.andrew.cmu.edu>
> The following three switch statements will all behave differently:
>
> switch -exact -- foo {
> bar {puts bars}
> # three word comment
> default {puts lose}
> }
>
> ...and...
>
> switch -exact -- foo {
> bar {puts bars}
> # four word comment line
> default {puts lose}
> }
>
> ...and...
>
> switch -exact -- foo {
> bar {puts bar}
> # this foo junk
> default {puts lose}
> }
>
> The first will print the string "lose", as one would expect.
>
> The second, fails, with the error:
> extra switch pattern with no body
>
> The third also fails, and says:
> invalid command name "junk"
>
> I don't know about anyone else, but this strikes me as being incorrect, or
> at least silly.
Interesting note - if I delete the word line from the second example, I get
the word lose output instead of the error!
Short answer: because the # pattern has one argument; after that are
more patterns and actions. It only *looks* like all that belongs to the
# pattern.
I don't think you can see the trees for the forest (the last switch
argument is the forest, the list elements are the trees...) The last
argument to the switch statement is a list. This list must have an even
number of patter/action elements. It's in the man page, but you do have
to infer it -- it doesn't come right out and say you must have an even
number of elements.
Whitespace will make this easier to explain. Here's the first case:
# example A1
switch -exact -- foo {
bar {puts bar}
# four word comment line
default {puts lose}
}
... which is exactly the same as this:
# example A2
switch -exact -- foo {
bar {puts bar}
# four
word comment
line default
{puts lose}
}
Remember, the last argument to switch is a list of elements, and there
must be an even number of them. Notice that because of the 'comment', we
are short one action. Hence the syntax error.
Next case:
# example B1
switch -exact -- foo {
bar {puts bar}
# three word comment
default {puts lose}
}
..is the same as this:
# example B2
switch -exact -- foo {
bar {puts bar}
# three
word comment
default {puts lose}
Now we have an even number of list elements, so no syntax error.
To futher hammer this thing home, here is a quick test using a slight
variation of B1:
proc three {} {
puts "'\#' was matched"
}
proc comment {} {
puts "'word' was matched."
}
foreach foo [list bar \# word bogus] {
switch -exact -- $foo {
bar {puts bar}
# three word comment
default {puts lose}
}
}
-----------------
$ tclsh7.6
bar
'#' was matched
'word' was matched.
lose
Notice that '#' is treated as a pattern, and calls 'three' when it is
matched. Also, 'word' is a pattern with 'comment' being it's command.
Does that make the consistency more apparent? It's consistent because
the # character is not a comment in this case, just an element in a list
passed to the switch statement. If that 'comment' has an odd number of
words, it's going to bust the switch statement (if the switch is
otherwise correct...).
Perhaps we should treat all this as a bug in the man page. If the man
page was more explicit about how the list of elements is processed,
would that help?
when you give 3 different inputs, and it treats each according to its
documented rules, it's consistent, isn't it?
>I understand about # being a command. I've been around this newsgroup
>since the beginning of it, and see this problem at least every month -
>sometimes every day. I provide a limited amount of support for tcl
>for a large group of non-programmers who have to use tcl daily.
>
>The inconsistency I speak of is between the last two cases. Why
>is Tcl behaving consistently to generate one error when the # pattern
>has 4 arguments than when it has 3?
it's not the #, it's the switch. the switch expects the last string to parse
into a list with an even number of elements,
pattern code pattern code ...
the poster expected tcl to treat the # in the string as a comment, in a place
where tcl is well-documented not to be expecting # to start a comment... like
it doesn't in uplevel #0 or upvar #0.
so when the # had "3 arguments", the # and "its arguments" contributed 4 list
elements, which totalled an even number along with the other bits; when "it had
4 arguments" the switch got an odd-lengthed list and spewed.
ditto being mostly used here to communicate derision, not direct quoting.
>From: Aaron G Goldstein <bred...@andrew.cmu.edu>
>Message-ID: <Pine.SOL.3.95L.97040...@unix14.andrew.cmu.edu>
>
>> The following three switch statements will all behave differently:
>>
>> switch -exact -- foo {
>> bar {puts bars}
>> # three word comment
>> default {puts lose}
>> }
>>
>> ...and...
>>
>> switch -exact -- foo {
>> bar {puts bars}
>> # four word comment line
>> default {puts lose}
>> }
>>
>> ...and...
>>
>> switch -exact -- foo {
>> bar {puts bar}
>> # this foo junk
>> default {puts lose}
>> }
>>
>> The first will print the string "lose", as one would expect.
>>
>> The second, fails, with the error:
>> extra switch pattern with no body
>>
>> The third also fails, and says:
>> invalid command name "junk"
>>
>> I don't know about anyone else, but this strikes me as being incorrect, or
>> at least silly.
>
>Interesting note - if I delete the word line from the second example, I get
>the word lose output instead of the error!
of course. the switch sees four patterns,
bar # word default
and foo only matches default, thus the switch executes the code paired with
default which is "puts lose".
now
i
have
to
put
more
lines
here
to
try
to
get
istar's
new
braindead
fascist
news
server
to
think
there's
more
new
text
than
included
text
-
as
if
the
discussion
would
be
clear
if
you
didn't
happen
to
see
all
the
original
articles,
as
i
have
not
in
this
case
myself.
Reminder
SYNOPSIS
switch ?options? string pattern body ?pattern body ...?
switch ?options? string {pattern body ?pattern body ...?}
>> The first will print the string "lose", as one would expect.
>> switch -exact -- foo {
>> bar {puts bars}
>> # three word comment
>> default {puts lose}
>> }
Reformat this:
switch -exact -- foo {
bar {puts bars}
# three
word comment
default {puts lose}
}
>> The second, fails, with the error:
>> extra switch pattern with no body
>> switch -exact -- foo {
>> bar {puts bars}
>> # four word comment line
>> default {puts lose}
>> }
switch -exact -- foo {
bar {puts bars}
# four
word comment
line default
{puts lose}
} ^^^^^^^^^^^ ^^^^^^^
pattern no body
>> The third also fails, and says:
>> invalid command name "junk"
>> switch -exact -- foo {
>> bar {puts bar}
>> # this foo junk
>> default {puts lose}
>> }
switch -exact -- foo {
bar {puts bar}
# this
foo junk <--- matches "foo", calls "junk"
default {puts lose}
}
>Interesting note - if I delete the word line from the second example, I get
>the word lose output instead of the error!
switch -exact -- foo {
bar {puts bars}
# four
word comment
default {puts lose} <--- no cases match, so call default body
}
According to Bryan Oakley <oak...@healthcare.com>:
:lvi...@cas.org wrote:
:>
:> Okay, I am sorry for being dense here. But if someone would have
:> the patience to explain (feel free to use email if necessary) the
And many of you have - some politely, and some quite rudely. Sorry
that you felt so incensed that instead of ignoring my posting and moving
on with your life some folk felt it necessary to flame me.
:Short answer: because the # pattern has one argument; after that are
And here was the catch that I was missing. That in some cases, the
tcl interpreter treats everything after a # as 'a part of the # command'
and in at least one case - switch - the interpreter associates only
the first word (sometimes!) with the # and treats the remainder of
the line as being another command.
:Perhaps we should treat all this as a bug in the man page. If the man
:page was more explicit about how the list of elements is processed,
:would that help?
I don't know whether it would help in general or not. The behavior of
tcl to treat plain text as data or commands , depending on the vagarity
of the command in process, is pretty tough to explain in a mere
man page.
Not exactly. You are still missing something. In the case of the switch
statement the interpreter isn't associating anything with the #
character. It's just an element in a list that is an argument to the
switch command. Based on where that character sits in the list it's
either treated as a pattern or body. No magic associations going on
here.
The same is true whether we're talking about '#' or expr or if or while
or ..... Nowhere in the tcl language does the interpreter associate one
word with the # and the remainder of the line as being another comand
(well, unless you count "# comment! ; set foo bar". The only time # is
treated as the comment character is if it appears where a command could
appear (from the man page: "at a point where tcl is expecting the first
character of the first word of a command"). The same can be said of
'expr' or 'if' or ... these are only treated as commands if they appear
where a command is expected. Otherwise they are just another word in a
list (or string, or whatever).
> :Perhaps we should treat all this as a bug in the man page. If the man
> :page was more explicit about how the list of elements is processed,
> :would that help?
>
> I don't know whether it would help in general or not. The behavior of
> tcl to treat plain text as data or commands , depending on the vagarity
> of the command in process, is pretty tough to explain in a mere
> man page.
But it *is* explained in a mere man page, and fairly suscinctly. Half a
man page, really. The main tcl man page spells out a mere eleven rules
which covers this quite nicely. Really only the first three rules and
rule 9 (the comment rule...) are all that's required to explain how tcl
distinguishes between commands and data. The rest is quoting.
My remark about the man page was specifically in reference to the switch
statement. Perhaps that man page needs to spell out that the list of
patterns and actions *must* have an even number of elements.
sorry if i was one of them - i was just amazed that The Tcl FAQ Guy appeared to
be yet another ? who didn't understand how tcl comments worked.
>And here was the catch that I was missing. That in some cases, the
>tcl interpreter treats everything after a # as 'a part of the # command'
>and in at least one case - switch - the interpreter associates only
>the first word (sometimes!) with the # and treats the remainder of
>the line as being another command.
the cases are quite well-defined: when the evaluator is parsing out the first
word of a command, and the first character of that word is #, it skips to the
next newline (or to the end of the string) and starts again. that's the only
time # has any special meaning.
# has no special meaning in
uplevel #0 {puts "global foo = $foo"}
because it is the first character of the *second* word of the phrase.
# has no special meaning in
puts "# of lines = $count"
because it is not the first character of *any* word of the phrase.
# has no special meaning in
switch -- $char {# {puts hash} $ {puts dollar}}
because it's not the first character of the command (and appears in a pattern
argument in switch, so never gets to the evaluator as code.
# has no special meaning in
proc #foo {} {puts wow}
because (as in the uplevel case) it's not the first character of the first
word.
can a proc with such a name ever be used? soitny:
set x #foo; $x
\#foo
\43foo
{#foo}
to be ignored in evaluation, the # must appear directly in code as the first
character of the first word. any other time, it is an just like any other
character.
here's a way i have (ab?)used this fact:
proc tracehandler {} {# something here}
trace var foo w {handler;# from memory but the idea shouls be clear}
and similarly
scale .x -command {puts scale-changed;#}
in cases where i was not interested in the arguments appended before
evaluation.
>I don't know whether [better docs] would help in general or not. The behavior
of
>tcl to treat plain text as data or commands , depending on the vagarity
>of the command in process, is pretty tough to explain in a mere
>man page.
what is so hard to explain? everything is a string. what the string means is
always decided by context - by what's using the string. give it to puts, it
becomes output; give it to open, it's a file name; give it to expr, it's
arithmetic; give it to lindex, it's a list; give it to set or proc, it's just
stuff to store (or a label under which to store it); give it to eval or (as
certain arguments of) while, if, for, foreach etc. it's treated as code.
once we moved beyond patchpanels, code became another datatype (perhaps the
most complicated and dangerous one, but a datatype nonetheless). even C
remembers that to a small degree - eg int (*f)() - but my guess is that so few
languages manage to make it into a datatype as manipulable as all the others,
that a pervasive mental block has cropped up that there's actually something
screwy with such languages.
Re: You SHOULD know this...
There are many things in life I should know. I don't. Sorry - many days
I have problems knowing the name of my family members, let alone the
syntax in question.
I surrender. I seem to be incapable of learning the most simple
aspects of Tcl. I retreat to cataloging you folk's software and
leave you all to answer the questions of the novices regarding
comments again and again and again and again....
You SHOULD know this. The last argument to switch is *NOT*
a procedure The "#" is never seen as a command in this case
as switch just treats it's last argument as a list and assumes
that the even elements are the match and the odd elements are
what should be executed. This is why to make multiple things
match to the same command you need the "--" placeholder. The
line with "#" on it is just translated as a "#" followed by
a bunch of words. There is no way for switch to be clever
scanned string as the newlines are gone by the time it gets
it.
-Ron
It's like ":" in the shell (almost) which also isn't quite a comment.
The way this was fixed in Unix Edition 7 was to introduce a new comment
character which really was a comment, the comment character in question
was "#".
That approach just doesn't work for Tcl though. Because you can have
switch $var "
-- is this a comment?
foo bar
-- where comments start with `--'
"
and you "obviously" don't want comments in strings. (And yes, I have
used this form of the switch command, with good reason.)
It occurs to me, however, that "split" (which is used to split the
switch argument into an even number of elements) could be enhanced to
strip (lexical) comments. You would still need a different comment
convention for backwards compatability reasons, but "new style" comments
could be modified for backwards compatability, eg
set tcl_commentBrackets {"--" "\n"}
for the default or
unset tcl_commentBrackets
to permanently disable the feature or
set tcl_commentBrackets {"COMMENT" "TNEMMOC"}
for Algol68 fans :-)
--
John Haxby
j...@pwd.hp.com http://www.ice.hp.com/
------------------------------------------------------------------------
These are my opinions, not my employer's.
Whoops - sorry, I forgot that I'm too stupid for this topic. I would
cancel that last article, but I'm too stupid to figure out how to
configure trn here to post articles in a fashion so they can be cancelled.
Sighed - just ignore that last article.
According to John Haxby <j...@hazel.pwd.hp.com>:
: switch $var "
: -- is this a comment?
: foo bar
: -- where comments start with `--'
: "
:
:and you "obviously" don't want comments in strings. (And yes, I have
:used this form of the switch command, with good reason.)
:
Frankly, the simplest way I can think of to fix things is to just
make Tcl require some kind of quoting around string constants.