View · Index

Tcl Procs

  • Use namespace

    Define your procs with a namespace like mypackage::foo_proc. Here is a discussion about [this]. Check many examples in the code, example:

    namespace eval auth {} 
    
    ad_proc -public auth::require_login { 
         {-level ok} 
         {-account_status ok} 
      } { 
         doc...  
         @return something 
         @see ad_script_abort 
      } { 
      ... proc body 
    }
    
  • Use procs safely and their safer variations to help keep code robust and avoid security issues.

    Particularly in cases, where user_input is processed, be sure to avoid executing unwanted code. Use the Tcl expand operator {*} instead of eval. Use
        {*}$cmd
    instead of
        eval $cmd
    For legacy code, you might use  util::safe_eval instead of eval in such cases; subst_safe precedes meta characters with backslashes.

  • Use named parameters whenever possible 

    Define named parameters on your procs such that parameters will not be mixed up if somebody makes a mistake on passing the order of parameters. Also, this makes the proc easier to add additional parameters in the future if needed.

    Use:

       ad_proc proc_name { {-parent_id pid} {-child_id cid} } ...

    and not

       ad_proc proc_name {pid cid} ...

    This way, developers will need to call proc stating explicitly which parameter are passed. This is especially useful when some parameters are optional.

    Also, when calling a proc in your Tcl script, it is recommended to write one parameter per line like this:

       set my_var [proc_name  \ 
                        -parent_id $pid \ 
                        -child_id $cid]

    Rather than:

       set my_var [proc_name -parent_id $pid -child_id cid]

    Again, this helps to make the code more clean and readable.


  • Use ad_proc to define your Tcl procs

    Make use of ad_proc. And make use of the self documentation facility of ad_proc.

    	ad_proc foo {}
    	   Use this area to document
    	} 
    	   # .... your implementation of proc foo
    	}
    

    This way, the API browser will pick up your documentation automatically. Is encouraged to use automatic api-doc documentation that ad_provides, such as: @author, @return, @see

  • Use "ad_proc -private ..." always when a proc is used only in one package

    This reduces the size of the public API and improves the flexibility of the package maintainers.

  • Use "ad_proc -deprecate ..." when removing definitions from the public API

    When deprecated code is called, the error.log of the site will show its usage. This way, a site maintainer can update with code with the new replacement call.

    Don't move deprecated calls immediately to the long-range backward compatibility procs (tcl/deprecated-procs.tc). When OpenACS is configured to omit loading of long deprecated code (WithDeprecatedCode set to 0) these files are not loaded to reduce the every growing blueprint bloat. Therefore, these files should only contain code, which was deprecated at LEAST ONE RELEASE EARLIER, such that site admins have one release time to fix calls to deprecated code.

  • Avoid using "upvar"

    Try to avoid using "upvar". If needed, pass in a parameter that specifies the "upvar" name. This way, the one using your proc has the option to name his/her variable. Example:

        ad_proc upvaring {-upvar_name:required} {
            upvar $upvar_name local_var
        }
    
  • Use modern Tcl idioms

    Do not use "==" in comparing strings. Using "if {$string == "foo"}" tries to make a numeric comparison first. Instead, make use of "if {"foo" eq $string}" or if you need the negation "if {"foo" ne $string}".

    Do not use "if {[lsearch -exact $list $element] > -1}", but use "if {$element in $list}" instead, or "if {$element ni $list}" in case a "not in" test is required.

  • Always "return" at the end of your proc

    And if you have to return more than one variable, use associative arrays, which can be extended by additional fields without breaking code

    So instead of this:

       ad_proc ... {
          ..... 
          return [list $creation_status $creation_message ...]
       } 
    use key/value pairs or Tcl arrays to group related information:
       ad_proc ... {     
          array set creation_info {
                     creation_status {}
                     creation_message {}
                     element_messages {}
                     account_status {}
                     account_message {}              
          } 
          .....     
          return [array get creation_info] 
       } 
  • ... or even better: use Tcl dicts
       ad_proc proc ... {} {
    	  set creation_info [dict create  \
    	               creation_status {}   \
    	               creation_message {}  \
    	               element_messages {}  \
    	               account_status {}    \
    	               account_message {}   ]
    	  ....     
          return $creation_info 
      }
    
    
  • Read the Tcl Style guide

    This is the Tcl style guide (PDF), try to apply relevant guidelines. In particular chapter 4,5 and 7

previous October 2022
Sun Mon Tue Wed Thu Fri Sat
25 26 27 28 29 30 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

Popular tags

17 , 5.10 , 5.10.0 , 5.9.0 , 5.9.1 , ad_form , ADP , ajax , aolserver , asynchronous , bgdelivery , bootstrap , bugtracker , CentOS , COMET , compatibility , CSP , CSRF , cvs , debian , docker , docker-compose , emacs , engineering-standards , exec , fedora , FreeBSD , guidelines , host-node-map , hstore
No registered users in community xowiki
in last 30 minutes
Contributors

OpenACS.org