Problem creating new command in `array` ensemble












1














I want to create a convenience command array values arrayName as a "flip side" to the "array names" command.



It's straightforward to create a simple proc:



proc array_values {arrayName} {
upvar 1 $arrayName ary
set values {}
foreach {name value} [array get ary] {lappend values $value}
return $values
}

array set a {foo bar baz qux}
puts [array_values a] ;# => bar qux


However, I'm having difficulty creating a command in the ::tcl::array namespace:





  • first some homework:





    1. is array a namespace ensemble? Yes.



      % namespace ensemble exists array
      1



    2. what is the namespace?



      % namespace ensemble configure array -namespace
      ::tcl::array



    3. what are the subcommands?



      % namespace ensemble configure array -subcommands
      % namespace ensemble configure array -map
      anymore ::tcl::array::anymore donesearch ::tcl::array::donesearch exists ::tcl::array::exists get ::tcl::array::get names ::tcl::array::names nextelement ::tcl::array::nextelement set ::tcl::array::set size ::tcl::array::size startsearch ::tcl::array::startsearch statistics ::tcl::array::statistics unset ::tcl::array::unset





OK, all good so var. Let's add that array_values proc into the namespace



% namespace eval ::tcl::array {
proc values {arrayName} {
upvar 1 $arrayName ary
set values {}
foreach {name value} [array get ary] {lappend values $value}
return $values
}
}
% array set a {foo bar baz qux}
% puts [::tcl::array::values a]




can't set "values": variable is array


Where is this error coming from? I tried renaming the "values" variable in the proc to other names, but it still emits the "variable is array" error.





a note: I can add the first proc to the ensemble:



% namespace ensemble config array -map [list values ::array_values {*}[namespace ensemble config array -map]]
% array values a
bar qux


But what is wrong with my ::tcl::array::values proc?










share|improve this question






















  • As a follow-up on Schelte's answer: Also foreach would have to be qualified, since ::tcl::array::foreach is about to become available (in 8.7, if I am right)? See also my complementary answer.
    – mrcalvin
    Nov 19 '18 at 21:03










  • Just to close this loop, TP 421 implements array for -- core.tcl.tk/tcl/info/7c614b93309da90a
    – glenn jackman
    Nov 20 '18 at 13:54










  • Correct, I was confused by the progenitor discussion on the corresponding bounty: github.com/flightaware/Tcl-bounties/issues/27
    – mrcalvin
    Nov 20 '18 at 14:14


















1














I want to create a convenience command array values arrayName as a "flip side" to the "array names" command.



It's straightforward to create a simple proc:



proc array_values {arrayName} {
upvar 1 $arrayName ary
set values {}
foreach {name value} [array get ary] {lappend values $value}
return $values
}

array set a {foo bar baz qux}
puts [array_values a] ;# => bar qux


However, I'm having difficulty creating a command in the ::tcl::array namespace:





  • first some homework:





    1. is array a namespace ensemble? Yes.



      % namespace ensemble exists array
      1



    2. what is the namespace?



      % namespace ensemble configure array -namespace
      ::tcl::array



    3. what are the subcommands?



      % namespace ensemble configure array -subcommands
      % namespace ensemble configure array -map
      anymore ::tcl::array::anymore donesearch ::tcl::array::donesearch exists ::tcl::array::exists get ::tcl::array::get names ::tcl::array::names nextelement ::tcl::array::nextelement set ::tcl::array::set size ::tcl::array::size startsearch ::tcl::array::startsearch statistics ::tcl::array::statistics unset ::tcl::array::unset





OK, all good so var. Let's add that array_values proc into the namespace



% namespace eval ::tcl::array {
proc values {arrayName} {
upvar 1 $arrayName ary
set values {}
foreach {name value} [array get ary] {lappend values $value}
return $values
}
}
% array set a {foo bar baz qux}
% puts [::tcl::array::values a]




can't set "values": variable is array


Where is this error coming from? I tried renaming the "values" variable in the proc to other names, but it still emits the "variable is array" error.





a note: I can add the first proc to the ensemble:



% namespace ensemble config array -map [list values ::array_values {*}[namespace ensemble config array -map]]
% array values a
bar qux


But what is wrong with my ::tcl::array::values proc?










