[getopt-sig] Prefer non-imperative -- my 1 cent

Joshua Rodman joshua_rodman@yahoo.com
Tue, 12 Feb 2002 15:15:08 -0800 (PST)


--0-1006439860-1013555708=:30853
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

--- Russ Cox <rsc@plan9.bell-labs.com> wrote:

> I will grant that perhaps there are cases where the
> loop might just get too big, but I have a hard time
> envisioning them.  In particular, just having
> lots of options doesn't seem like enough to make
> the option loop not work.  You claim that tying "all
> the logic related to an option into a single solitary
> stanza" is a good thing, which I grant.  What I don't
> understand is how many of these:
> 
> 	elif o=='-o' or '--optionlong':
> 		# single solitary stanza here
> 
> don't actually do that or could get "sufficiently
> bloated that it is difficult to take in the structure
> of it at once."

In practice I find that the tradditional style equates to:

initialize a bunch of things to defaults
call the parser
loop:
   handle option:
      verify option is valid
         if not: usage()
      ...

perform some additional checks and assignments

If nothing else, optik-style puts the initializers, the variable 
assigned to, and the break on invalid assignment all in one spot,
instead of sprinkled over three locations. 

On a possibly incorrect side-note, I've found that the traditional
loop seems to encourage the use of state flags during the walking
of the loop.  At least, in larger projects I've bumped into, this
seems rather common, and rather ugly.  I'm speaking here from the
school of thought that says that constricture which eliminates
bad choices is good.  Some people hate this school of thought. :-)

> All that aside, my big problem with the Optik-style
> modules, and to a lesser extent getopt, is the barrier
> to entry.  Option parsing is something everyone has to
> do, more or less; it should require as little work
> as possible to get simple parsing in place.  The fact
> that it's _not_ simple enough is why people settle for
> quick and dirty things like
> 
> 	if sys.argv[1]=='-d':
> 		debug=1
> 		sys.argv = sys.argv[1:]
> 
> when they want just one or two options.  This problem
> is certainly endemic in C programs; I haven't surveyed
> enough Python programs to make informed comments about
> how widespread the practice is in Python.
> 
> On the other hand, since (in the module I posted)
> it's hardly any more code to use the option parser:
> 
> 	opt = OptionParser()
> 	for o in opt:
> 		if o=='-d':
> 			debug=1
> 
> I think people are more likely to use it, even for quick
> and dirty argument parsing.  I think that's the big deal.

WARNING: Anecdotal consideration ahead!

You're right of course.  Traditional getopt was too much of
a barrier to use for me. Strangely, the ornateness of Optik
I found much easier to get into.  Scripts I'd never have 
bothered to set up getopt for, I'm finding I bother to create 
option arguments for. I think it has a lot to do with the 
elimination of the usage() function, the usage string, and 
the copious calls to that exit-point from the program.

Maybe I just haven't given a system like yours a proper try.
I admit I'm biased against it: eliminating the loop walking 
is _very_ seductive to me. I don't like the idea of building 
the loop machinery every time when that's the same across 
all option parsers.

> Of course, it's possible that there is some hybrid scheme
> that would satisfy everyone, but I really don't have
> any feel for argument parsing so hairy that you need
> parsing objects and callbacks and the like: someone please
> enlighten me.

Parsing objects don't seem heavy to me.  Callbacks are of course,
but I've not yet felt the desire to use them.  What _has_ been
a huge benefit to me is the extensibility of optik. 

I had a tool which required option pairs for a left hand side
and a right hand side of a set of operations.  For example, 
given a fruit-eating program, you want to be able to say:

  eatfruits --fruitcount 5 

and have it eat 5 apples and five pears.  Or

  eatfruits --pears --fruitcount 5 --apples --fruitcount 3

and have it eat 3 apples and 5 pears.  This example stinks, in
the real case it made sense to do this.  I had about 10 different
values with more expected in the future, some of them dependent on
each other.  Creating this in a traditional loop structure would
have me create a tristate flag variable and extra handling with
each assignment.  I _think_ it would have been painful to build.
I was avoiding it because it sounded just awful, even to the point
of having a poor framework for debugging the rest of the system.

In optik, I subclassed the option object, added my behavior, 
and it was done.  Admittedly I still had a tristate flag variable,
but the logic was all encapsulated in the interface.  

The actual example is a bit of a counterargument, as I'm extending
in a direction it isn't really designed to go, so it's a bit bulky.
I'm also a rather inexpert Python programmer, so I suspect I'm 
implementing passthrough to the base class inexpertly.  Attached
if interesting.

All this may only serve to elaborate on my prejudice, as I haven't
thought deeply enough about the other way.  Feel free to dump it in
the trash if it says nothing useful to you.

> Thanks.
> Russ

Thanks for taking my rambling more seriously than it really deserves. :-)

-josh



__________________________________________________
Do You Yahoo!?
Send FREE Valentine eCards with Yahoo! Greetings!
http://greetings.yahoo.com
--0-1006439860-1013555708=:30853
Content-Type: application/octet-stream; name="optik_pairs.py"
Content-Transfer-Encoding: base64
Content-Description: optik_pairs.py
Content-Disposition: attachment; filename="optik_pairs.py"

