• Re: confused about lists and strings...

    From Harald Oehlmann@21:1/5 to All on Wed Jul 2 11:27:54 2025
    Am 02.07.2025 um 10:39 schrieb Mark Summerfield:
    proc process1 args {
    set first [lindex $args 0]
    puts "first='$first' args='$args' list? [string is list -strict $args]"
    set rest [lrange $args 1 end]
    puts "rest='$rest' list? [string is list -strict $rest]"
    }

    The name "args" is special in TCL returning all remaining arguments as a
    list.

    As you call:
    process1 $argv

    The one argument is put in a list. The result is a matrix (list in list).

    How to solve:

    a) don't use "args":

    proc process1 myargs {
    set first [lindex $myargs 0]
    puts "first='$first' args='$myargs' list? [string is list -strict $myargs]"
    set rest [lrange $myargs 1 end]
    puts "rest='$rest' list? [string is list -strict $rest]"
    }

    b) use the delist operator:

    process {*}$argv

    Hope this helps,
    Harald

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et99@21:1/5 to Mark Summerfield on Wed Jul 2 02:53:02 2025
    On 7/2/2025 2:34 AM, Mark Summerfield wrote:
    On Wed, 2 Jul 2025 11:27:54 +0200, Harald Oehlmann wrote:

    Am 02.07.2025 um 10:39 schrieb Mark Summerfield:
    proc process1 args {
    set first [lindex $args 0]
    puts "first='$first' args='$args' list? [string is list -strict $args]"
    set rest [lrange $args 1 end]
    puts "rest='$rest' list? [string is list -strict $rest]"
    }

    The name "args" is special in TCL returning all remaining arguments as a
    list.

    As you call:
    process1 $argv

    The one argument is put in a list. The result is a matrix (list in list).

    How to solve:

    a) don't use "args":

    proc process1 myargs {
    set first [lindex $myargs 0]
    puts "first='$first' args='$myargs' list? [string is list -strict
    $myargs]"
    set rest [lrange $myargs 1 end]
    puts "rest='$rest' list? [string is list -strict $rest]"
    }

    b) use the delist operator:

    process {*}$argv

    Hope this helps,
    Harald

    Thanks, I hadn't realised that using `args` would give me a list in a list.
    I now just pass the list as-is (and called `rest` to avoid confusion!).

    This used to confuse me totally. Now I understand (I think) that args and {*} are inverses of each other. If you can get your head around this, then you got it :)


    % proc p args {puts [list {*}$args]} ;# so an inverse of an inverse is an identity

    % p 1 2 3
    1 2 3

    % p {1 2 3}
    {1 2 3}

    % p {1 2 3} {4 5 6}
    {1 2 3} {4 5 6}

    % p {*}{1 2 3}
    1 2 3

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to [email protected] on Wed Jul 2 12:55:14 2025
    et99 <[email protected]> wrote:
    On 7/2/2025 2:34 AM, Mark Summerfield wrote:
    Thanks, I hadn't realised that using `args` would give me a list in a list. >> I now just pass the list as-is (and called `rest` to avoid confusion!).

    This used to confuse me totally. Now I understand (I think) that
    args and {*} are inverses of each other. If you can get your head
    around this, then you got it :)

    If you understand what 'xargs' does on a Unix CLI, {*} is essentially a
    "Tcl xargs".

    It (when used for calling a proc) converts "a list of things" into
    "individual parameters to the proc".

    What it really does is "unwraps" the lists contents. So instead of
    having "one list containing 5 things" you end up with the internal "5
    things" each individually.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Mark Summerfield on Wed Jul 2 12:59:32 2025
    Mark Summerfield <[email protected]> wrote:
    Thanks, I hadn't realised that using `args` would give me a list in a
    list.

    The proc man page documents this 'special nature' of 'args' (note the
    third sentence below):

    There is one special case to permit procedures with variable numbers
    of arguments. If the last formal argument has the name “args”, then
    a call to the procedure may contain more actual arguments than the
    proce‐ dure has formal arguments. In this case, all of the actual
    arguments starting at the one that would be assigned to args are
    combined into a list (as if the list command had been used); this
    combined value is as‐ signed to the local variable args.

    Note also from the above that it is only 'special' when it is the "last argument" to the proc.

    $ rlwrap tclsh
    % proc abc {args y} {puts "args='$args' y='$y'" }
    % abc 1 2
    args='1' y='2'
    %

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christian Gollwitzer@21:1/5 to All on Wed Jul 2 19:40:08 2025
    Am 02.07.25 um 11:34 schrieb Mark Summerfield:

    Thanks, I hadn't realised that using `args` would give me a list in a list.
    I now just pass the list as-is (and called `rest` to avoid confusion!).

    Actually this is very similar in Python:

    def fun1(*args):
    # now you have all arguments in the list args
    pass
    fun1(1,2,3)


    and the inverse:

    def fun2(a,b,c):
    pass

    list=[1, 2, 3]
    fun2(*list)

    That'd be in Tcl

    proc fun1 {args} {
    }

    fun1 1 2 3

    proc fun2 {a b c} { }

    set list "1 2 3"
    fun2 {*}$list


    Christian

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et99@21:1/5 to Rich on Wed Jul 2 12:41:34 2025
    On 7/2/2025 5:55 AM, Rich wrote:
    et99 <[email protected]> wrote:
    On 7/2/2025 2:34 AM, Mark Summerfield wrote:
    Thanks, I hadn't realised that using `args` would give me a list in a list. >>> I now just pass the list as-is (and called `rest` to avoid confusion!).

    This used to confuse me totally. Now I understand (I think) that
    args and {*} are inverses of each other. If you can get your head
    around this, then you got it :)

    If you understand what 'xargs' does on a Unix CLI, {*} is essentially a
    "Tcl xargs".

    It (when used for calling a proc) converts "a list of things" into "individual parameters to the proc".

    What it really does is "unwraps" the lists contents. So instead of
    having "one list containing 5 things" you end up with the internal "5
    things" each individually.


    Yes, it was your explanation, some years back which opened my brain to {*}.

    One pleasant implementation detail I discovered, is that {*}{} does not produce an argument, which is useful in say, passing in some optional arguments that are then passed into the middle of some other command, such as lsort, for example:

    proc mysort {alist args} {
    ...
    lsort {*}$args $alist
    ...
    }

    If args is null, then lsort only sees one arg; no need to test for args being null.

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