quantum231
quantum231

Reputation: 2585

Pass few but not all optional arguments to a Tcl procedure

In TCL the way to make a parameter optional is to give it a default value. I don't know if there are any other ways too. e.g

proc my_func {a b c {d 10} {e 11} {f 12}} {
  ...
}

Now in the above example the parameters a, b and c are compulsory. The parameters d, e and f are optional. Is there another way to create optional parameters?

I am in a situation where I need to create a parameter that can be called from a TCL terminal (in Xilinx Vivado) which has some optional parameters. The user decide to pass a few or all of the optional parameters or none at all. The problem is that, when using positional argument passing, it is impossible to tell TCL which optional parameter we are passing to it. What is the solution to this? e.g

my_func 1 2 3 4 5 6 

shall call the my_func with values a=1, b=2, c=3, d=4, e=5 and f=6. Also,

my_func 1 2 3 4 

shall call my_func with values a=1, b=2, c=3 and d=4 and the e, f left at their default values. However, I might need to do something like this

my_func 1 2 3 100

where I am passing 100 to f and leave c and d at default value. But the above stament will set d to 100 instead and leave e and f at their default values.

What is the solution since I can clearly not use the positional argument technique here.

Upvotes: 0

Views: 210

Answers (3)

mrcalvin
mrcalvin

Reputation: 3434

The below is a minor variation to the solutions already suggested. By using dict with, on can unpack the dictionary content into the proc-local scope as variables:

proc my_func {a b c args} {
  set () [dict merge {(d) 10 (e) 11 (f) 12} $args]
  dict with () {}
  puts "a = $a"
  puts "b = $b"
  puts "c = $c"
  puts "d = $(d)"
  puts "e = $(e)"
  puts "f = $(f)"
}

Some remarks:

  • To avoid collisions with other (existing?) proc-local variables, the optional parameters are denoted as elements of an array named using the empty string: ().
  • dict with will unpack the so-named keys into that array: (e), (f), ...
  • The processed optionals can be accessed via $ syntax: $(e), $(f), ...

Watch:

my_func 1 2 3
my_func 1 2 3 (e) 100 (d) 200

Yields:

a = 1
b = 2
c = 3
d = 10
e = 11
f = 12
a = 1
b = 2
c = 3
d = 200
e = 100
f = 12

Upvotes: 1

glenn jackman
glenn jackman

Reputation: 246744

A readable way to design the function is to do it Tk style: use -d 100 options:

proc my_func {a b c args} {
    set opts [dict merge {-d 10 -e 11 -f 12} $args]

    puts "a = $a"
    puts "b = $b"
    puts "c = $c"
    puts "d = [dict get $opts -d]"
    puts "e = [dict get $opts -e]"
    puts "f = [dict get $opts -f]"
}

Then when you use them, you can specify them in any order:

% my_func
wrong # args: should be "my_func a b c ?arg ...?"
% my_func 1 2 3
a = 1
b = 2
c = 3
d = 10
e = 11
f = 12
% my_func 1 2 3 -e 100 -d 200
a = 1
b = 2
c = 3
d = 200
e = 100
f = 12

Upvotes: 2

Chris Heithoff
Chris Heithoff

Reputation: 1863

If the final argument in your proc definition is literally args, then the remaining arguments (if any) are collected in a list.

This proc demonstrates how d,e,f can be optional. The optional arguments are included as a {name value} pair.

proc my_func {a b c args} {
    set defaults {d 10 e 11 f 12}
    foreach {var_name var_value} $defaults {
        set $var_name $var_value
    }

    foreach arg $args {
        set [lindex $arg 0] [lindex $arg 1]
    }

     puts "a:$a b:$b c:$c d:$d e:$e f:$f"
}

tcl8.6.8> my_func 1 2 3
  a:1 b:2 c:3 d:10 e:11 f:12

tcl8.6.8> my_func 1 2 3 {d 5} {e 8} {f 99}
  a:1 b:2 c:3 d:5 e:8 f:99

tcl8.6.8> my_func 1 2 3 {f 99}
  a:1 b:2 c:3 d:10 e:11 f:99

Upvotes: 1

Related Questions