share|improve this question






















  • As a follow-up on Schelte's answer: Also foreach would have to be qualified, since ::tcl::array::foreach is about to become available (in 8.7, if I am right)? See also my complementary answer.
    – mrcalvin
    Nov 19 '18 at 21:03










  • Just to close this loop, TP 421 implements array for -- core.tcl.tk/tcl/info/7c614b93309da90a
    – glenn jackman
    Nov 20 '18 at 13:54










  • Correct, I was confused by the progenitor discussion on the corresponding bounty: github.com/flightaware/Tcl-bounties/issues/27
    – mrcalvin
    Nov 20 '18 at 14:14
















1












1








1







I want to create a convenience command array values arrayName as a "flip side" to the "array names" command.



It's straightforward to create a simple proc:



proc array_values {arrayName} {
upvar 1 $arrayName ary
set values {}
foreach {name value} [array get ary] {lappend values $value}
return $values
}

array set a {foo bar baz qux}
puts [array_values a] ;# => bar qux


However, I'm having difficulty creating a command in the ::tcl::array namespace:





  • first some homework:





    1. is array a namespace ensemble? Yes.



      % namespace ensemble exists array
      1



    2. what is the namespace?



      % namespace ensemble configure array -namespace
      ::tcl::array



    3. what are the subcommands?



      % namespace ensemble configure array -subcommands
      % namespace ensemble configure array -map
      anymore ::tcl::array::anymore donesearch ::tcl::array::donesearch exists ::tcl::array::exists get ::tcl::array::get names ::tcl::array::names nextelement ::tcl::array::nextelement set ::tcl::array::set size ::tcl::array::size startsearch ::tcl::array::startsearch statistics ::tcl::array::statistics unset ::tcl::array::unset





OK, all good so var. Let's add that array_values proc into the namespace



% namespace eval ::tcl::array {
proc values {arrayName} {
upvar 1 $arrayName ary
set values {}
foreach {name value} [array get ary] {lappend values $value}
return $values
}
}
% array set a {foo bar baz qux}
% puts [::tcl::array::values a]




can't set "values": variable is array


Where is this error coming from? I tried renaming the "values" variable in the proc to other names, but it still emits the "variable is array" error.





a note: I can add the first proc to the ensemble:



% namespace ensemble config array -map [list values ::array_values {*}[namespace ensemble config array -map]]
% array values a
bar qux


But what is wrong with my ::tcl::array::values proc?










share|improve this question













I want to create a convenience command array values arrayName as a "flip side" to the "array names" command.



It's straightforward to create a simple proc:



proc array_values {arrayName} {
upvar 1 $arrayName ary
set values {}
foreach {name value} [array get ary] {lappend values $value}
return $values
}

array set a {foo bar baz qux}
puts [array_values a] ;# => bar qux


However, I'm having difficulty creating a command in the ::tcl::array namespace:





  • first some homework:





    1. is array a namespace ensemble? Yes.



      % namespace ensemble exists array
      1



    2. what is the namespace?



      % namespace ensemble configure array -namespace
      ::tcl::array



    3. what are the subcommands?



      % namespace ensemble configure array -subcommands
      % namespace ensemble configure array -map
      anymore ::tcl::array::anymore donesearch ::tcl::array::donesearch exists ::tcl::array::exists get ::tcl::array::get names ::tcl::array::names nextelement ::tcl::array::nextelement set ::tcl::array::set size ::tcl::array::size startsearch ::tcl::array::startsearch statistics ::tcl::array::statistics unset ::tcl::array::unset





OK, all good so var. Let's add that array_values proc into the namespace



% namespace eval ::tcl::array {
proc values {arrayName} {
upvar 1 $arrayName ary
set values {}
foreach {name value} [array get ary] {lappend values $value}
return $values
}
}
% array set a {foo bar baz qux}
% puts [::tcl::array::values a]




can't set "values": variable is array


Where is this error coming from? I tried renaming the "values" variable in the proc to other names, but it still emits the "variable is array" error.





a note: I can add the first proc to the ensemble:



% namespace ensemble config array -map [list values ::array_values {*}[namespace ensemble config array -map]]
% array values a
bar qux


But what is wrong with my ::tcl::array::values proc?







tcl






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 19 '18 at 17:40









glenn jackman

166k26143234