IyEvdXNyL2Jpbi9lbnYgcHl0aG9uCmZyb20gb3B0aWsub3B0aW9uX3BhcnNl
ciBpbXBvcnQgVmFsdWVzCmZyb20gb3B0aWsgaW1wb3J0IE9wdGlvbgoKY2xh
c3MgUGFpck9wdGlvbihPcHRpb24pOgogICAgQUNUSU9OUyA9IE9wdGlvbi5B
Q1RJT05TICsgICAgICAgICAgICAgKCJzdG9yZV9wYWlyIiwpCiAgICBTVE9S
RV9BQ1RJT05TID0gT3B0aW9uLlNUT1JFX0FDVElPTlMgKyAoInN0b3JlX3Bh
aXIiLCkKICAgIFRZUEVEX0FDVElPTlMgPSBPcHRpb24uVFlQRURfQUNUSU9O
UyArICgic3RvcmVfcGFpciIsKQoKICAgIE1FVEFfU1RPUkVfQUNUSU9OUyA9
ICAgICAgICAgICAgICAgICAgICgic3RvcmVfcGFpciIsKQoKICAgIEFUVFJT
ID0gT3B0aW9uLkFUVFJTICsgICAgICAgICAgICAgICAgIFsic3ViYWN0aW9u
Il0KCiAgICBkZWYgX19pbml0X18oc2VsZiwgKm9wdHMsICoqYXR0cnMpOgog
ICAgICAgIGFwcGx5KE9wdGlvbi5fX2luaXRfXywgKHNlbGYsKSArIG9wdHMs
IGF0dHJzKQogICAgICAgIHNlbGYuX2NoZWNrX3N1YmFjdGlvbigpCgogICAg
ZGVmIF9jaGVja19zdWJhY3Rpb24oc2VsZik6CiAgICAgICAgaWYgc2VsZi5h
Y3Rpb24gaW4gc2VsZi5NRVRBX1NUT1JFX0FDVElPTlM6CiAgICAgICAgICAg
IGlmIHNlbGYuc3ViYWN0aW9uIGlzIE5vbmU6CiAgICAgICAgICAgICAgICBz
ZWxmLnN1YmFjdGlvbiA9ICJzdG9yZSIKICAgICAgICAgICAgZWxpZiBzZWxm
LmFjdGlvbiBub3QgaW4gc2VsZi5TVE9SRV9BQ1RJT05TOgogICAgICAgICAg
ICAgICAgcmFpc2UgT3B0aW9uRXJyb3IoImludmFsaWQgc3ViYWN0aW9uOiAl
ciIgJSBzZWxmLnN1YmFjdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICBzZWxmKQoKICAgIGRlZiB0YWtlX2FjdGlvbihzZWxmLCBh
Y3Rpb24sIGRlc3QsIG9wdCwgdmFsdWUsIHZhbHVlcywgcGFyc2VyKToKICAg
ICAgICBpZiBhY3Rpb24gPT0gInN0b3JlX3BhaXIiOgogICAgICAgICAgICB0
YXJnX2xvYyA9IHZhbHVlcy5lbnN1cmVfdmFsdWUoZGVzdCwgW05vbmVdKjIp
CiAgICAgICAgICAgIGR1bW15dmFsdWVzID0gVmFsdWVzKCkKICAgICAgICAg
ICAgaWYgbm90IHZhbHVlcy5lbnN1cmVfdmFsdWUoJ3BhaXJfY29udHJvbCcs
ICcnKSA9PSAic2Vjb25kIjoKICAgICAgICAgICAgICAgIGR1bW15dmFsdWVz
LmZpcnN0ID0gdGFyZ19sb2NbMF0KICAgICAgICAgICAgICAgIHNlbGYudGFr
ZV9hY3Rpb24oc2VsZi5zdWJhY3Rpb24sICdmaXJzdCcsIG9wdCwgdmFsdWUs
IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdW1teXZhbHVl
cywgcGFyc2VyKQogICAgICAgICAgICAgICAgdGFyZ19sb2NbMF0gPSBkdW1t
eXZhbHVlcy5maXJzdAogICAgICAgICAgICBpZiBub3QgdmFsdWVzLnBhaXJf
Y29udHJvbCA9PSAiZmlyc3QiOgogICAgICAgICAgICAgICAgZHVtbXl2YWx1
ZXMuc2Vjb25kID0gdGFyZ19sb2NbMV0KICAgICAgICAgICAgICAgIHNlbGYu
dGFrZV9hY3Rpb24oc2VsZi5zdWJhY3Rpb24sICdzZWNvbmQnLCBvcHQsIHZh
bHVlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHVtbXl2
YWx1ZXMsIHBhcnNlcikKICAgICAgICAgICAgICAgIHRhcmdfbG9jWzFdID0g
ZHVtbXl2YWx1ZXMuc2Vjb25kCiAgICAgICAgZWxzZToKICAgICAgICAgICAg
T3B0aW9uLnRha2VfYWN0aW9uKHNlbGYsIGFjdGlvbiwgZGVzdCwgb3B0LCB2
YWx1ZSwgdmFsdWVzLCBwYXJzZXIpCgo=

--0-1006439860-1013555708=:30853--