For Programmers: Free Programming Magazines  


Home > Archive > Tcl > October 2005 > Passing "dash" Options to a procedure









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Passing "dash" Options to a procedure
Sam

2005-10-20, 7:00 pm

I've been looking for a way to write my TCL procedures to accept "dash"
options, but I haven't had any luck.

As an example, I'm trying to take something like this:

sub my_proc { {var1 "foo"} {var2 "bar"}} {
puts $var1
puts $var2
}
which does:
>my_proc

foo
bar
>my_proc cat

cat
bar

and turn it's interface into this
>my_proc -var2 dog

foo
dog
>

So now it will still have it's defaults, but I can override var2 without
having to specify var1.
Does anyone have any ideas how to do this? I'm sure it's been solved before.
If so, does anyone know of a package that's out there that can handle this
type of option passing?


davidhbigelow@simplifiedlogic.com

2005-10-20, 7:00 pm

Use SNIT instead. It is faster and easier to use, and you can have
option specific value validation.

Dave

Bryan Oakley

2005-10-20, 7:00 pm

Sam wrote:[color=darkred]
> I've been looking for a way to write my TCL procedures to accept "dash"
> options, but I haven't had any luck.
>
> As an example, I'm trying to take something like this:
>
> sub my_proc { {var1 "foo"} {var2 "bar"}} {
> puts $var1
> puts $var2
> }
> which does:
>
>
> foo
> bar
>
>
> cat
> bar
>
> and turn it's interface into this
>


Lately I've taken the long, straight-forward approach. Something like
the following, though it has the slight divantage of pushing the
definition of the defaults down into the proc:

