Argumentizing a TCL proc dynamically

Clovertech Forums Read Only Archives Cloverleaf Cloverleaf Argumentizing a TCL proc dynamically

  • Creator
    Topic
  • #53340
    Ian Morris
    Participant

      I’d like to know if there’s a way to dynamically argumentize a TCL proc.  For example, let’s say I pass these arguments to my .tcl filter:

      Code:

      {SEGMENT EVN} {FIELDNUMBER 5} {SEARCHCRITERIA foot}

      In my filter, I then have to go in and look for the value of these arguements like this:

      Code:

      keylget uargs SEGMENT segm
      keylget uargs FIELDNUMBER fieldnum
      keylget uargs SEARCHCRITERIA searchcrit

      What if I wanted to dynamically pass my arguments?  So, maybe include the ability to do this:

      Code:

      {SEGMENT EVN} {FIELDNUMBER 5} {SEARCHCRITERIA foot}
      {DECISION and}
      {SEGMENT MSH} {FIELDNUMBER 4} {SEARCHCRITERIA ANESAPP}
      {DECISION or}
      {SEGMENT MSH} {FIELDNUMBER 9} {SEARCHCRITERIA A08}

      Ideally, I would create arrays for SEGMENT, FIELDNUMBER, DECISION.  But, it look like that’s not possible (http://wiki.tcl.tk/3262):

      Entire arrays, however, are not currently able to be passed by value to a Tcl procedure…

      Does anyone have an idea of what may be possible here?

    Viewing 11 reply threads
    • Author
      Replies
      • #77324
        David Barr
        Participant

          Keyed lists aren’t allowed to have multiple entries for the same key, but as long as you are parsing the list with your own code and not using keylget this should work.

          Working with the parameters as you’ve described them seems like it would be very tricky. I can think of a few alternatives.

          Most people will probably say that what you’re doing isn’t advisable and you should just write a new TPS proc with the conditions hard-coded in the proc. That’s certainly the simplest approach and what I’ve usually done.

          Another option would be to pass in a TCL expression as a parameter and use some kind of macro syntax that you interpret before passing the expression to “expr”. So your parameters would look something like this:

          { EXPRESSION { %EVN.5% eq “foot” && %MSH.4% eq “ANESAPP” || %MSH.9% eq “A08” } }

          So your code would have to parse the string and look for your macros (%EVN.5%, etc.) and replace them in the original expression with values taken from the message. Then you evaluate the expression using expr and kill or continue the message based on the result.

        • #77325
          Jim Kosloskey
          Participant

            But a keyed list can contain other keyed lists or lists or lists of keyed lists.

            So you can get quite creative using that flexibility.

            email: jim.kosloskey@jim-kosloskey.com 29+ years Cloverleaf, 59 years IT - old fart.

          • #77326
            Charlie Bursell
            Participant

              And of course my response would be why?

              Why create a proc that takes more time to call correctly than it would take to write a proc to do specifically what you want?  It adds to the maintainability and usabily of the proc.  I prefer KISS!  Write a filter specific to your needs.

              With that said we pass arguments to proc as a keyed list by convention only.  It will certainly work without keys.  The arguments then become positional.  

              You could pass all the args you need and then get the contents of ARGS and pass verbation to a sub-proc in a namespace.  Define that proc like:

              proc myproc {args} {

              The keyword args allow you to pass any number of arguments to a proc as a list.

              Of course you will need a priori knowledge of the positioning of each argument in the list but you should be able to figure that out if you really want to do this.

              Just don’t put it someplace where I have to maintain it   😀

            • #77327
              Ian Morris
              Participant

                Thank you for all of the ideas and tips.  I’m going to think this one over.

              • #77328
                Jeff Dinsmore
                Participant

                  … and I might respond why not?

                  As far as I’m concerned, this type of overloading of the the process call structure is often advisable, and most often produces simpler to maintain code.

                  For example, I have a procedure that’s an indexer for SMAT files – defined like this:

                  proc cloverLogUtils::smatIndexMaster { args } {

                   

                   

                  }

                  Of course, the cloverLogUtils namespace must be defined – and you need code where it says … but you get the idea.

                  Call it like this, and it indexes all SMAT files it knows about – and assumes a “secondary” role:

                   cloverLogUtils::smatIndexMaster INDEXALL

                  Call it like this and it does the same thing, but in a Master/primary role:

                   cloverLogUtils::smatIndexMaster INDEXALL primary

                  Call it like this and it indexes just the specified (adt_in) SMAT in an explicitly secondary role:

                   cloverLogUtils::smatIndexMaster  adt_in secondary

                  All of this is done with the same core code with a wee bit of overhead for handling the args. We get compact code – with no need to duplicate its logic in other procedures. If it’s busted – I’m sure other peoples’ code sometimes is ;o) – we fix it in one place rather than two or three or ten. If we add an enhancement, same thing. Nice, neat and maintainable.

                  A one-off copy of something like this is, perhaps easier to maintain than general purpose code, but as soon as you start making copies of the same logic for multiple uses and/or with multiple nuances, your maintenance task eventually becomes unmanageable.

                  Jeff Dinsmore
                  Chesapeake Regional Healthcare

                • #77329
                  Charlie Bursell
                  Participant

                    I did not say, nor did I mean to imply that process loading should *NEVER* be used.  I use that and optional arguments a lot for procs I write

                    My point was why would you want to write an arcane proc that will do everything but wash your car when it is so simple, in most cases, to write a filter proc for the explicit purpose

                  • #77330
                    David Barr
                    Participant

                      I don’t think the proc has to be arcane. The main advantage that I see to implementing a proc that can take its filtering logic from the arguments is for ease of troubleshooting.

                      I don’t know about you, but I’m often asked why a Cloverleaf filter blocked a particular message. To troubleshoot these types of problems I have to look at the list of TPS filters (which are usually on the route). Then if there’s a custom TPS proc I have to look through the source code. If the filter is a generic proc with all of the information in the arguments then I don’t have to look at any source code.

                      Code:

                             run {
                                 package require hl7
                                 keylget args MSGID mh
                                 keylget args ARGS.EXPRESSION expr1
                                 set disp CONTINUE
                                 set hl7 [hl7::parse_msg [msgget $mh]]
                                 set expr2 “”
                                 set parts [split $expr1 %]
                                 for { set i 0 } { $i 0 } {
                                         append expr2 “””
                                     }
                                     set part [lindex $parts $i]
                                     if { $i % 2 == 0 } {
                                         append expr2 [string map { “‘” “”” } $part]
                                     } else {
                                         append expr2 [hl7::get_field hl7 $part]
                                     }
                                 }
                                 if { ![expr $expr2] } {
                                     set disp KILL
                                 }
                                 lappend dispList “$disp $mh”
                             }

                      This requires a library that I’ve posted in another thread. It uses the argument syntax that I gave in my previous post, but I had to replace double-quotes in the arguments with single-quotes or it confused the testing tool.

                    • #77331
                      Ian Morris
                      Participant

                        That’s very helpful.  Thank you!

                      • #77332
                        Todd Horst
                        Participant

                          I frequently pass the name of an array with settings. Then in the called proc I upvar to get a local copy of the array

                        • #77333
                          Greg Tataryn
                          Participant

                            If you are using this to filter, why not write a proc to create a custom trxid and use that to “filter” your messages down?

                          • #77334
                            David Barr
                            Participant

                              Todd Horst wrote:

                              I frequently pass the name of an array with settings. Then in the called proc I upvar to get a local copy of the array

                              How do you get the settings into the array? Why is this better than passing the arguments directly?

                            • #77335
                              Todd Horst
                              Participant

                                i was just talking about passing arrays in general.

                                The proc itself:

                                proc other_Email { settings_name } {

                                [code]
                                proc other_Email { settings_name } {

                            Viewing 11 reply threads
                            • The forum ‘Cloverleaf’ is closed to new topics and replies.