views:

205

answers:

5

Hi,

I'm currently trying to learn Ruby and I'm trying to understand more about what it offers in terms of encapsulation and contracts.

In C# a contract can be defined using an interface. A class which implements the interface must fulfil the terms within the contract by providing an implementation for each method and property (and maybe other things) defined. The individual class that implements an interface can do whatever it needs within the scope of the methods defined by the contract, so long as it accepts the same types of arguments and returns the same type of result.

Is there a way to enforce this kind of thing in Ruby?

Thanks

A simple example of what I mean in C#:

interface IConsole
{
    int MaxControllers {get;}
    void PlayGame(IGame game);
}

class Xbox360 : IConsole
{
   public int MaxControllers
   {
      get { return 4; }
   }

   public void PlayGame(IGame game)
   {
       InsertDisc(game);
       NavigateToMenuItem();
       Click();
   }
}

class NES : IConsole
{
    public int MaxControllers
    {
        get { return 2; }
    }

   public void PlayGame(IGame game)
   {
       InsertCartridge(game);
       TurnOn();
   }
}
+10  A: 

There are no interfaces in ruby since ruby is a dynamically typed language. Interfaces are basically used to make different classes interchangeable without breaking type safety. Your code can work with every Console as long it behaves like a console which in C# means implements IConsole. "duck typing" is a keyword you can use to catch up with the dynamic languages way of dealing with this kind of problem.

Further you can and should write unit tests to verify the behavior of your code. Every object has a respond_to? method you can use in your assert.

Zebi
Admittedly, it might be useful to be able to say [respond_to? <some interface>], with <some interface> meaning some collection of operations. For a method that expects a list of objects as inputs that supports the expected operations (add, remove, find, length, etc), it could validate that it's input does, indeed, satisfy those requirements without needing to check each one. The object in question wouldn't need to be any type of object, just support the operations declared by "that interface".
RHSeeger
@myself - Seems like it would be entirely possible to define a respond_to? type command validates against an "interface" (list of methods) that just iterates over the methods in the "interface" and returns true if they're all met.
RHSeeger
+1  A: 

Ruby doesn't really have them; interfaces and contracts generally live more in the static world, rather than the dynamic.

There is a gem called Handshake that can implement informal contracts, if you really need it.

Matchu
+1  A: 

Ruby uses the concept of Modules as a stand-in (kinda) for interfaces. Design Patterns in Ruby has a lot of really great examples on the differences between the two concepts and why ruby chooses the more flexible alternative to interfaces.

http://www.amazon.com/Design-Patterns-Ruby-Russ-Olsen/dp/0321490452

Jed Schneider
Interfaces have no functionality, Modules do.
Marc-André Lafortune
+2  A: 

Interfaces are usually introduced to static typed OO languages in order to make up for lack of multiple inheritance. In other words, they are more of a necessary evil than something useful per se.

Ruby, on the other hand:

  1. Is dynamically typed language with "duck typing", so if you want to call method foo on two objects, they don't need to neither inherit same ancestor class, nor implement the same interface.
  2. Supports multiple inheritance through concept of mixins, again no need for interfaces here.
Mladen Jablanović
+4  A: 

Ruby has Interfaces just like any other language.

Note that you have to be careful not to conflate the concept of the Interface, which is an abstract specification of the responsibilities, guarantees and protocols of a unit with the concept of the interface which is a keyword in the Java, C# and VB.NET programming languages. In Ruby, we use the former all the time, but the latter simply doesn't exist.

It is very important to distinguish the two. What's important is the Interface, not the interface. The interface tells you pretty much nothing useful. Nothing demonstrates this better than the marker interfaces in Java, which are interfaces that have no members at all.

Another good example:

interface ICollection<T>: IEnumerable<T>, IEnumerable
{
    void Add(T item);
}

What is the Interface of ICollection<T>.Add?

  • that the length of the collection does not decrease
  • that all the items that were in the collection before are still there
  • that item is in the collection

And which of those actually shows up in the interface? None! There is nothing in the interface that says that the Add method must even add at all, it might just as well remove an element from the collection.

This is a perfectly valid implementation of that interface:

class MyCollection<T>: ICollection<T>
{
    void Add(T item)
    {
        Remove(item);
    }
}

Another example: where in java.util.Set<E> does it actually say that it is, you know, a set? Nowhere! Or more precisely, in the documentation. In English.

In pretty much all cases of interfaces, both from Java and .NET, all the relevant information is actually in the docs, not in the types. So, if the types don't tell you anything interesting anyway, why keep them at all? Why not stick just to documentation? And that's exactly what Ruby does.

Note that there are other languages in which the Interface can actually be described in a meaningful way. However, those languages typically don't call the construct which describes the Interface "interface", they call it type. In a dependently-typed programming language, you can for example express the properties that a sort function returns a collection of the same length as the original, that every element which is in the original is also in the sorted collection and that no bigger element appears before a smaller element.

Jörg W Mittag