166k26143234












  • As a follow-up on Schelte's answer: Also foreach would have to be qualified, since ::tcl::array::foreach is about to become available (in 8.7, if I am right)? See also my complementary answer.
    – mrcalvin
    Nov 19 '18 at 21:03










  • Just to close this loop, TP 421 implements array for -- core.tcl.tk/tcl/info/7c614b93309da90a
    – glenn jackman
    Nov 20 '18 at 13:54










  • Correct, I was confused by the progenitor discussion on the corresponding bounty: github.com/flightaware/Tcl-bounties/issues/27
    – mrcalvin
    Nov 20 '18 at 14:14




















  • As a follow-up on Schelte's answer: Also foreach would have to be qualified, since ::tcl::array::foreach is about to become available (in 8.7, if I am right)? See also my complementary answer.
    – mrcalvin
    Nov 19 '18 at 21:03










  • Just to close this loop, TP 421 implements array for -- core.tcl.tk/tcl/info/7c614b93309da90a
    – glenn jackman
    Nov 20 '18 at 13:54










  • Correct, I was confused by the progenitor discussion on the corresponding bounty: github.com/flightaware/Tcl-bounties/issues/27
    – mrcalvin
    Nov 20 '18 at 14:14


















As a follow-up on Schelte's answer: Also foreach would have to be qualified, since ::tcl::array::foreach is about to become available (in 8.7, if I am right)? See also my complementary answer.
– mrcalvin
Nov 19 '18 at 21:03




As a follow-up on Schelte's answer: Also foreach would have to be qualified, since ::tcl::array::foreach is about to become available (in 8.7, if I am right)? See also my complementary answer.
– mrcalvin
Nov 19 '18 at 21:03












Just to close this loop, TP 421 implements array for -- core.tcl.tk/tcl/info/7c614b93309da90a
– glenn jackman
Nov 20 '18 at 13:54




Just to close this loop, TP 421 implements array for -- core.tcl.tk/tcl/info/7c614b93309da90a
– glenn jackman
Nov 20 '18 at 13:54












Correct, I was confused by the progenitor discussion on the corresponding bounty: github.com/flightaware/Tcl-bounties/issues/27
– mrcalvin
Nov 20 '18 at 14:14






Correct, I was confused by the progenitor discussion on the corresponding bounty: github.com/flightaware/Tcl-bounties/issues/27
– mrcalvin
Nov 20 '18 at 14:14














3 Answers
3






active

oldest

votes


















3














Your set values {} command executes in the ::tcl::array namespace, so it runs the ::tcl::array::set command. In other words, it does the equivalent of array set values {}. So it makes values an array with no members. Then the lappend values $value command fails because values is an array at that point.



The solution should be to use ::set values {}



Or you can completely avoid the issue by using:



proc array_values {arrayName} {
upvar 1 $arrayName ary
return [lmap {name value} [get ary] {string cat $value}]
}





