From: Robert Date: 2003-01-06T00:17:53+09:00 Subject: Re: Interfaces in Ruby (attempted summary) Hi all, in order to clarify my understanding of the issue at hand I tried to summarize the discussion. Comments are welcome. Interfaces in Ruby - the short story. There are none. Ok, since this was quite short, we'll try a bit harder. :-) Interfaces in Ruby - the real story. Technically speaking Ruby does not need interfaces since it is dynamically typed. Any argument list that at least satisfies the arity condition can be handed into a method. Since people appreciate the usage of interfaces and even more Design by Contract (DbC) some mechanics were developed that mimic interfaces and certain aspects of DbC. I list them in order of increasing complexity. (1) Document which methods a method argument must implement or its expected type. (2) Define a module containing the methods that all raise an exception like this: module FooInterface def bar(a,b) raise "bar(a,b) must be overridden"; end end class FooClass include FooInterface def bar(a,b) a+b; end end (3) Create a framework (like the one Paul Brannan suggested here [1]) for defining interface methods and for checking that a particular instance implements these methods. (4) Try to support even more of DbC by dealing with preconditions and postconditions like I tried in [2]. However: these things tend to get complicated and ugly, which seems to be quite un-rubyish. Apart from that, they never reach the robustness and power of languages with such features built in (like Eiffel). From the perspective of an Eiffel developer this might not be satisfactory. But then, one should keep in mind the different focus of Ruby. OO capabilities are still a lot better than in Perl. Regards robert [1] http://rm-f.net/~cout/code/ruby/treasures/RubyTreasures-0.3/lib/hacks/interf ace.rb.html [2] Imperfect DbC experiments: class ConditionException < Exception; end class PreConditionException < ConditionException; end class PostConditionException < ConditionException; end module Contract def type_check(value, type) raise TypeError, "#{value} is not #{type}" unless value.kind_of? type end def pre_condition_check(binding, *predicates) predicates.each do |p| raise PreConditionException, "violation of '#{p.strip}'" unless eval(p, binding) end end def post_condition_check(binding, *predicates) predicates.each do |p| raise PostConditionException, "violation of '#{p.strip}'" unless eval(p, binding) end end end module FooContract include Contract def bar(a,b) # check preconditions env = binding() type_check(a, String) type_check(b, Integer) pre_condition_check env, %{ a.length < 10 }, %{ a.length > 0 } # invoke method result = barImpl(a,b) # check postconditions env = binding() type_check(result, Array) post_condition_check env, %{ result.size == 3 } # finished return result end end class FooImpl include FooContract protected def barImpl(a,b) [a, b, a*b]; end end foo = FooImpl.new f.bar("x",3) begin f.bar("x","3") rescue Exception => e p e end begin f.bar("xxxxxxxxxxx",3) rescue Exception => e p e end begin f.bar("",3) rescue Exception => e p e end