Procedures

part of Tcl for Web Nerds by Hal Abelson, Philip Greenspun, and Lydia Sandon; updated July 2011
To define a procedures in Tcl use the following syntax:
proc name { list_of_arguments } {
   body_expressions
}
This creates a procedure with the name "name." Tcl has a global environment for procedure names, i.e., there can be only one procedure called "foobar" in a Tcl system.

The next part of the syntax is the set of arguments, delimited by a set of curly braces. Each argument value is then mapped into the procedure body, which is also delimited by curly braces. As before, each statement of the procedure body can be separated by a semi-colon or a newline (or both). Here's an example, taken from a calendar widget component:

proc calendar_convert_julian_to_ansi { date } {
    set db [ns_db gethandle subquery]
    # make Oracle do all the real work
    set output [database_to_tcl_string $db \ 
        "select trunc(to_date('$date', 'J')) from dual"]
    ns_db releasehandle $db
    return $output
}
Of course in the actual ACS, we encourage programmers to use proc_doc instead, which defines the procedure but also records a doc string, as described in array variable chapter. Here's what the definition would look like with proc_doc:
proc_doc calendar_convert_julian_to_ansi { date } "Return an ANSI date
for a Julian date" {
    set db [ns_db gethandle subquery]
    # make Oracle do all the real work
    set output [database_to_tcl_string $db \ 
        "select trunc(to_date('$date', 'J')) from dual"]
    ns_db releasehandle $db
    return $output
}


More: http://www.tcl.tk/man/tcl8.4/TclCmd/proc.htm

Scope, Upvar and Uplevel

There are three possible scopes for a variable in an AOLserver Tcl script:

To use a variable locally, you need not declare it. To instruct the Tcl interpreter to read and set a variable in the global environment, you must call global every place that the variable is used. For example, when side graphics have been displayed on a page, ad_footer needs to know so that it can insert a <BR CLEAR=RIGHT> tag.

# a proc that might display a side graphic
proc ad_decorate_side {} {
    # we use a GLOBAL variable (shared by procs in a thread) as opposed to 
    # an ns_share (shared by many threads)
    global sidegraphic_displayed_p
    ...
    set sidegraphic_displayed_p 1
}

proc ad_footer {{signatory ""}} {
    global sidegraphic_displayed_p
    if [empty_string_p $signatory] {
	set signatory [ad_system_owner]
    } 
    if { [info exists sidegraphic_displayed_p] && $sidegraphic_displayed_p } {
	# we put in a BR CLEAR=RIGHT so that the signature will clear any side graphic
	# from the ad-sidegraphic.tcl package
	set extra_br "<br clear=right>"
    } else {
	set extra_br ""
    }
    return "
$extra_br
<hr>
<a href=\"mailto:$signatory\"><address>$signatory</address></a>
</body>
</html>"
}
One of the strangest and most difficult to use features of Tcl is the ability to read and write variables up the calling stack with uplevel and upvar.

More: http://www.tcl.tk/man/tcl8.4/TclCmd/upvar.htm; http://www.tcl.tk/man/tcl8.4/TclCmd/uplevel.htm; http://www.tcl.tk/man/tcl8.4/TclCmd/global.htm

Optional arguments

Here is an example of a procedure that has one required and one optional argument:
proc ad_header {page_title {extra_stuff_for_document_head ""}} {
    set html "<html>
<head>$extra_stuff_for_document_head
<title>$page_title</title>
</head>
"
    return $html
}
If a page calls ad_header with one argument, it gets the standard appropriate HTML header. If a page supplies the extra optional argument, that information gets written into the HEAD. Otherwise, the default value of empty string is used for the second argument.

Variable number of arguments

In addition, Tcl can also provide for a variable number of arguments at the end, using a special last argument called args in any procedure definition. After all of the other (previous) arguments are bound to names, the rest of the arguments are shoved into a list called args which can then be accessed inside the procedure.

You could imagine that between optional arguments and extra ones, the interpreter might get confused. It doesn't, because it assumes that you aren't using extra args at the end without binding all of the optional ones in the middle; that is, it stuffs argument values into the argument names in strict order without regard to options, extras, etc.

Rename

In case this wasn't flexible enough, Tcl lets you rename procedures using a proc called rename old_name new_name. If you wanted to keep the old proc but still take advantage of the great abstraction you've used throughout your site (i.e. not change all of the command calls when you change their bodies), you can rename the old proc and create a new one with the old one's name. You can also use rename with the empty string for the second argument. This results in the proc being deleted.

More: http://www.tcl.tk/man/tcl8.4/TclCmd/rename.htm

Continue on to file commands.
Return to Table of Contents

lsandon@alum.mit.edu
Add a comment | Add a link