Procedures and scope
The cards come in more than one shape: a command to explain, a snippet with a fault to find, and a description whose command you name. A missed card returns later in the round and starts the schedule over. A card answered correctly moves up the schedule and next appears after 1, 3, 7, then 21 days. Keys 1 to 4 choose an option, h shows a hint, and Enter moves on. A hint keeps the card where it is on the schedule. An ordering card is answered by clicking its items in order, and one wrong click ends it. Time values are in nanoseconds. Progress is stored in this browser.
All 8 cards in this section, with answers
-
proc report_stage {stage {verbose 0}} { puts "stage $stage" if { $verbose } { report_design_area } }Defines a command whose second argument is optional, defaulting to 0.
Hint: Read the second parameter: it is written differently from the first.
A parameter written as a two-element list gives a default. The special name
argscollects any remaining arguments into a list, which is how a wrapper passes options through to the command it wraps. Tcl reference -
proc count_cell {} { global cell_count incr cell_count }Makes the global variable visible inside the procedure.
Hint: Ask what a procedure can see by default.
A procedure's variables are local unless declared otherwise, so a script that sets a variable at the top level and expects a procedure to see it is a common bug.
upvarlinks to a caller's variable by name, which is how a procedure modifies a variable passed to it. Tcl reference -
proc add_to {listVar item} { upvar 1 $listVar l lappend l $item }Links the caller's variable to a local name, so changes reach the caller.
Hint: The procedure is given a variable's name rather than its value.
Tcl passes arguments by value, so modifying a list means passing its name and linking to it. The
1is how many levels up to look, almost always the immediate caller.uplevelis the same idea for running a script in the caller's scope. Tcl reference -
proc report {stage args} { puts "$stage: $args" } report place -verbose -limit 10Whatever is left over arrives as a list in the final parameter.
Hint: The last parameter has a name the language treats specially.
This is how a wrapper passes options through to the command it calls, usually with
{*}$argsso the list is expanded back into separate arguments rather than passed as one. It is the standard way to wrap a tool command and add a default. Tcl reference -
proc worst {slacks} { lindex [lsort -real $slacks] 0 }The value of the last command is returned.
Hint: There is no return statement, and yet the procedure is useful.
An explicit
returnis still clearer, and it is needed to leave early or to return something other than the last value. Its option form sets the code as well, soreturn -code errorraises an error the caller can catch, exactly aserrordoes. Tcl reference -
namespace eval flow { variable count 0 proc reset {} { variable count; set count 0 } } flow::resetA named scope for procedures and variables.
Hint: Ask what would happen if the procedure were called `reset` at the top level.
A tool's interpreter already holds hundreds of commands, and a procedure named the same as one of them replaces it silently for the rest of the session. Namespacing a script's own procedures is the way to stay clear of that, and
variableis how a procedure reaches the namespace's data. Tcl reference -
set count 0 proc bump {} { incr count }The procedure has its own scope, so it does not see that variable.
Hint: Ask which variable the procedure is reaching for.
A procedure sees only its own variables and those it names with
global,variable, orupvar. As written it fails, since there is no local variable to increment. The clearer fix in a tool script is often to pass the value in and return the new one. Tcl reference -
Your procedure is given the name of a variable belonging to its caller, and it has to change that variable rather than a copy.upvar 1 $varName local
Hint: The procedure needs a local name that stands for the caller's variable.
Linking the names makes every later use of the local name act on the caller's variable. Declaring it global reaches the top level instead, which is wrong when the caller is another procedure, and assigning through the name only works if the variable happens to be visible. Tcl reference