Abstract interfaces as a means of documentation

Hi all,

The issue of abstract interfaces has been discussed extensively in
this group. The general consensus is that Ruby’s duck typing coupled
with the power of mixins renders solves the vast majority of the
problems interfaces in general and abstract interfaces in particular
were designed to solve in static languages like Java and C#.

However, one issue that wasn’t addressed is documentation. An abstract
interface has the advantage of a single place to actually document the
interface. Consider a couple Ruby classes that implement the same
interface:

class FooTypePlayer
def jump

end

def climb(arg1, arg2)
end
end

class BarTypePlayer
def jump

end

def climb(arg1, arg2)
end
end

And now I want to document what these methods do (with a block comment
describing the arguments and return values, presenting examples,
etc.), and I want the documentation to be reflected in the RDoc of my
code. What are my options ? As I see it, several:

  1. Duplicate the same documentation for each class.
  • This is hardly feasible for large class-families and violates DRY.
  1. Don’t document. Give the methods and arguments descriptive names,
    and write test cases that show how to use them.
  • I will write unit tests anyway, and I definitely try to give methods
    and arguments descriptive names, but a talkative block of
    documentation with examples is essential for anything but trivial
    classes.
  1. Create a “dummy” abstract class that doesn’t really do anything
    (and is never instantiated), something like:

Documentation ! bla bla bla…

class AbstractPlayer

bla bla bla

def jump; end;

This method… and returns …, the arguments are …

def climb(arg1, arg2); end;
end

Now, I can inherit FooTypePlayer and BarTypePlayer from AbstractPlayer
to show certainly that they’re related, I can also fill in the methods
of AbstractPlayer by throwing “NotImplementedError”. Although this all
is unnecessary, it might be a good solution for a single place of
documenting this interface.

What do you think ?

Eli

On Jun 15, 6:57 am, Eli B. [email protected] wrote:
[snip]

  1. Create a “dummy” abstract class that doesn’t really do anything
    (and is never instantiated), something like:
  1. Create a Module and document the method in the module, and then
    include that module in each class. Similar to your abstract class, but
    solves the problems of instantiation, and allows you to mix in methods
    along various axes.

module JumpingClimbingPlayer

docs here

def jump
raise “You should implement this per player”
# or maybe implement the common technique
end

same for climb

end

class FooTypePlayer
include JumpingClimbingPlayer
def jump
# specific implementation here
end
end

end

same for climb

end

class FooTypePlayer
include JumpingClimbingPlayer
def jump
# specific implementation here
end
end

Is this really different from declaring JumpingClimbingPlayer as a
class and inheriting the concrete classes from it, like:

class FooTypePlayer < JumpingClimbingPlayer

?

On 6/15/07, Eli B. [email protected] wrote:

Is this really different from declaring JumpingClimbingPlayer as a
class and inheriting the concrete classes from it, like:

class FooTypePlayer < JumpingClimbingPlayer

Yes. Modules cannot be inherited from or instantiated.

On Jun 16, 1:53 am, “Gregory B.” [email protected] wrote:

On 6/15/07, Eli B. [email protected] wrote:

Is this really different from declaring JumpingClimbingPlayer as a
class and inheriting the concrete classes from it, like:

class FooTypePlayer < JumpingClimbingPlayer

Yes. Modules cannot be inherited from or instantiated.

Understood, thanks. Another thing - say that for some reason I want my
classes not to have the default .new constructor, and instead use
factory methods (for example, it’s important to return values from the
factory methods, other than the object).

In a normal class, I can say:

class Foo
private_class_method :new

self.create(a, b)
… # do stuff
return [new(a, b), message]
end

private
def initialize(a, b)

end
end

But if I want a class family adhering to an abstract interface (like
the previous posts show), how can I do that with a Module ? Module
doesn’t allow the “private_class_method” line since it doesn’t have
a :new method. With an abstract base Class (instead of Module) it is
possible, isn’t it ?

Eli

On 6/16/07, Eli B. [email protected] wrote:

But if I want a class family adhering to an abstract interface (like
the previous posts show), how can I do that with a Module ? Module
doesn’t allow the “private_class_method” line since it doesn’t have
a :new method. With an abstract base Class (instead of Module) it is
possible, isn’t it ?

module B

def create
new(20)
end

end

class A

extend B

def initialize(foo)
@foo = foo
end

def bar
@foo + 10
end
end

c = A.create
c.bar #=> 30