share|improve this answer































    1














    I would like to add that, given that the presence of possibly conflicting ensemble commands is a moving target, patching an ensemble is likely to occur from everywhere, I have seen core developers keep extra ensemble commands outside the ::tcl::array::* namespace:



    proc arrayValues {arrayName} {
    upvar 1 $arrayName ary
    set values {}
    foreach {name value} [array get ary] {lappend values $value}
    return $values
    }

    # implant "arrayValues" into [array] ensemble as "values"
    namespace ensemble configure ::array -map
    [dict replace [namespace ensemble configure ::array -map]
    values [namespace which arrayValues]]


    This way, you don't have to worry about unintended resolution conflicts (whatever that means in Tcl, to begin with).






    share|improve this answer























    • Just figured that you had that sorted out anyways (::array_values).
      – mrcalvin
      Nov 19 '18 at 22:18



















    0














    For the curious, this is what I have ended up with:



    $HOME/tcl/lib/monkeypatches/monkeypatches.tcl



    # a set of useful additions to built-in ensembles

    package provide monkeypatches 0.1

    namespace eval ::monkeypatches {
    # https://wiki.tcl-lang.org/page/wrapping+commands
    proc append_subcommand {cmd subcmd procname} {
    set map [namespace ensemble configure ::$cmd -map]
    dict set map $subcmd [namespace which $procname]
    namespace ensemble configure ::$cmd -map $map
    }


    # array foreach
    # to be subsumed by https://core.tcl.tk/tips/doc/trunk/tip/421.md
    #
    # example:
    # array set A {foo bar baz qux}
    # array foreach {key val} A {puts "name=$key, value=$val"}
    #
    proc array_foreach {vars arrayName body} {
    if {[llength $vars] != 2} {
    error {array foreach: "vars" must be a 2 element list}
    }
    lassign $vars keyVar valueVar

    # Using the complicated `upvar 1 $arrayName $arrayName` so that any
    # error messages propagate up with the user's array name
    upvar 1 $arrayName $arrayName
    $keyVar key
    $valueVar value

    set sid [array startsearch $arrayName]
    # If the array is modified while a search is ongoing, the searchID will
    # be invalidated: wrap the commands that use $sid in a try block.
    try {
    while {[array anymore $arrayName $sid]} {
    set key [array nextelement $arrayName $sid]
    set value [set "${arrayName}($key)"]
    uplevel 1 $body
    }
    array donesearch $arrayName $sid
    } trap {TCL LOOKUP ARRAYSEARCH} {"" e} {
    return -options $e "detected attempt to modify the array while iterating"
    }
    return
    }
    append_subcommand array foreach array_foreach


    # array values arrayName
    # https://stackoverflow.com/q/53379995/7552
    #
    # example:
    # array set x {foo bar baz qux}
    # array get x ;# => foo bar baz qux
    # array names x ;# => foo baz
    # array values x ;# => bar qux
    #
    proc array_values {arrayName} {
    upvar 1 $arrayName ary
    set values [list]
    array foreach {name value} ary {lappend values $value}
    return $values
    }
    append_subcommand array values array_values


    # info formalargs procName
    # https://core.tcl.tk/tips/doc/trunk/tip/65.md
    #
    # example:
    # proc test {one {two 2} {three {3 4 5}} args} {return}
    # info args test ;# => one two three args
    # info formalargs test ;# => one {two 2} {three {3 4 5}} args
    #
    proc info_formalargs {procname} {
    # [info args] throws an error if $procname is not a procedure.
    return [lmap arg [info args $procname] {
    set has_d [info default $procname $arg value]
    if {$has_d} then {list $arg $value} else {set arg}
    }]
    }
    append_subcommand info formalargs info_formalargs
    }


    With its associated pkgIndex.tcl



    And $HOME/.tclshrc



    set lib_dir [file join $env(HOME) tcl lib]
    if {$lib_dir ni $auto_path} {lappend auto_path $lib_dir}
    unset lib_dir
    package require monkeypatches





    share|improve this answer























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53379995%2fproblem-creating-new-command-in-array-ensemble%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      3














      Your set values {} command executes in the ::tcl::array namespace, so it runs the ::tcl::array::set command. In other words, it does the equivalent of array set values {}. So it makes values an array with no members. Then the lappend values $value command fails because values is an array at that point.



      The solution should be to use ::set values {}



      Or you can completely avoid the issue by using:



      proc array_values {arrayName} {
      upvar 1 $arrayName ary
      return [lmap {name value} [get ary] {string cat $value}]
      }





      share|improve this answer




























        3














        Your set values {} command executes in the ::tcl::array namespace, so it runs the ::tcl::array::set command. In other words, it does the equivalent of array set values {}. So it makes values an array with no members. Then the lappend values $value command fails because values is an array at that point.



        The solution should be to use ::set values {}



        Or you can completely avoid the issue by using:



        proc array_values {arrayName} {
        upvar 1 $arrayName ary
        return [lmap {name value} [get ary] {string cat $value}]
        }





        share|improve this answer


























          3












          3








          3






          Your set values {} command executes in the ::tcl::array namespace, so it runs the ::tcl::array::set command. In other words, it does the equivalent of array set values {}. So it makes values an array with no members. Then the lappend values $value command fails because values is an array at that point.



          The solution should be to use ::set values {}



          Or you can completely avoid the issue by using:



          proc array_values {arrayName} {
          upvar 1 $arrayName ary
          return [lmap {name value} [get ary] {string cat $value}]
          }





          share|improve this answer














          Your set values {} command executes in the ::tcl::array namespace, so it runs the ::tcl::array::set command. In other words, it does the equivalent of array set values {}. So it makes values an array with no members. Then the lappend values $value command fails because values is an array at that point.



          The solution should be to use ::set values {}



          Or you can completely avoid the issue by using:



          proc array_values {arrayName} {
          upvar 1 $arrayName ary
          return [lmap {name value} [get ary] {string cat $value}]
          }






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 19 '18 at 19:48

























          answered Nov 19 '18 at 19:42









          Schelte Bron

          463128




          463128

























              1














              I would like to add that, given that the presence of possibly conflicting ensemble commands is a moving target, patching an ensemble is likely to occur from everywhere, I have seen core developers keep extra ensemble commands outside the ::tcl::array::* namespace:



              proc arrayValues {arrayName} {
              upvar 1 $arrayName ary
              set values {}
              foreach {name value} [array get ary] {lappend values $value}
              return $values
              }

              # implant "arrayValues" into [array] ensemble as "values"
              namespace ensemble configure ::array -map
              [dict replace [namespace ensemble configure ::array -map]
              values [namespace which arrayValues]]


              This way, you don't have to worry about unintended resolution conflicts (whatever that means in Tcl, to begin with).






              share|improve this answer























              • Just figured that you had that sorted out anyways (::array_values).
                – mrcalvin
                Nov 19 '18 at 22:18
















              1














              I would like to add that, given that the presence of possibly conflicting ensemble commands is a moving target, patching an ensemble is likely to occur from everywhere, I have seen core developers keep extra ensemble commands outside the ::tcl::array::* namespace:



              proc arrayValues {arrayName} {
              upvar 1 $arrayName ary
              set values {}
              foreach {name value} [array get ary] {lappend values $value}
              return $values
              }

              # implant "arrayValues" into [array] ensemble as "values"
              namespace ensemble configure ::array -map
              [dict replace [namespace ensemble configure ::array -map]
              values [namespace which arrayValues]]


              This way, you don't have to worry about unintended resolution conflicts (whatever that means in Tcl, to begin with).






              share|improve this answer























              • Just figured that you had that sorted out anyways (::array_values).
                – mrcalvin
                Nov 19 '18 at 22:18














              1












              1








              1






              I would like to add that, given that the presence of possibly conflicting ensemble commands is a moving target, patching an ensemble is likely to occur from everywhere, I have seen core developers keep extra ensemble commands outside the ::tcl::array::* namespace:



              proc arrayValues {arrayName} {
              upvar 1 $arrayName ary
              set values {}
              foreach {name value} [array get ary] {lappend values $value}
              return $values
              }

              # implant "arrayValues" into [array] ensemble as "values"
              namespace ensemble configure ::array -map
              [dict replace [namespace ensemble configure ::array -map]
              values [namespace which arrayValues]]


              This way, you don't have to worry about unintended resolution conflicts (whatever that means in Tcl, to begin with).






              share|improve this answer














              I would like to add that, given that the presence of possibly conflicting ensemble commands is a moving target, patching an ensemble is likely to occur from everywhere, I have seen core developers keep extra ensemble commands outside the ::tcl::array::* namespace:



              proc arrayValues {arrayName} {
              upvar 1 $arrayName ary
              set values {}
              foreach {name value} [array get ary] {lappend values $value}
              return $values
              }

              # implant "arrayValues" into [array] ensemble as "values"
              namespace ensemble configure ::array -map
              [dict replace [namespace ensemble configure ::array -map]
              values [namespace which arrayValues]]


              This way, you don't have to worry about unintended resolution conflicts (whatever that means in Tcl, to begin with).







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Nov 19 '18 at 21:27

























              answered Nov 19 '18 at 21:11









              mrcalvin

              1,169612




              1,169612












              • Just figured that you had that sorted out anyways (::array_values).
                – mrcalvin
                Nov 19 '18 at 22:18


















              • Just figured that you had that sorted out anyways (::array_values).
                – mrcalvin
                Nov 19 '18 at 22:18
















              Just figured that you had that sorted out anyways (::array_values).
              – mrcalvin
              Nov 19 '18 at 22:18




              Just figured that you had that sorted out anyways (::array_values).
              – mrcalvin
              Nov 19 '18 at 22:18











              0














              For the curious, this is what I have ended up with:



              $HOME/tcl/lib/monkeypatches/monkeypatches.tcl



              # a set of useful additions to built-in ensembles

              package provide monkeypatches 0.1

              namespace eval ::monkeypatches {
              # https://wiki.tcl-lang.org/page/wrapping+commands
              proc append_subcommand {cmd subcmd procname} {
              set map [namespace ensemble configure ::$cmd -map]
              dict set map $subcmd [namespace which $procname]
              namespace ensemble configure ::$cmd -map $map
              }


              # array foreach
              # to be subsumed by https://core.tcl.tk/tips/doc/trunk/tip/421.md
              #
              # example:
              # array set A {foo bar baz qux}
              # array foreach {key val} A {puts "name=$key, value=$val"}
              #
              proc array_foreach {vars arrayName body} {
              if {[llength $vars] != 2} {
              error {array foreach: "vars" must be a 2 element list}
              }
              lassign $vars keyVar valueVar

              # Using the complicated `upvar 1 $arrayName $arrayName` so that any
              # error messages propagate up with the user's array name
              upvar 1 $arrayName $arrayName
              $keyVar key
              $valueVar value

              set sid [array startsearch $arrayName]
              # If the array is modified while a search is ongoing, the searchID will
              # be invalidated: wrap the commands that use $sid in a try block.
              try {
              while {[array anymore $arrayName $sid]} {
              set key [array nextelement $arrayName $sid]
              set value [set "${arrayName}($key)"]
              uplevel 1 $body
              }
              array donesearch $arrayName $sid
              } trap {TCL LOOKUP ARRAYSEARCH} {"" e} {
              return -options $e "detected attempt to modify the array while iterating"
              }
              return
              }
              append_subcommand array foreach array_foreach


              # array values arrayName
              # https://stackoverflow.com/q/53379995/7552
              #
              # example:
              # array set x {foo bar baz qux}
              # array get x ;# => foo bar baz qux
              # array names x ;# => foo baz
              # array values x ;# => bar qux
              #
              proc array_values {arrayName} {
              upvar 1 $arrayName ary
              set values [list]
              array foreach {name value} ary {lappend values $value}
              return $values
              }
              append_subcommand array values array_values


              # info formalargs procName
              # https://core.tcl.tk/tips/doc/trunk/tip/65.md
              #
              # example:
              # proc test {one {two 2} {three {3 4 5}} args} {return}
              # info args test ;# => one two three args
              # info formalargs test ;# => one {two 2} {three {3 4 5}} args
              #
              proc info_formalargs {procname} {
              # [info args] throws an error if $procname is not a procedure.
              return [lmap arg [info args $procname] {
              set has_d [info default $procname $arg value]
              if {$has_d} then {list $arg $value} else {set arg}
              }]
              }
              append_subcommand info formalargs info_formalargs
              }


              With its associated pkgIndex.tcl



              And $HOME/.tclshrc



              set lib_dir [file join $env(HOME) tcl lib]
              if {$lib_dir ni $auto_path} {lappend auto_path $lib_dir}
              unset lib_dir
              package require monkeypatches





              share|improve this answer




























                0














                For the curious, this is what I have ended up with:



                $HOME/tcl/lib/monkeypatches/monkeypatches.tcl



                # a set of useful additions to built-in ensembles

                package provide monkeypatches 0.1

                namespace eval ::monkeypatches {
                # https://wiki.tcl-lang.org/page/wrapping+commands
                proc append_subcommand {cmd subcmd procname} {
                set map [namespace ensemble configure ::$cmd -map]
                dict set map $subcmd [namespace which $procname]
                namespace ensemble configure ::$cmd -map $map
                }


                # array foreach
                # to be subsumed by https://core.tcl.tk/tips/doc/trunk/tip/421.md
                #
                # example:
                # array set A {foo bar baz qux}
                # array foreach {key val} A {puts "name=$key, value=$val"}
                #
                proc array_foreach {vars arrayName body} {
                if {[llength $vars] != 2} {
                error {array foreach: "vars" must be a 2 element list}
                }
                lassign $vars keyVar valueVar

                # Using the complicated `upvar 1 $arrayName $arrayName` so that any
                # error messages propagate up with the user's array name
                upvar 1 $arrayName $arrayName
                $keyVar key
                $valueVar value

                set sid [array startsearch $arrayName]
                # If the array is modified while a search is ongoing, the searchID will
                # be invalidated: wrap the commands that use $sid in a try block.
                try {
                while {[array anymore $arrayName $sid]} {
                set key [array nextelement $arrayName $sid]
                set value [set "${arrayName}($key)"]
                uplevel 1 $body
                }
                array donesearch $arrayName $sid
                } trap {TCL LOOKUP ARRAYSEARCH} {"" e} {
                return -options $e "detected attempt to modify the array while iterating"
                }
                return
                }
                append_subcommand array foreach array_foreach


                # array values arrayName
                # https://stackoverflow.com/q/53379995/7552
                #
                # example:
                # array set x {foo bar baz qux}
                # array get x ;# => foo bar baz qux
                # array names x ;# => foo baz
                # array values x ;# => bar qux
                #
                proc array_values {arrayName} {
                upvar 1 $arrayName ary
                set values [list]
                array foreach {name value} ary {lappend values $value}
                return $values
                }
                append_subcommand array values array_values


                # info formalargs procName
                # https://core.tcl.tk/tips/doc/trunk/tip/65.md
                #
                # example:
                # proc test {one {two 2} {three {3 4 5}} args} {return}
                # info args test ;# => one two three args
                # info formalargs test ;# => one {two 2} {three {3 4 5}} args
                #
                proc info_formalargs {procname} {
                # [info args] throws an error if $procname is not a procedure.
                return [lmap arg [info args $procname] {
                set has_d [info default $procname $arg value]
                if {$has_d} then {list $arg $value} else {set arg}
                }]
                }
                append_subcommand info formalargs info_formalargs
                }


                With its associated pkgIndex.tcl



                And $HOME/.tclshrc



                set lib_dir [file join $env(HOME) tcl lib]
                if {$lib_dir ni $auto_path} {lappend auto_path $lib_dir}
                unset lib_dir
                package require monkeypatches





                share|improve this answer


























                  0












                  0








                  0






                  For the curious, this is what I have ended up with:



                  $HOME/tcl/lib/monkeypatches/monkeypatches.tcl



                  # a set of useful additions to built-in ensembles

                  package provide monkeypatches 0.1

                  namespace eval ::monkeypatches {
                  # https://wiki.tcl-lang.org/page/wrapping+commands
                  proc append_subcommand {cmd subcmd procname} {
                  set map [namespace ensemble configure ::$cmd -map]
                  dict set map $subcmd [namespace which $procname]
                  namespace ensemble configure ::$cmd -map $map
                  }


                  # array foreach
                  # to be subsumed by https://core.tcl.tk/tips/doc/trunk/tip/421.md
                  #
                  # example:
                  # array set A {foo bar baz qux}
                  # array foreach {key val} A {puts "name=$key, value=$val"}
                  #
                  proc array_foreach {vars arrayName body} {
                  if {[llength $vars] != 2} {
                  error {array foreach: "vars" must be a 2 element list}
                  }
                  lassign $vars keyVar valueVar

                  # Using the complicated `upvar 1 $arrayName $arrayName` so that any
                  # error messages propagate up with the user's array name
                  upvar 1 $arrayName $arrayName
                  $keyVar key
                  $valueVar value

                  set sid [array startsearch $arrayName]
                  # If the array is modified while a search is ongoing, the searchID will
                  # be invalidated: wrap the commands that use $sid in a try block.
                  try {
                  while {[array anymore $arrayName $sid]} {
                  set key [array nextelement $arrayName $sid]
                  set value [set "${arrayName}($key)"]
                  uplevel 1 $body
                  }
                  array donesearch $arrayName $sid
                  } trap {TCL LOOKUP ARRAYSEARCH} {"" e} {
                  return -options $e "detected attempt to modify the array while iterating"
                  }
                  return
                  }
                  append_subcommand array foreach array_foreach


                  # array values arrayName
                  # https://stackoverflow.com/q/53379995/7552
                  #
                  # example:
                  # array set x {foo bar baz qux}
                  # array get x ;# => foo bar baz qux
                  # array names x ;# => foo baz
                  # array values x ;# => bar qux
                  #
                  proc array_values {arrayName} {
                  upvar 1 $arrayName ary
                  set values [list]
                  array foreach {name value} ary {lappend values $value}
                  return $values
                  }
                  append_subcommand array values array_values


                  # info formalargs procName
                  # https://core.tcl.tk/tips/doc/trunk/tip/65.md
                  #
                  # example:
                  # proc test {one {two 2} {three {3 4 5}} args} {return}
                  # info args test ;# => one two three args
                  # info formalargs test ;# => one {two 2} {three {3 4 5}} args
                  #
                  proc info_formalargs {procname} {
                  # [info args] throws an error if $procname is not a procedure.
                  return [lmap arg [info args $procname] {
                  set has_d [info default $procname $arg value]
                  if {$has_d} then {list $arg $value} else {set arg}
                  }]
                  }
                  append_subcommand info formalargs info_formalargs
                  }


                  With its associated pkgIndex.tcl



                  And $HOME/.tclshrc



                  set lib_dir [file join $env(HOME) tcl lib]
                  if {$lib_dir ni $auto_path} {lappend auto_path $lib_dir}
                  unset lib_dir
                  package require monkeypatches





                  share|improve this answer














                  For the curious, this is what I have ended up with:



                  $HOME/tcl/lib/monkeypatches/monkeypatches.tcl



                  # a set of useful additions to built-in ensembles

                  package provide monkeypatches 0.1

                  namespace eval ::monkeypatches {
                  # https://wiki.tcl-lang.org/page/wrapping+commands
                  proc append_subcommand {cmd subcmd procname} {
                  set map [namespace ensemble configure ::$cmd -map]
                  dict set map $subcmd [namespace which $procname]
                  namespace ensemble configure ::$cmd -map $map
                  }


                  # array foreach
                  # to be subsumed by https://core.tcl.tk/tips/doc/trunk/tip/421.md
                  #
                  # example:
                  # array set A {foo bar baz qux}
                  # array foreach {key val} A {puts "name=$key, value=$val"}
                  #
                  proc array_foreach {vars arrayName body} {
                  if {[llength $vars] != 2} {
                  error {array foreach: "vars" must be a 2 element list}
                  }
                  lassign $vars keyVar valueVar

                  # Using the complicated `upvar 1 $arrayName $arrayName` so that any
                  # error messages propagate up with the user's array name
                  upvar 1 $arrayName $arrayName
                  $keyVar key
                  $valueVar value

                  set sid [array startsearch $arrayName]
                  # If the array is modified while a search is ongoing, the searchID will
                  # be invalidated: wrap the commands that use $sid in a try block.
                  try {
                  while {[array anymore $arrayName $sid]} {
                  set key [array nextelement $arrayName $sid]
                  set value [set "${arrayName}($key)"]
                  uplevel 1 $body
                  }
                  array donesearch $arrayName $sid
                  } trap {TCL LOOKUP ARRAYSEARCH} {"" e} {
                  return -options $e "detected attempt to modify the array while iterating"
                  }
                  return
                  }
                  append_subcommand array foreach array_foreach


                  # array values arrayName
                  # https://stackoverflow.com/q/53379995/7552
                  #
                  # example:
                  # array set x {foo bar baz qux}
                  # array get x ;# => foo bar baz qux
                  # array names x ;# => foo baz
                  # array values x ;# => bar qux
                  #
                  proc array_values {arrayName} {
                  upvar 1 $arrayName ary
                  set values [list]
                  array foreach {name value} ary {lappend values $value}
                  return $values
                  }
                  append_subcommand array values array_values


                  # info formalargs procName
                  # https://core.tcl.tk/tips/doc/trunk/tip/65.md
                  #
                  # example:
                  # proc test {one {two 2} {three {3 4 5}} args} {return}
                  # info args test ;# => one two three args
                  # info formalargs test ;# => one {two 2} {three {3 4 5}} args
                  #
                  proc info_formalargs {procname} {
                  # [info args] throws an error if $procname is not a procedure.
                  return [lmap arg [info args $procname] {
                  set has_d [info default $procname $arg value]
                  if {$has_d} then {list $arg $value} else {set arg}
                  }]
                  }
                  append_subcommand info formalargs info_formalargs
                  }


                  With its associated pkgIndex.tcl



                  And $HOME/.tclshrc



                  set lib_dir [file join $env(HOME) tcl lib]
                  if {$lib_dir ni $auto_path} {lappend auto_path $lib_dir}
                  unset lib_dir
                  package require monkeypatches






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 20 '18 at 13:45

























                  answered Nov 20 '18 at 2:28









                  glenn jackman

                  166k26143234




                  166k26143234






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53379995%2fproblem-creating-new-command-in-array-ensemble%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      MongoDB - Not Authorized To Execute Command

                      in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith

                      Npm cannot find a required file even through it is in the searched directory