Hi --

On Sun, 29 Sep 2002, Massimiliano Mirra wrote:

> On Sun, Sep 29, 2002 at 12:09:32PM +0900, dblack / candle.superlink.net wrote:
> > Another thing people often point to that might deter people from
> > learning a truly type-unchecked programming style is the wordiness of
> > the most often-mentioned alternative, the "respond_to?" test:
> >
> >    thing.action if thing.respond_to?(action)
>
> Do you really want your method to go on even if `thing' doesn't
> respond to `action'?  Similarly, would you do the following?
>
>     thing.action if thing.is_a?(Thing)
>
> That would look as redundant (and dangerous).
>
> > This has the look and feel of duplicate, workaround code.  Whereas
> > this:
> >
> >    raise ArgumentError unless obj.is_a?(Thing)
>
> Sorry David, I feel you're comparing apples and oranges here. :-)

Yes, I don't think all my examples are synonymous with each other.

> If verbs were always chosen for method names, this could be nice:
>
>     obj.can?(:mkdir)
>
> And this wouldn't be too bad:
>
>     def meth(obj)
>       continue if
>         obj.can?(:mkdir) and
> 	obj.can?(:recurse) and
> 	obj.can?(:list)
>
>
> Or more concise:
>
>     def meth(obj)
>       continue if obj.can?(:mkdir, :recurse, :list)


I don't think the verb thing is a necessity.  Maybe I'm just being
influenced by the "Ich kann Deutsch" ("I can [speak] German") idiom.
Actually this is all reminiscent of Franz Schubert's stock question,
upon being introduced to or told about another person: "Kann er was?"
(Can he do anything? i.e., is he good at anything?)  :-)

Anyway, just for fun, here's a little testbed.  Ummmm, it just got
less little.  It expands modules and classes into their public
instance methods, so you can do obj.can?(Enumerable).

  module Kernel
    def can?(*meths)
      x_meths = meths.map do |m|
        begin
          m.public_instance_methods
        rescue NameError
          m
        end
      end .flatten
      not x_meths.detect { |m| not respond_to?(m) }
    end

    def screen_for(*meths)
      if can?(*meths)
        yield
        true
      else
        false
      end
    end

  end

  class CanTest
    def meth(obj)
      raise NameError unless obj.can?(:split, :chomp)
      obj.split(//)
    end

    def screen_me(obj)
      obj.screen_for(:split, :chomp) do
        puts "OK, passed the screen"
        obj.split(//)
      end
    end

    def screen_for_Enum(obj)
      obj.screen_for(Enumerable) do
        puts "OK, passed the Enum screen"
        obj.each {|e| puts "Element: #{e}"}
      end
    end
  end

  c = CanTest.new
  puts c.meth("abc")
  begin puts c.meth([]); rescue NameError; puts "Didn't work with []";
  end

  puts c.screen_me("abc")
  puts c.screen_for_Enum([1,2,3])
  puts c.screen_for_Enum(3)


David

-- 
David Alan Black                      | Register for RubyConf 2002!
home: dblack / candle.superlink.net     | November 1-3
work: blackdav / shu.edu                | Seattle, WA, USA
Web:  http://pirate.shu.edu/~blackdav | http://www.rubyconf.com