From: Stephen D. <sd...@gm...> - 2007-11-28 17:21:57
|
On Nov 28, 2007 11:42 AM, Zoran Vasiljevic <vas...@us...> wrote: > Update of /cvsroot/naviserver/naviserver/nsd > In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv23874/nsd > > Modified Files: > tclconf.c > Log Message: > * nsd/tclconf.c: Fixed NsTclConfigObjCmd() to correctly set the > returned value of an default boolean param to 0/1 and not just > blindly parrot what user has given (true/false for example) as > this could (and it does!) break Tcl expressions. > > > > Index: tclconf.c > =================================================================== > RCS file: /cvsroot/naviserver/naviserver/nsd/tclconf.c,v > retrieving revision 1.5 > retrieving revision 1.6 > diff -C2 -d -r1.5 -r1.6 > *** tclconf.c 21 Oct 2007 16:20:24 -0000 1.5 > --- tclconf.c 28 Nov 2007 11:42:38 -0000 1.6 > *************** > *** 130,140 **** > > if (defObj != NULL) { > ! if ((isbool && Tcl_GetBooleanFromObj(interp, defObj, &i) != TCL_OK) > ! || (isint && Tcl_GetWideIntFromObj(interp, defObj, &v) != TCL_OK)) { > ! return TCL_ERROR; > ! } > ! if (isint && (v < min || v > max)) { > ! Tcl_SetResult(interp, "value out of range", TCL_STATIC); > ! return TCL_ERROR; > } > Tcl_SetObjResult(interp, defObj); > --- 130,143 ---- > > if (defObj != NULL) { > ! if (isbool) { > ! if (Tcl_GetBooleanFromObj(interp, defObj, &i) != TCL_OK) { > ! return TCL_ERROR; > ! } > ! defObj = Tcl_NewIntObj(i); > ! } else if (isint) { > ! if (v < min || v > max) { > ! Tcl_SetResult(interp, "value out of range", TCL_STATIC); > ! return TCL_ERROR; > ! } > } > Tcl_SetObjResult(interp, defObj); Pre-change: % expr !1 0 % expr !0 1 % expr !true 0 % expr !yes 0 % expr !y 0 % expr !yup syntax error in expression "!yup": variable references require preceding $ % expr ![ns_config -bool a/b c yup] expected boolean value but got "yup" Post-change: $ make test TCLTESTARGS="-file ns_config.test" Only running test files that match: ns_config.test Tests began at Wed Nov 28 06:18:18 PM GMT 2007 ns_config.test ==== ns_config-3.4 not an int FAILED ==== Contents of test case: ns_config -int ns/testconfig missing huh? ---- Test completed normally; Return code was: 0 ---- Return code should have been one of: 1 ==== ns_config-3.4 FAILED ==== ns_config-4.6 int min def FAILED ==== Contents of test case: ns_config -min 43 ns/testconfig intval 43 ---- Test generated error; Return code was: 1 ---- Return code should have been one of: 0 2 ---- errorInfo: value out of range while executing "ns_config -min 43 ns/testconfig intval 43" ("uplevel" body line 2) invoked from within "uplevel 1 $script" ---- errorCode: NONE ==== ns_config-4.6 FAILED ==== ns_config-4.7 int max def FAILED ==== Contents of test case: ns_config -max 41 ns/testconfig intval 41 ---- Test generated error; Return code was: 1 ---- Return code should have been one of: 0 2 ---- errorInfo: value out of range while executing "ns_config -max 41 ns/testconfig intval 41" ("uplevel" body line 2) invoked from within "uplevel 1 $script" ---- errorCode: NONE ==== ns_config-4.7 FAILED Tests ended at Wed Nov 28 06:18:18 PM GMT 2007 all.tcl: Total 31 Passed 28 Skipped 0 Failed 3 Sourced 1 Test Files. Files with failing tests: ns_config.test |
From: Vasiljevic Z. <zv...@ar...> - 2007-11-28 17:46:32
|
On Nov 28, 2007, at 6:22 PM, Stephen Deasey wrote: > Pre-change: > > > % expr !1 > 0 > % expr !0 > 1 > > % expr !true > 0 > % expr !yes > 0 > % expr !y > 0 set value [ns_config -bool /missing/section missing_parameter true] if {$value == 1} { puts "$value is true" } else { puts "$value is false" } What do you think the above will print out? The problem is that the programmer could test the value on 0/1 as well, so more defensive way is to return canonical value's of 1/0 for true/false boolean values. The code before retured whatever the value has been given (y/Y/true/Yes etc pp) which broke some of our code (that costed us *hours* to dig it out!!!) The code was broken at that place definitely. The change fixed that but broke the integer part... I will look into that now.... Cheers Zoran |
From: Vasiljevic Z. <zv...@ar...> - 2007-11-28 18:19:12
|
On Nov 28, 2007, at 6:46 PM, Vasiljevic Zoran wrote: > I will look into that now.... There you go: zvmbp:naviserver zoran$ make test TCLTESTARGS="-file ns_config.test" Tests running in interp: /Users/zoran/sf/naviserver/nsd/nsd Tests located in: /Users/zoran/sf/naviserver/tests Tests running in: /Users/zoran/sf/naviserver/tests Temporary files stored in /Users/zoran/sf/naviserver/tests Test files sourced into current interpreter Running tests that match: * Skipping test files that match: l.*.test Only running test files that match: ns_config.test Tests began at Wed Nov 28 19:18:11 CET 2007 ns_config.test Tests ended at Wed Nov 28 19:18:11 CET 2007 all.tcl: Total 31 Passed 31 Skipped 0 Failed 0 Sourced 1 Test Files. |
From: Stephen D. <sd...@gm...> - 2007-11-28 19:14:49
|
On Nov 28, 2007 5:46 PM, Vasiljevic Zoran <zv...@ar...> wrote: > > On Nov 28, 2007, at 6:22 PM, Stephen Deasey wrote: > > > Pre-change: > > > > > > % expr !1 > > 0 > > % expr !0 > > 1 > > > > % expr !true > > 0 > > % expr !yes > > 0 > > % expr !y > > 0 > > > set value [ns_config -bool /missing/section missing_parameter true] > if {$value == 1} { > puts "$value is true" > } else { > puts "$value is false" > } {$bool == 1} is not a valid test of truthiness. And it's uneccessary: set bool 1 if {$bool} { puts yup } set bool yes if {$bool} { puts $yup } |
From: Vasiljevic Z. <zv...@ar...> - 2007-11-28 19:38:13
|
On Nov 28, 2007, at 8:14 PM, Stephen Deasey wrote: > > {$bool == 1} is not a valid test of truthiness. ... so Tcl and C are "broken"? > > > And it's uneccessary: > > set bool 1 > if {$bool} { > puts yup > } > > set bool yes > if {$bool} { > puts $yup > } It is not but it is widely used. When Tcl disallows us to use 1/0 for true/false and test on 1/0 equality for it, then we can talk more about it. Cheers Zoran |
From: Stephen D. <sd...@gm...> - 2007-11-28 21:39:57
|
On Nov 28, 2007 7:38 PM, Vasiljevic Zoran <zv...@ar...> wrote: > > On Nov 28, 2007, at 8:14 PM, Stephen Deasey wrote: > > > > > {$bool == 1} is not a valid test of truthiness. > > ... so Tcl and C are "broken"? Tcl and C are fine. The example is broken. For example, in C the above should be: if (bool != 0) { printf("truth"); } because 1 is not the only value of true. Same in Tcl, although it's not sufficient because integers other than 0 are not the only valid representation of truth. The *default* representation of truth is the integer 1: % expr 1 < 2 1 % expr 2 < 1 0 You can certainly use 1/0 for true/false. But if you only check the equality of a boolean against 1 you are only checking a small subset of integers, and none of the other truths: yes, y, t, on, etc. Therefore, I don't think it's fair to say that this is a more robust test of Tcl truth: if {$bool == 1} ... > When Tcl disallows us to use 1/0 for true/false and test on 1/0 equality for > it, then we can talk more about it. It is already disallowed... :-) if: http://www.tcl.tk/man/tcl8.5/TclCmd/if.htm The if command evaluates expr1 as an expression (in the same way that expr evaluates its argument). The value of the expression must be a boolean (a numeric value, where 0 is false and anything is true, or a string value such as true or yes for true and false or no for false) expr: http://www.tcl.tk/man/tcl8.5/TclCmd/expr.htm A Tcl expression consists of a combination of operands, operators, and parentheses... Where possible, operands are interpreted as integer values... If no numeric interpretation is possible (note that all literal operands that are not numeric or boolean must be quoted with either braces or with double quotes), then an operand is left as a string (and only a limited set of operators may be applied to it). Operands may be specified in any of the following ways: [1] As a numeric value, either integer or floating-point. [2] As a boolean value, using any form understood by string is boolean. [...] string is ...: http://www.tcl.tk/man/tcl8.5/TclCmd/string.htm#M16 Returns 1 if string is a valid member of the specified character class, otherwise returns 0. If -strict is specified, then an empty string returns 0, otherwise an empty string will return 1 on any class. string is boolean: Any of the forms allowed to Tcl_GetBoolean. Tcl_GetBoolean: http://www.tcl.tk/man/tcl8.5/TclLib/GetInt.htm Tcl_GetBoolean expects src to specify a boolean value. If src is any of 0, false, no, or off, then Tcl_GetBoolean stores a zero value at *boolPtr. If src is any of 1, true, yes, or on, then 1 is stored at *boolPtr. Any of these values may be abbreviated, and upper-case spellings are also acceptable. |
From: Vasiljevic Z. <zv...@ar...> - 2007-11-29 05:15:32
|
On Nov 28, 2007, at 10:39 PM, Stephen Deasey wrote: > > Tcl and C are fine. The example is broken. Ah, Stephen... set value [ns_config -bool /missing/thing missing_par false] if {$value == 0} { puts "should it print?" } In the pre-checkin version it didn't because value was set to string "false" and this ain't equal number zero. In the post-checkin version it does as it always substitutes the result to 0 or 1. Is this now "broken"? |
From: Stephen D. <sd...@gm...> - 2007-11-29 06:32:21
|
On Nov 29, 2007 5:15 AM, Vasiljevic Zoran <zv...@ar...> wrote: > > On Nov 28, 2007, at 10:39 PM, Stephen Deasey wrote: > > > > > Tcl and C are fine. The example is broken. > > > > Ah, Stephen... > > set value [ns_config -bool /missing/thing missing_par false] > if {$value == 0} { > puts "should it print?" > } > > In the pre-checkin version it didn't > because value was set to string "false" > and this ain't equal number zero. > In the post-checkin version it does as > it always substitutes the result to 0 or 1. > > Is this now "broken"? It's equally as broken as the other example, and for exactly the same reason. Are you saying that "false" is not false and "true" is not true? If not, then whey insist on using integer equality expressions? |
From: Vasiljevic Z. <zv...@ar...> - 2007-11-29 06:46:01
|
On Nov 29, 2007, at 7:32 AM, Stephen Deasey wrote: > > Are you saying that "false" is not false and "true" is not true? I'm saying that false IS zero and 1 IS true (better, non-zero is true). If false IS zero then testing the value for zero EQUALS testing the value for false. Or not? This was NOT so in the implementation, hence I had to correct that. But this can bring us to the question: set value [ns_config -bool jummy juice false] if {$value == "true"} { # ... } and all sorts of other weird things. I know I know... This all ISN'T very clear because Tcl's C-heritage and LACK of proper boolean type (actually lack of ANY types). So, we cannot teach Tcl types, we can only make some approximations. The (ns_config )code was simply too strict at that place, which broke our scripts at various places. The change isn't going to break anybody's scripts and is "in the spirit" of the (Tcl) language. |
From: Vasiljevic Z. <zv...@ar...> - 2007-11-29 07:08:44
|
On Nov 29, 2007, at 7:45 AM, Vasiljevic Zoran wrote: > The change isn't going to break anybody's scripts and is > "in the spirit" of the (Tcl) language. *Strictly* speaking it would break, if you were testing string equality on "true" and "false" but then again, the older scripts would never have worked, as ns_config DID normalize return values to 0/1 some times before. |
From: Stephen D. <sd...@gm...> - 2007-11-29 07:10:51
|
On Nov 29, 2007 6:45 AM, Vasiljevic Zoran <zv...@ar...> wrote: > > On Nov 29, 2007, at 7:32 AM, Stephen Deasey wrote: > > > > > Are you saying that "false" is not false and "true" is not true? > > I'm saying that false IS zero and 1 IS true (better, non-zero is true). OK. But why are you saying that? The Tcl man pages define explicitly what the valid values for boolean are, and in what context booleans are expected. Can you point to the part which supports your argument? > But this can bring us to the question: > > set value [ns_config -bool jummy juice false] > if {$value == "true"} { > # ... > } > > and all sorts of other weird things. I know I know... This is a false dilemma. A string equality expression is not the only substitute for an integer comparison expression. if {$boolilicious} { ;# <--- boolean expression puts "truthy" } > This all ISN'T very clear because Tcl's C-heritage and > LACK of proper boolean type (actually lack of ANY types). Tcl has a boolean type: http://www.tcl.tk/man/tcl8.5/TclLib/BoolObj.htm It's string rep when false is 0, false, no, f and so on. > So, we cannot teach Tcl types, we can only make some > approximations. The (ns_config )code was simply too strict > at that place It was returning a boolean value, guaranteed. It used Tcl_GetBoolean to parse the value from the config file, and Tcl_GetBooleanFromObj to check the default value. If both of those calls return TCL_OK, then whatever comes out the other side is a valid boolean value. |
From: Vasiljevic Z. <zv...@ar...> - 2007-11-29 07:33:33
|
On Nov 29, 2007, at 8:10 AM, Stephen Deasey wrote: > On Nov 29, 2007 6:45 AM, Vasiljevic Zoran <zv...@ar...> wrote: >> >> On Nov 29, 2007, at 7:32 AM, Stephen Deasey wrote: >> >>> >>> Are you saying that "false" is not false and "true" is not true? >> >> I'm saying that false IS zero and 1 IS true (better, non-zero is >> true). > > > OK. But why are you saying that? Because you asked: "Are you saying that "false" is not false and "true" is not true?" so I wanted to make clear what I'm saying. > > > The Tcl man pages define explicitly what the valid values for boolean > are, and in what context booleans are expected. Can you point to the > part which supports your argument? > I cannot, because Tcl has no strict typing. All this is really best-effort where possible. This is not something that the language enforces. You can't (nobody can) make Tcl typed language as if you want to do that, you will break the backward compat and in this particular case, you would defeat the whole purpose of the language. > >> But this can bring us to the question: >> >> set value [ns_config -bool jummy juice false] >> if {$value == "true"} { >> # ... >> } >> >> and all sorts of other weird things. I know I know... > > > This is a false dilemma. > > A string equality expression is not the only substitute for an integer > comparison expression. > > if {$boolilicious} { ;# <--- boolean expression > puts "truthy" > } > In the IDEAL world, we would have Tcl types. But then again, why bother with Tcl and don't use Java or C## or something "typed"? > >> This all ISN'T very clear because Tcl's C-heritage and >> LACK of proper boolean type (actually lack of ANY types). > > > Tcl has a boolean type: > > http://www.tcl.tk/man/tcl8.5/TclLib/BoolObj.htm > > It's string rep when false is 0, false, no, f and so on. > This is only a boolean type if you want to treat it as boolean. Otherwise it is just a string. > >> So, we cannot teach Tcl types, we can only make some >> approximations. The (ns_config )code was simply too strict >> at that place > > > It was returning a boolean value, guaranteed. It did, yes. But it did not follow the assumption that people would test the return value with numeric comparison relying on the fact that zero IS true. And this is what you are accustomed when comming for C. Nobody in C would write char *false = "false" if (false) { } and everybody is simply accustomed to zero/nonzero integer value to hold for false/true. This is also valid for Tcl. Just about lately they (Tcl) started to mingle with true/false in expressions and that created all this mess. We cannot fix that mess. But I'm also not going to change my scripts because of that mess. But hold on... why are we consuming list bandwidth on this obvious thing? It is simple as that: the code was not broken essentialy. It was simply too "straight" and broke backward compatibility w/o any good reason. |
From: Vasiljevic Z. <zv...@ar...> - 2007-11-29 07:40:46
|
On Nov 29, 2007, at 8:10 AM, Stephen Deasey wrote: > It was returning a boolean value, guaranteed. It used Tcl_GetBoolean > to parse the value from the config file, and Tcl_GetBooleanFromObj to > check the default value. If both of those calls return TCL_OK, then > whatever comes out the other side is a valid boolean value. What about: puts "[expr {0 == 0}]" What is this going to return in your tclsh? Is it going to say true or t or yes ? NO. It is printing: 1 It will NEVER print anything else. Hence you cannot test string equality for expressions with "false"/"no" etc but you CAN test it with numerical value of 0 (zero) or non-zero. Allright? |
From: Stephen D. <sd...@gm...> - 2007-11-29 08:47:07
|
On Nov 29, 2007 7:40 AM, Vasiljevic Zoran <zv...@ar...> wrote: > > On Nov 29, 2007, at 8:10 AM, Stephen Deasey wrote: > > > It was returning a boolean value, guaranteed. It used Tcl_GetBoolean > > to parse the value from the config file, and Tcl_GetBooleanFromObj to > > check the default value. If both of those calls return TCL_OK, then > > whatever comes out the other side is a valid boolean value. > > What about: > > puts "[expr {0 == 0}]" > > What is this going to return in your tclsh? > Is it going to say > > true > or > t > or > yes > > ? > > NO. It is printing: > 1 > > It will NEVER print anything else. Hence you cannot > test string equality for expressions with "false"/"no" etc > but you CAN test it with numerical value of 0 (zero) > or non-zero. > > Allright? Not alright. There is no dispute about what the string rep of a boolean expression is: it's 0 or 1. But it's irrelevant. We're concerned with input, not output. Specifically: what does the 'if' command require as it's first argument? The answer is: boolean. Not int. Not string. Which is why you can test like this: On Nov 29, 2007 7:33 AM, Vasiljevic Zoran <zv...@ar...> wrote: > > > > This is a false dilemma. > > > > A string equality expression is not the only substitute for an integer > > comparison expression. > > > > if {$boolilicious} { ;# <--- boolean expression > > puts "truthy" > > } > > > > In the IDEAL world, we would have Tcl types. But then again, > why bother with Tcl and don't use Java or C## or something > "typed"? I'm not sure which ideal world you're wishing for, but here In the real world, try this: % set bool 1 % if {$bool} {puts "this totally worked!"} % set bool true % if {$bool} {puts "this sooo worked!"} I've explained how it works, but it really doesn't matter. All that matters is that it does, in fact work. |