Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby and duck typing: design by contract impossible?

Method signature in Java:

public List<String> getFilesIn(List<File> directories)

similar one in ruby

def get_files_in(directories)

In the case of Java, the type system gives me information about what the method expects and delivers. In Ruby's case, I have no clue what I'm supposed to pass in, or what I'll expect to receive.

In Java, the object must formally implement the interface. In Ruby, the object being passed in must respond to whatever methods are called in the method defined here.

This seems highly problematic:

  1. Even with 100% accurate, up-to-date documentation, the Ruby code has to essentially expose its implementation, breaking encapsulation. "OO purity" aside, this would seem to be a maintenance nightmare.
  2. The Ruby code gives me no clue what's being returned; I would have to essentially experiment, or read the code to find out what methods the returned object would respond to.

Not looking to debate static typing vs duck typing, but looking to understand how you maintain a production system where you have almost no ability to design by contract.

Update

No one has really addressed the exposure of a method's internal implementation via documentation that this approach requires. Since there are no interfaces, if I'm not expecting a particular type, don't I have to itemize every method I might call so that the caller knows what can be passed in? Or is this just an edge case that doesn't really come up?

like image 292
davetron5000 Avatar asked Oct 07 '08 02:10

davetron5000


People also ask

Does Ruby use duck typing?

Depending on the language, variables' type can be defined statically or dynamically. Ruby relies on a principle that is called Duck Typing.

Is duck typing good?

With duck typing the type doesn't matter as long as it has the right method, so it really just eliminates a lot of the hassle of casting and conversions between types. There is plenty of anecdotal evidence suggesting that duck typing is significantly more productive than static typing.

Does Java use duck typing?

Java does not support duck typing. The method signature has to specify the correct type for each argument. For example, an argument has to implement the “duck” interface. It is not enough for a class to have the same methods that are provided for in the interface; no, it is necessary to actually write implements Duck.


2 Answers

What it comes down to is that get_files_in is a bad name in Ruby - let me explain.

In java/C#/C++, and especially in objective C, the function arguments are part of the name. In ruby they are not.
The fancy term for this is Method Overloading, and it's enforced by the compiler.

Thinking of it in those terms, you're just defining a method called get_files_in and you're not actually saying what it should get files in. The arguments are not part of the name so you can't rely on them to identify it.
Should it get files in a directory? a drive? a network share? This opens up the possibility for it to work in all of the above situations.

If you wanted to limit it to a directory, then to take this information into account, you should call the method get_files_in_directory. Alternatively you could make it a method on the Directory class, which Ruby already does for you.

As for the return type, it's implied from get_files that you are returning an array of files. You don't have to worry about it being a List<File> or an ArrayList<File>, or so on, because everyone just uses arrays (and if they've written a custom one, they'll write it to inherit from the built in array).

If you only wanted to get one file, you'd call it get_file or get_first_file or so on. If you are doing something more complex such as returning FileWrapper objects rather than just strings, then there is a really good solution:

# returns a list of FileWrapper objects
def get_files_in_directory( dir )
end

At any rate. You can't enforce contracts in ruby like you can in java, but this is a subset of the wider point, which is that you can't enforce anything in ruby like you can in java. Because of ruby's more expressive syntax, you instead get to more clearly write english-like code which tells other people what your contract is (therein saving you several thousand angle brackets).

I for one believe that this is a net win. You can use your newfound spare time to write some specs and tests and come out with a much better product at the end of the day.

like image 89
Orion Edwards Avatar answered Sep 20 '22 07:09

Orion Edwards


I would argue that although the Java method gives you more information, it doesn't give you enough information to comfortably program against.
For example, is that List of Strings just filenames or fully-qualified paths?

Given that, your argument that Ruby doesn't give you enough information also applies to Java.
You're still relying on reading documentation, looking at the source code, or calling the method and looking at its output (and decent testing of course).

like image 32
Darren Greaves Avatar answered Sep 17 '22 07:09

Darren Greaves