From: Harry Ohlsen Date: 2002-10-12T06:27:05+09:00 Subject: Re: Polymorphism, Isomorphism On Thu, 10 Oct 2002 06:12, Phil Tomson wrote: > ClassA.isomorphic?(ClassB) #returns true if there is a 1:1 correspondence > #between methods in ClassA and ClassB > ClassA.containsMethods?(ClassB) #returns true if ClassA defines all of the > # same methods that ClassB has defined (but > # ClassA could define methods not defined in > # ClassB I think you'd be better off with something more like how Java checks whether a class implements a defined interface at compile time. Ie, some way of specifying a set of methods and asking whether the class provides all of them. I'm sure someone will give me a shorter or more efficient version, but ... I would think this is pretty easy. Something like ... class Object def implements?(methods) !(methods.flatten.map { |m| self.respond_to? m } .include? false) end end class A def f; end def g; end def h; end end class B def g; end def h; end def i; end end puts A.new.implements?([:f, :g]) # => true puts A.new.implements?([:g, :h]) # => true puts A.new.implements?([:f, :g, :h]) # => true puts A.new.implements?([:g, :h, :i]) # => false puts B.new.implements?([:g, :h, :i]) # => true More likely, you'd use it like ... $interfaceGH = [:g, :h] $interfaceHI = [:h, :i] $interface GHI = [$interfaceGH, $interfaceHI] puts A.new.implements? $interfaceGH # => true puts B.new.implements? $interfaceGH # => true puts A.new.implements? $interfaceGHI # => false puts B.new.implements? $interfaceGHI # => true In any case, you could use this inside methods that need objects that have specific interfaces. Eg ... def fred(a, b) raise "Parameter 'a' unusable" unless a.implements? $interfaceA raise "Parameter 'b' unusable" unless b.implements? $interfaceB end If you dislike the Java association, you could call the method "provides?" perhaps. By the way, I was surprised that I needed to make those interface variables globals in order to use them inside fred(). Why is that? I would have thought they were in scope anyway. I learn something new every day !! What I'd prefer is to be able to say Runnable = [:run] def fred(a) raise "Unusable 'a' parameter" unless a.implements? Runnable end since I would think of interface specifications as being logically similar to classes, as in Java (hence the capitalisation). However, that didn't work, either. By the way, I would think a simple change to respond_to?, allowing it to accept an array (with, potentially, sub-arrays, hence the flattening), would provide the same thing, without having to add a new method. > Also, what about this idea of set operations on Classes (where we look at > classes and modules as sets of methods)? Would it buy us anything? That one, I'll have to think about !! Cheers, Harry O.