Thread from comp.lang.tcl (7 replies)
Array get element with default (no error if not exist)
Hi Friends! Still making my first feeble steps in TCL so please excuse me if this is naive or was asked multiple times. Attempt to fetch by non-existing key in "associative array" results in error, e.g. set a(1) 5 puts $a(2) ;# yields error the workaround seems to be [info exists ::a(2)] which feels a bit remote from other "array" commands. Is there some motivation why some command for get-with-default is not implemented, e.g. puts [array peek $a 2 "default value"] Popular use-case for this would be creating map where elements are updated (like counter of words etc) - though I found this is cleverly covered by "incr" and "append" commands properly behaving when element to be incremented or appended does not exist yet. But I suspect there are other situations when such a command may be handy. Also why [array exists ...] command does not exist (while [dict exists ...] does)? Perhaps there is something about no good syntax for it due to how arrays are implemented? -- to email me substitute github with gmail pleaseClick on article to view all threads in comp.lang.tcl
Re: Array get element with default (no error if not exist)
* RodionGork <rodiongork@github.com> | Is there some motivation why some command for get-with-default is not | implemented, e.g. > | puts [array peek $a 2 "default value"] Most probably because up to now nobody required it so badly that s/he implemented it, since the [info exists] approach is not too bad IMHO. proc array_peek {arr key default} { upvar $arr a if {![array exists a] || ![info exists a($key)]} { return $default } return $a($key) } array set a {1 one} array_peek a 1 "default value" => one array_peek a 2 "default value" => default value Or you could set up a read-trace on the array to provide non-existing values: array set a {} trace add variable a read set_array_default proc set_array_default {name1 name2 op} { upvar a $name1 # puts stderr "set_array {$name1} {$name2} {$op}" if {![info exists a($name2)]} { set a($name2) "default" } } set a(2) => default Though that would alter the array and make the key exists which might not be what you want. HTH R'Click on article to view all threads in comp.lang.tcl
Re: Array get element with default (no error if not exist)
On Fri, 16 Aug 2024 07:10:30 +0000 RodionGork <rodiongork@github.com> wrote: > Hi Friends! > > Still making my first feeble steps in TCL so please excuse me if this is > naive or was asked multiple times. > > Attempt to fetch by non-existing key in "associative array" results in > error, e.g. > > set a(1) 5 > puts $a(2) ;# yields error > > the workaround seems to be [info exists ::a(2)] which feels a bit remote > from other "array" commands. > > Is there some motivation why some command for get-with-default is not > implemented, e.g. > > puts [array peek $a 2 "default value"] > > Popular use-case for this would be creating map where elements are > updated (like counter of words etc) - though I found this is cleverly > covered by "incr" and "append" commands properly behaving > when element to be incremented or appended does not exist yet. > > But I suspect there are other situations when such a command may be > handy. Already there in 8.7/9.0 % array default set foo NOSUCHVALUE % set foo(1) NOSUCHVALUE % info exists foo(1) 0 8.7/9.0 also adds [dict getwithdefault] (aka [dict getdef]) for dict values. > Also why [array exists ...] command does not exist (while [dict exists > ..] does)? Perhaps there is something about no good syntax for it due > to how arrays are implemented? The [array exists] command is there since ... forever % array exists foo 1 % array exists nosucharray 0 Well, at least since 8.4 . See https://www.tcl-lang.org/man/tcl8.4/TclCmd/array.htm -- EmilianoClick on article to view all threads in comp.lang.tcl
Re: Array get element with default (no error if not exist)
* Emiliano <emil.g@example.invalid> | On Fri, 16 Aug 2024 07:10:30 +0000 | RodionGork <rodiongork@github.com> wrote: | > Also why [array exists ...] command does not exist (while [dict exists | > ..] does)? Perhaps there is something about no good syntax for it due | > to how arrays are implemented? > | The [array exists] command is there since ... forever > | % array exists foo | 1 | % array exists nosucharray | 0 Obviouosly in this context the OP meant "array exists" with respect to a specific key, i.e. array exists arrayname key => return true if arrayname is an array and the key exists in that array. R'Click on article to view all threads in comp.lang.tcl
Re: Array get element with default (no error if not exist)
Friends, thanks for all the replies! And for suggestions providing insight on techniques of which I wasn't aware of, especially that "read trace". Yep, I definitely meant something like [array element_exists ...] rather than [array exists ...] which seems a bit inconsistent with [dict exists ...] but of course it is not a big issue. My curiosity was mostly satisfied, thanks! The only small thing I still haven't grasped well is why it happened that checking for element in array found its way into [info exists...] rather than some [array ...] subcommands. I suspected there was something hindering implementing it there, but probably it just, well, so happened historically :) -- to email me substitute github with gmail pleaseClick on article to view all threads in comp.lang.tcl
Re: Array get element with default (no error if not exist)
RodionGork <rodiongork@github.com> wrote: > Friends, thanks for all the replies! > > And for suggestions providing insight on techniques of which I wasn't > aware of, especially that "read trace". > > Yep, I definitely meant something like [array element_exists ...] rather > than [array exists ...] which seems a bit inconsistent with [dict exists > ..] but of course it is not a big issue. > > My curiosity was mostly satisfied, thanks! The only small thing I still > haven't grasped well is why it happened that checking for element in > array found its way into [info exists...] rather than some [array ...] > subcommands. I suspected there was something hindering implementing it > there, but probably it just, well, so happened historically :) [info exists] is used for determining if a variable exists. A Tcl array is built such that it is a collection of individual variables referenced together as a set (this is also the reason why you can't "pass" an array to a proc, nor [return] an array from a proc in the same way you can pass/return a dict [1]). Given that the array is merely a set of individual variables, someone, way back in the distant past, decided it was more consistent to use the "does this variable exist" command to determine if an individual variable existed in an array. [1] You can pass in the name of the array, and use upvar to access it, or you can convert to a string and pass in the string. And to [return] you have to convert to a string ([array get]) to return one. But this does not work: proc handle {arr} { puts "I have array [array get arr]" } set array(1) something handle $array You get "can't read "array": variable is array" as an error message. This difference is also why you can [trace] individual array elements (they are individual variables) but cannot [trace] individual dict elements (they are just entries inside the dict variable).Click on article to view all threads in comp.lang.tcl
Re: Array get element with default (no error if not exist)
Thank you, this definitely makes sense! I remember about issue with passing/returning array in functions. By the way I still am not sure why it works with global for example... if they are actually different variables, every key-pair :) e.g. like here: https://github.com/RodionGork/languages-benchmark/blob/main/02-primes/primes_a.tcl#L7 -- to email me substitute github with gmail pleaseClick on article to view all threads in comp.lang.tcl
Re: Array get element with default (no error if not exist)
RodionGork <rodiongork@github.com> wrote: > Thank you, this definitely makes sense! > > I remember about issue with passing/returning array in functions. By the > way I still am not sure why it works with global for example... if they > are actually different variables, every key-pair :) e.g. like here: > > https://github.com/RodionGork/languages-benchmark/blob/main/02-primes/primes_a.tcl#L7 Because the [global] command works with names of variables, not the actual variables. It links the global variable with the given name, to a local variable of the same name, inside the proc. If the global name references an array, then the new local name inside the proc references the same array.Click on article to view all threads in comp.lang.tcl