• Re: The "leading zero means octal" thing...

    From Luc@21:1/5 to All on Sun Jan 5 16:46:57 2025
    I updated my 'seq' code because of this thread:

    https://wiki.tcl-lang.org/page/seq


    --
    Luc


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Luc on Sun Jan 5 21:04:46 2025
    Luc <luc@sep.invalid> wrote:
    I updated my 'seq' code because of this thread:

    https://wiki.tcl-lang.org/page/seq

    And, line one of the proc contains the common Tcl bug of "applying a
    string operator" to a tcl list.

    Note this:

    $ rlwrap tclsh
    % proc p {args} { set args [string trimleft $args 0] ; return $args }
    % p 08
    8
    % p 08 08
    8 08
    % p #08 08
    {#08} 08
    % p 08 0a "one two three"
    8 0a {one two three}

    The 'args' special variable to a proc is provided to the proc as a
    "list".

    'string trimleft' is a string operator (not a list operator). So when
    'string trimleft' is applied to a list, Tcl first converts the list
    into a string, the operates on the string, which will likely not
    produce the expected result.

    Note the second 'test' above, where 08 08 was passed to p. Because
    args was converted to a string, only the initial leading zero was
    removed. However it is likely that the intent was to convert 08 08
    into 8 and 8. But 'string trimleft' does not work on individual list
    elements, it only knows strings, and after [list 08 08] is converted to
    a string, string trimleft sees "08 08" and only removes the first 0.

    Next, note the third test, where #08 was passed in. It is unlikely the
    intent was for #08 to become {#08} (the added {}'s are from Tcl's list
    to string conversion).

    Note as well the fourth test. "one two three" was changed to {one two
    three}. Also not likely the intended outcome.

    What this proc likely wanted was to iterate over each element in the
    args list, and remove leading zeros from each element, i.e.:

    proc p2 {args} { set args [lmap x $args {string trimleft $x 0}] ; return $args }

    Which does the right thing for plural leading zero arguments:

    % p2 08
    8
    % p2 08 08
    8 8
    % p2 08 08 08
    8 8 8

    Note, because the CLI does a list to string conversion when printing
    the return value, we can still get 'weird characters' when showing a
    demo:

    % p2 #08 08 08 "this or that"
    {#08} 8 8 {this or that}

    But a simple tweak will show the internal contents of the list without
    the extra 'stringification':

    % join [p2 #08 08 08 "this or that"] |
    #08|8|8|this or that

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Luc@21:1/5 to Rich on Sun Jan 5 20:13:01 2025
    On Sun, 5 Jan 2025 21:04:46 -0000 (UTC), Rich wrote:

    Luc <luc@sep.invalid> wrote:
    I updated my 'seq' code because of this thread:

    https://wiki.tcl-lang.org/page/seq

    And, line one of the proc contains the common Tcl bug of "applying a
    string operator" to a tcl list.

    **************************

    While I admit that I never took the list to string conversion into consideration (I am repeat offender at that), you explore certain
    possibilities in your exposition that I did take into consideration,
    and I decided that those don't matter.

    Anyone who has ever used seq (or just merely understands it in spite
    of never having used it) knows what the input is supposed to be: two
    or three integers.

    I improved on it by adding the ability to produce alphabetic sequences.

    About your examples, being atypically blunt, no programmer is stupid
    enough to input 08 and 08. Even I wouldn't that. Likewise, no programmer
    will be stupid enough to input #08. And if anyone actually does that,
    they will get the empty string. The code intentionally refuses to
    produce output when the input is incorrect.

    Of course, we have to consider the possibility of input being generated
    by some other code, which makes it more unpredictable. But then the
    blame will fall upon the code that produces incorrect input, and
    whoever writes (and hopefully tests) such code will have to make sure
    that the input is always correct. I can't blame the authors of the
    list and string commands to be responsible for my repeated incorrect
    use of lists and strings.

    But of course I am glad you chimed in once again because I was getting
    wrong outputs for '08 08' and '08 09'. I also noted another bug that
    you didn't point out: 'p.seq 0 5' was outputting '1 2 3 4 5' without
    the zero, which was also incorrect.

    So thanks to you, I have updated the code once again.

    Thank you.

    --
    Luc


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Luc on Mon Jan 6 03:12:48 2025
    Luc <luc@sep.invalid> wrote:
    So thanks to you, I have updated the code once again.

    You do know about the "foreach" loop, that specifically iterates across
    each element of a list, right?

    Even if you don't want to use lmap (which does require 8.6 IIRC) you
    don't need a C style "for" loop to iterate a list. Your "for {set x 0}
    loop could be something like:

    set cleanargs {}
    foreach arg $args {
    if {[string length $arg] > 1} {
    lappend cleanargs [string trimleft $arg 0]
    } else {
    lappend cleanargs $arg
    }
    }

    Alternately, since you are recreating seq, which only expects numbers
    as args, you could do:

    set cleanargs {}
    foreach arg $args {
    lappend cleanargs [scan $arg %d]
    }

    Which will handle any number of leading zeros (while producing decimal
    output) and will error out on non-numeric inputs.

    And, if you are willing to use lmap, the above four lines can become
    this single line:

    set args [lmap arg $args {scan $arg %d}]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Luc on Mon Jan 6 03:03:06 2025
    Luc <luc@sep.invalid> wrote:
    On Sun, 5 Jan 2025 21:04:46 -0000 (UTC), Rich wrote:

    Luc <luc@sep.invalid> wrote:
    I updated my 'seq' code because of this thread:

    https://wiki.tcl-lang.org/page/seq

    And, line one of the proc contains the common Tcl bug of "applying a
    string operator" to a tcl list.

    **************************

    While I admit that I never took the list to string conversion into consideration (I am repeat offender at that), you explore certain possibilities in your exposition that I did take into consideration,
    and I decided that those don't matter.

    Anyone who has ever used seq (or just merely understands it in spite
    of never having used it) knows what the input is supposed to be: two
    or three integers.

    I improved on it by adding the ability to produce alphabetic sequences.

    About your examples, being atypically blunt, no programmer is stupid
    enough to input 08 and 08. Even I wouldn't that. Likewise, no programmer
    will be stupid enough to input #08. And if anyone actually does that,
    they will get the empty string. The code intentionally refuses to
    produce output when the input is incorrect.

    And, of course, you miss the forest due to focusing on the trees.

    For this trivial example, the list to string conversion is not a "big
    deal". The greater point, and the one you should have taken from this,
    is that applying string operators willy-nilly to things that are
    documented as lists (or that contain lists) creates subtle, data
    dependent, bugs that can lie in wait for a very long time before "just
    the right data pattern" arrives that triggers the bug. This often
    occurs weeks or months (or longer) after one initially wrote the code,
    and it has been working perfectly since then, and then mysteriously, it
    fails. Those bugs can be very troublesome to track down.

    By being careful up front with "string operators" for "strings" and
    "list operators" for "lists" you can avoid an entire class of subtle,
    surprise, bugs that are hard to track down (even more so after you've
    long forgotten why you wrote what you wrote).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Kenny McCormack on Mon Jan 6 03:15:15 2025
    Posting groups and followup trimmed as this is Tcl specific:

    In comp.lang.tcl Kenny McCormack <gazelle@shell.xmission.com> wrote:
    In article <vletuv$17djb$1@dont-email.me>, saito <saitology9@gmail.com> wrote:
    ...
    I can't help but think that this may be related to your post regarding
    time calculation. I had left this quote in my reply:

    There is an interesting "octal" problem left as an exercise

    This was exactly the exercise as well. "clock format" leaves leading
    zeros in the result depending on what time it was. It is missing "string >>trimleft" calls which I'd discovered after some test runs before posting.

    It is, in fact, related to that other thread. In fact, I had developed an entirely different solution to that problem (very short, in fact) which had been running fine for a few weeks until it happened to hit the dreaded "08" and crashed. I fixed that basically by adding code using "regsub" to
    remove any leading zero before doing the calculations.

    I'll have to take a look at "string trimleft".

    The canonical Tcl way to handle decimal number strings with leading
    zeros is to filter them through [scan] using the %d scan pattern.

    $ rlwrap tclsh
    % scan 08 %d
    8
    % scan 00000000000000000000008 %d
    8
    %

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Luc@21:1/5 to Rich on Mon Jan 6 01:42:33 2025
    On Mon, 6 Jan 2025 03:12:48 -0000 (UTC), Rich wrote:

    And, if you are willing to use lmap, the above four lines can become
    this single line:

    set args [lmap arg $args {scan $arg %d}]

    **************************

    You are not going to believe this:

    I never knew that lmap existed.

    I've known lassign for a very long time.
    Never knew about lmap until today.


    --
    Luc


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Luc on Mon Jan 6 12:54:17 2025
    Luc <luc@sep.invalid> wrote:
    On Mon, 6 Jan 2025 03:12:48 -0000 (UTC), Rich wrote:

    And, if you are willing to use lmap, the above four lines can become
    this single line:

    set args [lmap arg $args {scan $arg %d}]

    **************************

    You are not going to believe this:

    I never knew that lmap existed.

    I've known lassign for a very long time.
    Never knew about lmap until today.

    In your defense, it was only introduced with Tcl 8.6, so it is one of
    the newer additions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kenny McCormack@21:1/5 to rich@example.invalid on Mon Jan 6 16:08:38 2025
    In article <vlfhs3$1ande$3@dont-email.me>, Rich <rich@example.invalid> wrote: ...
    The canonical Tcl way to handle decimal number strings with leading
    zeros is to filter them through [scan] using the %d scan pattern.

    $ rlwrap tclsh
    % scan 08 %d
    8
    % scan 00000000000000000000008 %d
    8
    %


    That's good to know.

    --
    (Cruz certainly has an odd face) ... it looks like someone sewed pieces of a waterlogged Reagan mask together at gunpoint ...

    http://www.rollingstone.com/politics/news/how-america-made-donald-trump-unstoppable-20160224

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)