user3069844
user3069844

Reputation: 23

How to declare optional arguments in proc

Could you help me how to use arguments with optionals I used this function but it does not work

proc {my_proc} {n1 n2 -args{{u2 "5"} {u1 "5"}} } {

puts "n1:'$n1', n2:'$n2', u1:'$u1', u2:'$u2'"
}

->my_proc 1 -args 5 7
n1:'1', n2:'$n2', u1:'7', u2:'5'

I would like to call function like

  1. my_proc 1 -args {u2 5} {u1 7}
  2. my_proc 1 {u2 5} {u1 7} (required + optional arguments)
  3. my_proc 1 (only required arguments)

Upvotes: 1

Views: 1957

Answers (2)

Donal Fellows
Donal Fellows

Reputation: 137567

You are strongly recommended to use only one of these patterns in a particular command:

  1. Optional arguments, where the optional-ness is by position.
  2. Optional key-value pairs.

Combining the two is relatively hard to get right, and is always rather confusing!

Optional by position

proc my_proc {n1 n2 {u2 "5"} {u1 "5"}} {
    puts "n1:'$n1', n2:'$n2', u1:'$u1', u2:'$u2'"
}
my_proc 7 8 9
#### n1:'7', n2:'8', u1:'5', u2:'9'

Optionality by key-value pair

proc my_proc {n1 n2 args} {
    # Add the defaults
    set args [dict merge {-u1 5 -u2 5} $args]
    # Magic! (Keys start with “-” by arbitrary convention.)
    # Copies from the value for key “-u1” to $u1 (and similarly “-u2”/$u2)
    # The empty value is an update script; empty here as we don't want to update
    dict update args  -u1 u1  -u2 u2  {}

    # Use...
    puts "n1:'$n1', n2:'$n2', u1:'$u1', u2:'$u2'"
}
my_proc 7 8 -u1 123 -u2 456
#### n1:'7', n2:'8', u1:'123', u2:'456'

There's a few other ways to do this, e.g., with dict set options $args;puts $options(-u1). These are particularly useful in Tcl 8.4 (and before, for the truly behind-the-times):

proc my_proc {n1 n2 args} {
    # Defaults
    array set opt {-u1 5 -u2 5}
    # Parse
    array set opt $args
    # Use
    puts "n1:'$n1', n2:'$n2', u1:'$opt(-u1)', u2:'$opt(-u2)'"
}
my_proc 7 8 -u1 123 -u2 456
#### n1:'7', n2:'8', u1:'123', u2:'456'

Upvotes: 4

glenn jackman
glenn jackman

Reputation: 246807

As Donal suggested, I like to use args and an array to handle options. It allows an easy way to set default values:

proc p {args} {
    array set options {-u1 defU1 -u2 defU2}  ;# the default values
    array set options $args                  ;# merge the user's values
    parray options
}
p -foo bar -u1 42
options(-foo) = bar
options(-u1)  = 42
options(-u2)  = defU2

You will need to check that $args contains an even number of elements:

% p 1 2 3
list must have an even number of elements

Upvotes: 0

Related Questions