Browse DevX
Sign up for e-mail newsletters from DevX


A Java Developer's Guide to Ruby : Page 3

Ruby's versatility and flexibility complement Java well. That's why a Java developer who can program in Ruby is more effective and efficient than one who programs only in Java.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Ruby Duck Typing
In Java, you can call a method only on an object that is defined (with public, package, etc. visibility) in the object's class hierarchy. Suppose that you have a collection of objects and you want to iterate over each element in the collection, calling one or more methods. In Java, the objects would need to be part of the same class hierarchy or implement interfaces defining the methods that you want to call.

As you have probably already guessed, Ruby is much more flexible. Specific data types and classes are not required in Ruby's runtime method-calling scheme. Suppose you call method foo on an object obj, and then call method bar on the resulting object of this first method call as follows (the example shows two equivalent calls; when there are no method arguments, you can leave off the ()):

obj.foo.bar obj.foo().bar()

The result of calling obj.foo will be some object, and whatever the class of this new object is, you would attempt to call method bar on it.

As another example, suppose you want to call the method name on each object in a collection. One element in this collection happens to be of an instance of class MyClass2 that does not have a method name defined. You will get a runtime error when you first try applying method name to this object. You can fix this by dynamically adding the method as follows:

class MyClass2 def name "MyClass2: #{this}" end end

Developers who are used to a strongly type checked language like Java likely will expect this "unsafe" flexibility to make their programs less reliable because the compiler or interpreter is not statically checking all type uses. However, any program bugs due to runtime type checking will be found quickly in testing, so there is no decrease in software reliability. Yet you get the benefits of a more flexible language: shorter programs and shorter development time.

Dealing with Missing Methods
Still skeptical about duck typing? Hang on, because now you are going to see another Ruby trick: how to handle missing methods for any Ruby class, starting with this simple example that applies two methods to a string object, one that is defined (length) and one that is undefined (foobar):

markw$ irb >> s = "this is a string" => "this is a string" >> s.length => 16 >> s.foobar NoMethodError: undefined method `foobar' for "this is a string":String from (irb):3

You'll see an error thrown for the undefined method. So "patch" the String class by writing your own method_missing method:

>> class String >> def method_missing(method_name, *arguments) >> puts "Missing #{method_name} (#{arguments.join(', ')})" >> end >> end => nil >> s.foobar Missing foobar () => nil >> s.foobar(1, "cat") Missing foobar (1, cat) => nil >>

Whenever the Ruby runtime system cannot find a method for an object, it calls the method method_missing that is initially inherited and simply raises a NoMethodError exception. This example overrode this inherited method with one that does not throw an error, and it prints out the name and arguments of the method call. Now, redefine this method again, this time checking to see if the method name (after converting it to a string with to_s) is equal to foobar:

>> class String >> def method_missing(method_name, *arguments) >> if method_name.to_s=='foobar' >> arguments.to_s.reverse # return a value >> else ?> raise NoMethodError, "You need to define #{method_name}" >> end >> end >> end => nil >> s.foobar(1, "cat") => "tac1" >> s.foobar_it(1, "cat") NoMethodError: You need to define foobar_it from (irb):38:in `method_missing' from (irb):43 from :0 >>

If the method name is equal to foobar, this example calculates a return value. Otherwise, it throws an error.

Thanks for your registration, follow us on our social networks to keep up-to-date