proc my_proc {args} {
set var1 foo
set var2 bar
while {[string match -* [lindex $args 0]} {
set option [lindex $args 0]
set args [lrange $args 1 end]
switch -exact -- $option {
-var1 {
set var1 [lindex $args 0]
set args [lrange $args 1 end]
}
-var2 {
...
}
...
default {
return -code error "unknown option \"$option\""
}
-- {break}
}
}
puts "var1 is $var1"
puts "var2 is $var2"
}

It's not fancy, but it gets the job done and any programmer can quickly
grasp how to add more options, remove options, etc without having to
learn some fancy option parsing library.

Usually I combine it with an array for the options so I can do something
like this:

proc my_proc {args} {
# establish defaults
array set options {-var1 foo -var2 bar}
...
switch -exact -- $option {
...
-var2 {
set options($option) [lindex $args 0]
set args [lrange $args 1 end]
}
...
}
...

Using array elements, I think, makes the code easier to follow. If
you're a page deep into the code and you see something like

if {$options(-var1) eq ...} ...

.... it's pretty obvious that you're comparing an argument to something.
Bruce

2005-10-20, 9:57 pm

Bryan Oakley wrote:
> Sam wrote:
>
>
> Lately I've taken the long, straight-forward approach. Something like
> the following, though it has the slight divantage of pushing the
> definition of the defaults down into the proc:
>
> proc my_proc {args} {
> set var1 foo
> set var2 bar
> while {[string match -* [lindex $args 0]} {
> set option [lindex $args 0]
> set args [lrange $args 1 end]
> switch -exact -- $option {
> -var1 {
> set var1 [lindex $args 0]
> set args [lrange $args 1 end]
> }
> -var2 {
> ...
> }
> ...
> default {
> return -code error "unknown option \"$option\""
> }
> -- {break}
> }
> }
> puts "var1 is $var1"
> puts "var2 is $var2"
> }
>
> It's not fancy, but it gets the job done and any programmer can quickly
> grasp how to add more options, remove options, etc without having to
> learn some fancy option parsing library.
>
> Usually I combine it with an array for the options so I can do something
> like this:
>
> proc my_proc {args} {
> # establish defaults
> array set options {-var1 foo -var2 bar}
> ...
> switch -exact -- $option {
> ...
> -var2 {
> set options($option) [lindex $args 0]
> set args [lrange $args 1 end]
> }
> ...
> }
> ...
>
> Using array elements, I think, makes the code easier to follow. If
> you're a page deep into the code and you see something like
>
> if {$options(-var1) eq ...} ...
>
> ... it's pretty obvious that you're comparing an argument to something.


all nice reasons. Additionally I like using an array of options defined
because then it is trivial to allow abbreviations of options, by using
foreach {opt arg} $args {
set fullopt [array names options $opt*]
switch [llength $fullopt] {
0 {
error "invalid option '$opt' \
must be one of [join [array names options] ", "]"
}
1 {
puts "option $fullopt set to $arg"
}
default {
error "ambiguous option '$opt' \
must be one of [join $fullopt ", "] "
}
}

Bruce
suchenwi

2005-10-21, 7:57 am

I tend to use a local "anonymous array" for such dashed options:

proc example args {
array set "" {-from 0 -to end -foo bar} ;# defaults
array set "" $args

#----- using options:
puts"foo $(-foo) from: $(-from) to $(-to)"
}

Juan C. Gil

2005-10-21, 7:57 am

On the heavyweight side, The Simple Development Library
(http://simpledevlib.sourceforge.net/) syntax for arguments is clean
and simple:

declare-proc my_proc {
{-var1 any foo {}}
{-var2 any foo {}}
} {
puts $var1
puts $var2
}

Juan Carlos---

Larry Smith

2005-10-21, 7:03 pm

Sam wrote:
> I've been looking for a way to write my TCL procedures to accept "dash"
> options, but I haven't had any luck.
>
> As an example, I'm trying to take something like this:
>
> sub my_proc { {var1 "foo"} {var2 "bar"}} {
> puts $var1
> puts $var2
> }


http://wiki.tcl.tk/init is the simplest and lightest-weight
solution. The above would become:

proc my_proc { args } {
init var1 "foo" var2 "bar"
puts $var1
puts $var2
}

init can also parse your argv inputs and returns a vector of
arguments that were present but didn't match any init'd vars.

--
..-. .-. .---. .---. .-..-.|Experts in Linux: www.WildOpenSource.com
| |__ / | \| |-< | |-< > / |"Making the bazaar more commonplace"
`----'`-^-'`-'`-'`-'`-' `-' |Check out my new novel: "Cloud Realm" at:
home:www.smith-house.org:8000|<-this url + /books/list.html
Bryan Oakley

2005-10-21, 9:56 pm

Larry Smith wrote:
> http://wiki.tcl.tk/init is the simplest and lightest-weight
> solution. The above would become:
>
> proc my_proc { args } {
> init var1 "foo" var2 "bar"
> puts $var1
> puts $var2
> }
>


The thing I don't like about that is, if you aren't familiar with the
'init' proc, there's absolutely no clue that it parses args and thus
becomes a maintenance issue. I personally think the API would be more
self-evident if you had to pass in the actual args or name of the
variable containing the args, to wit:

init -using args var1 "foo" var2 "bar"

or, for command line args:

init -using ::argv var1 "foo" var2 "bar"
GN

2005-10-22, 7:56 am

XOTcl provides C-implementend non-positional arguments,
which result in very little overhead (i measured six times lower
invocation overhead compared to a tcl implemented counterpart)

one can do with xotcl e.g. the following:

::xotcl::Object sample
sample proc foo {{-arg1:boolean false} {-arg2 123} -arg3 arg4} {
puts "arg1: $arg1, arg2: $arg2, arg4: $arg4"
}

sample foo 4711

which prints "arg1: false, arg2: 123, arg4: 4711". arg3 is an optional
argument without default value. In odrder to hide the object
one can do e.g.


interp alias {} foo {} sample foo
foo -arg1 true 4711

Check our the section about non positional arguments in
http://media.wu-wien.ac.at/doc/tutorial.html

davidhbigelow@simplifiedlogic.com

2005-10-23, 3:58 am

After looking at the various ways to skin the same cat, I figured you
needed a good snit example:

package require snit
snit::type myObj {
option -var1 -default "foo"
option -var2 -default "bar"
}

# Create your instance of the object
myObj cat

# Get cat options
cat cget -var1
--> foo
cat cget -var2
--> bar

cat configure -var1 "hello world"
cat cget -var1
--> hello world


# Create a dog instance
myObj dog

dog cget -var1
--> foo
dog cget -var2
--> bar

# Notice this change is not in any order!
dog configure -var2 "snit is " -var1 "nice day"

dog cget -var2
--> snit is
dog cget -var1
--> nice day

As you can see, SNIT ROCKS for things like this! It was very well
designed and is easy to use even with simple little objects like this.
You can do so much more with this - e.g. data value validation, type
formatting, etc and custom methods/procs within the object to do things
for you. Easy to use, easy to implement and I highly recomend it. :)

Dave

Larry Smith

2005-10-24, 9:57 pm

Bryan Oakley wrote:
> Larry Smith wrote:
>
>
> The thing I don't like about that is, if you aren't familiar with the
> 'init' proc, there's absolutely no clue that it parses args and thus
> becomes a maintenance issue. I personally think the API would be more
> self-evident if you had to pass in the actual args or name of the
> variable containing the args, to wit:
>
> init -using args var1 "foo" var2 "bar"
>
> or, for command line args:
>
> init -using ::argv var1 "foo" var2 "bar"


I've spent quite a bit of time trying to come up with a
good name. "init" really does "init" things - it takes
a list of names and values and sets up the vars for you
in one go. The fact that those values can also be changed
by arguments being passed is true but not really germain.
But it is true that "init" really doesn't imply arg parsing.

The -using switch idea is interesting, though. I like it,
it makes init more flexible. You could, for instance, init
using a catenation of args and some module-specific init
list, which would be a bit of a pain in the neck with init
as-is. I think I might work that in.

--
..-. .-. .---. .---. .-..-.|Experts in Linux: www.WildOpenSource.com
| |__ / | \| |-< | |-< > / |"Making the bazaar more commonplace"
`----'`-^-'`-'`-'`-'`-' `-' |Check out my new novel: "Cloud Realm" at:
home:www.smith-house.org:8000|<-this url + /books/list.html
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com