On Sat, 11 Jun 2005, Eric Mahurin wrote:

> I don't really like this because:
>
> a. if you put this all over the place, it will significantly
> degrade the code readability

i strongly disagree here.  in the case of short examples it is roughly
equivalent

   def method argv
     pa = parseargs(argv){
       required_argument 'a'
       optional_argument 'b'
     }
   end

four lines

   def method a, b
     @a = a
     @b = b
   end

two lines

in the real world, in case where you might actually use parseages, it will
shine

   TWENTY_SIX_KEWORDS_AT_ONCE = ('a' .. 'z').to_a

   def method argv
     pa = parsearges(argv){
       required_argument 'foobar'
       keywords TWENTY_SIX_KEWORDS_AT_ONCE
     }
   end

four lines

now, if you write some loop that accepts all those kewords and loads them into
a hash, openstruct, or something - and does not allow any other keywords,
raising an ArgumentError if they are passed in, and then you duplicate this in
all the methods that have that kind of logic, your code will be at least 10
time more verbose and obfusicated.

essentially your comment is like saying

   help = (ARGV.include? '-h' or ARGV.include? '--help')

is better/more readable than using optparse or getoplong.  true if that's all
you are doing (for instance in an example) - otherwise severely false.

another example

   class CascadingStyleSheet
     class Element
       FontProperties = %w(
         font-family
         font-style
         font-variant
         font-weight
         font-size
         font
       )
       ColorAndBackgroundProperties = %w(
         color
         background-color
         background-image
         background-repeat
         ...
         ...
       )
       TextProperties = %w(
         ...
         ...
       )
       BoxProperties = %w(
         ...
         ...
       )
       ClassificationProperties = %w(
         ...
         ...
       )

       CSSProperties = FontProperties + ColorAndBackgroundProperties +
                       TextProperties + BoxProperties + ClassificationProperties


       attr 'selector'

       CSSProperties.each{|prop| attr prop}

       def initialize argv
         pa = parseargs(argv) {
           required_argument 'selector'
           keywords CSSProperties
         }

         self.selector = pa.selector

         CSSProperties.each{|prop| send prop, pa.prop}
       end

       def font_configure argv
         pa = parseargs(argv) {
           keywords FontProperties
         }
         ...
       end

       def box_configure
         pa = parseargs(argv) {
           keywords FontProperties
         }
         ...
       end
     end
   end


it's this kind of code that spirals out of control with rampant DRY violations
unless parseargs or a roll-your-own type argv parsing scheme is devised.

> b. efficiency.  You've added unnecessary checking.  Why not let
> the code raise the exception when it doesn't find the method?

it's only added if you like.  you don't have to use the duck-typing feature at
all.  besides, you approach is simply not valid for some cases (like nearly
all the code i have around here) that do things like

   def method job, logger

     job.submit_job_to_queue_that_takes_three_to_five_days

     logger.info{ "job <#{ job.name }> finished with <#{ job.status }>"

   end

now, if logger doesn't repsond to 'info' or job doesn't respond to 'name' and
'status' i'll blow up and not log a job that just took three days to run.
bummer.

> c. this may actually hinder some duck typing.  In your example above, you
> might make the method not always call both upcase and downcase (maybe
> another boolean arg might control that).  If the caller has enough control,
> he could call the method with an object that just responds to one of them.
> But parseargs unnecessarily prohibit that.

again - it's __experimental__.  these kinds of comments are great and
precisely what this group is best at.


> d. this only starts to capture the true duck-type.

absolutely true.  remember - it's an arg parsing module not a duck typing
toolset.


> To really describe it, you would need a more elaborate system which included
> conditions when the arguments methods are called, description of the
> requirements for the arguments to those methods, and what the duck-type
> should be for return values of those methods.

absolutely.  there are several attempts on the RAA.

> If you are able to implement that, then you really are going to make the
> first problem even worse - code clutter.

which is is why i chose to implement the simplest possible thing that could
work and which covers the most common usage.  at the very least it's something
people might be able to build upon.

> I think the description of the duck-type only belongs in the documentation.
> I don't really see the advantage of putting it in the code.

three days - banking transactions - remote method invocations...  there are
tons of scenarios where you need to either know your object can do such and
such or try to make it if does not because each attempt is expensive in terms
of disk, cpu, or network.  it's luxurious to be able to write code that can
just crash or be run again - but it's not always possible.

>> hear hear!
>
> I guess I really should have said "use pure duck-typing everywhere".  What I
> mean by that is that methods shouldn't try to categorize or test the
> capabilities of their arguments at all - don't use #respond_to?, #class,
> etc.  I used to use #respond_to? occassionally to make overloaded methods,
> but am now convinced to go the pure duck-typing route - splitting overloaded
> methods into multiple methods.

again - this notion ignores all notion of temporality and cost.  what if you
were paying for a slot on a super-computer and wouldn't be able to get in
again for three weeks and had a pending paper due?

cheers.

-a
-- 
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| My religion is very simple.  My religion is kindness.
| --Tenzin Gyatso
===============================================================================