CSC/ECE 517 Fall 2011/ch1 2c rs
Here we discuss about interfaces in Java, mixins in Ruby and compare some of the functionalities offered by mixins in Ruby and the corresponding behaviors if exhibited by the interfaces.
Interfaces in Java
An interface in java is a collection of related methods with empty bodies, constant declarations ,nested types. It is declared using a key word ‘interface’. Constants are implicitly static and final. The methods are implicitly public, an interface cannot be instantiated as it is incomplete ie the methods are only declared but not defined. It can only be extended by other interfaces or implemented by classes. An interface can extend any number of interfaces.
interface <interface name> { <constants> <method declarations> }
A variable whose declared type is an interface type can hold a reference to an object of a class (or its subclass) that has implemented this interface.
Contractual Obligation:
A class that implements an interface has to provide a definition for each method of the inferface or has to be declared as an abstract class if it fails to implement even one method specified in the interface. An error message is issued by the compiler if the class does not define all the methods of an interface it has agreed to define. Even unrelated classes can implement an interface.
Example of an Interface:
In the following example, we create an interface called 'Shape' with the methods 'draw' and 'displayArea'. A class 'Square' implements the interface 'Shape' by provided definitions for the methods 'draw' and 'displayArea'. In the main method we create an object of Square and call the methods. Note that a 'Shape' variable can be used to hold the reference to the object of 'Square'
interface Shape { void draw(); void displayArea(float a,float b); } class Square implements Shape { public void draw() { System.out.println("Drawing Square"); } public void displayArea(float a,float b) { System.out.println("Area is "+a*b); } } public class InfDemo { public static void main(String args[]) { Square s=new Square(); s.draw(); s.displayArea(5,5); } }
Output:
Drawing Square Area is 25.0
Modules in Ruby
A module in Ruby has the same implementation and is similar to a ruby class except for a few significant differences:
- Instance of a module cannot be created.
- It cannot be inherited by other classes but can be included.
- The syntax to define module is different.
Example: Consider a requirement where a person must bow to a good guy and hit the bad guy with a bow. The module GoodGuy implements a method bow and tell the caller to bow to the guy because he is a good guy. There is another module BadGuy which implements the same method bow but tells the caller to hit the guy with a bow because he is a bad guy.
Examples of Modules:
module GoodGuy def GoodGuy.bow puts "I bow to you. you are a good guy" end end module BadGuy def BadGuy.bow puts "I will hit you with a bow.you are a bad guy" end end require 'GoodGuy' #require is used to load and execute the code once. require 'BadGuy' GoodGuy.bow BadGuy.bow
Mixins in Ruby
History of Mixins
Mixins are not new. Smalltalk supported them back in 1971.According to wikipedia, Mixins first appeared in the Symbolics' object-oriented Flavors system (developed by Howard Cannon), which was an approach to object-orientation used in Lisp Machine Lisp. The name was inspired by Steve's Ice Cream Parlor in Somerville, Massachusetts The ice cream shop owner offered a basic flavor of ice cream (vanilla, chocolate, etc.) and blended in a combination of extra items (nuts, cookies, fudge, etc.) and called the item a "Mix-in", his own trademarked term at the time .
Mixins
Mixins are used to make certain functionality available to a class. Lets assume that the two modules in the above examples are classes. Ruby is single-inherited,so the same functionality as above cannot be implemented through a class. Because to do so, we need to extend both the GoodGuy class and the BadGuy class which is not possible. Through modules, Ruby provides the excellent feature of multiple inheritance. Any functionality of any module can be imported into our class. Thus, the features of the module gets “mixed-in” with our class.
A class cannot inherit a module but can use the functionality of it by loading it into its definition using the ‘require’ keyword. Then, we can call all the functions in this module as if they belong to our class. If there are two modules having the same method and both modules are required by our class, the name conflict is resolved by using scope resolution operator (::)
The methods of the module do not belong to the class requiring it. In order to make a modules’ method the instance methods of our class, we have to use the include keyword instead of require. However, to include a module which is in a separate file, we have to use both the keywords require and include. Even now, it does not mean that these methods are copied into the class definition. It just references the module’s method from our class. Thus, any modifications made to the method definition in the module even at run time are reflected in the class.
Example of Mixins:
class Actnow require 'GoodGuy' require 'BadGuy' def Act(kind) if(kind=='good') GoodGuy.bow end if (kind =='bad') BadGuy.bow end end end myobj=Actnow.new myobj.Act('good') myobj.Act('bad')
Some Pre-defined mixin modules
Ruby has the following built into modules: Comparable, Enumerable, FileTest, GC, Kernel, Math, ObjectSpace, Preci-sion, Process, Signal
Comparable is a mixin module which permits the including class to implement comparison operators. The including class must define the <=> operator, which compares the receiver against another object, returning -1, 0, or +1 depending on whether the receiver is less than, equal to, or greater than the other object. Comparable uses <=> to implement the conventional comparison operators (<, <=, ==, >=, and >) and the method between?.
Enumerable is a mix-in module for enumeration. The including class must provide the method each.
FileTest is a module containing file test functions; its methods can also be accessed from the File class. The GC module provides an interface to Ruby’s mark and sweep garbage collection mechanism. Some of the underlying methods are also available via the ObjectSpace module. Kernel is a module included by the Object class; it defines Ruby’s ‘built-in’ methods.
Math is a module containing module functions for basic trigonometric and transcendental functions.
ObjectSpace is a module which contains routines that interact with the garbage collection facility and allows traversing all living objects with an iterator. Precision is a mixin for concrete numeric classes with precision
Comparable Behavior
The comparable functionality is useful when there is a requirement to compare few objects and maybe even sort them.
In Ruby the comparable behavior is achieved by simply defining the <=>operator(which returns -1,0,1 depending on whether the argument object is greater than, equal to or less-than the calling object) and including the Comparable mixin.
Example of Comparable in Ruby:
class Org include Comparable attr :name attr :revenue attr :emplCount def initialize(name,revenue,emplCount) @name = name @revenue=revenue @emplCount=emplCount end def <=>(second) self.revenue <=> second.revenue end def to_s "#{name}" end end org1=Org.new('org1',100000,5000); org2=Org.new('org2',100001,4000); org3=Org.new('org3',100002,4000); org4=Org.new('org4',100003,4000); org5=Org.new('org5',100004,4000); a=[org1,org2,org3,org4,org5]; puts a.sort
output:
org1 org2 org3 org4 org5
In Java, there is an interface called Comparable which declares an abstract method called CompareTo. Several pre-defined classes such as Float,Double,Integer,Long implement this interface and provide a definition for the CompareTo method. If we have to compare two objects of our class by comparing a specific attribute of the objects, we need to implement the interface in our class and provide the implementation of the CompareTo method by writing our code in there to compare the two objects of that class. Consider a situation where we have a class Organization and this Organization stores the information about Organizations. Suppose we have to sort different organizations as to which is greater by comparing the total revenue of each. The implementation in Java is as follows.
Example of Comparable in Java:
import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; //import java.util.*; public class Org implements Comparable { String name; Integer revenue; int emplCount; public Org(String name,Integer revenue, int emplCount) { this.name=name; this.revenue=revenue; this.emplCount=emplCount; } public int compareTo(Object obj1) { if (this.revenue == ((Org) obj1).revenue) return 0; else if ((this.revenue) > ((Org) obj1).revenue) return 1; else return -1; } public String toString() { return "Org " + name + "\n" ; } public static void main(String[] args) { List list1 = new ArrayList(); Org org1=new Org("org1",1000000,5000); Org org2=new Org("org2",1000001,4000); Org org3=new Org("org3",1000002,4000); Org org4=new Org("org4",1000003,4000); Org org5=new Org("org5",1000004,4000); Org org6=new Org("org6",1000005,4000); list1.add(org1); list1.add(org2); list1.add(org3); list1.add(org4); list1.add(org5); list1.add(org6); Collections.sort(list1); Iterator itr = list1.iterator(); System.out.println("The list of organizations in the ascending order of revenue are"); while(itr.hasNext()){ Object element = itr.next(); System.out.println(element + "\n"); } } }
Output:
The list of organizations in the ascending order of revenue are Org org1 Org org2 Org org3 Org org4 Org org5 Org org6
Enumerable Behavior
Enumerable module
Various operations are supported by the Ruby Collection classes .Some of such operations are traversing the collection, sorting the collection. We can define classes that can support these features on collections by including the enumerable module and defining an iterator ‘each’. This iterator has to return the elements of the collection in turn.
If the classes which have included the Enumerable module can implement the rocket method <=>, we can also use other methods like min, max ,sort on the collections.
Enumerable is a standard mixin implementing operators in terms of the ‘each’ method defined the host class. The host class is that class which includes the enumerable.
Usage of Enumerable
Ruby’s enumerable module has methods for all kinds of operations that can be performed on a collection. Collection objects which can be instances of Array,Hash etc. “mixin” the enumerable module.It gives objects of collections additional collection specific behaviors. These behaviors are given by the each method.
Following is the list of methods provided by the Enumerable mixin.
all? ; any? ; chunk ; collect ; collect_concat; count; cycle; detect; drop; drop_while ; each_cons ; each_entry ; each_slice; each_with_index; each_with_object ; entries ; find ; find_all ; find_index ; first ; flat_map ; grep ; group_by ; include? ; inject ; map ; max ; max_by ; member? ; min ; min_by ; minmax; minmax_by; none? ; one?; partition ; reduce; reject ; reverse_each ; select; slice_before; sort; sort_by ; take ; take_while; to_a ; zip
To Mix in Enumerable in a class,
Class MyCollection include Enumerable #other code def each #definiton end #othercode end
Some of the built in classes which mixin Enumerable are : String, Hash ,Array ,Range ,Struct. Each class that includes ‘Enumerable’ must define the ‘each’ method as per its own requirement.
eg: the Array class ‘s each method yields each element.The Hash class‘s each yields each key-value pair as a two element array.
Some Useful Methods offered by Enumerable:
- map: modifies each member according to the instructions in a block and returns the modified collection of members.
- collect: similar to map.
- grep: The grep method ‘searches’ for members using a regular expression
eg:
(1..10).grep (5..7) #=>[5,6,7]
- all? : It returns true if all elements of a collection satisfy the condition in the block ie the block never returns false or nil. If no block is specified it returns true if none of the collection members are false or nil.
eg:
%w{ant bear cat}.all? {|word| word.length >= 3} #=> true %w{ant bear cat}.all? {|word| word.length >= 4} #=> false
- any?
Passes each element of the collection to the given block. The method returns true if the block ever returns a value other than false or nil.
eg:
%w{ant bear cat}.any? {|word| word.length >= 3} #=> true %w{ant bear cat}.any? {|word| word.length >= 4} #=> true
One of the common and useful methods of enumerable is ‘inject’. We can use it in any class that includes enumerable and provides the implemation for ‘each’ method. This method applies a function or operation to the first two elements in the
collection and then applies the operation to the result of this computation and to the third
element, and so on, until all elements in the collection have been used.
Example of Enumerable
class EnumerableDemo include Enumerable def initialize(string) @string=string end def each @string.scan(/\d/) do |num| yield num end end ed=EnumerableDemo.new("123Bond007") puts ed.inject(:+)
output:
123007 #The numbers in a string are concatinated and returned.
In Java, the Collection interface specifies some methods similar to the methods of Enumerable module. For example contains can be mapped to find,to_array can be mapped to collect. etc. But the methods are also not as powerful as those of the Enumerable module methods. Also the implementation of these methods is not available unless we inherit from a class which implements this interface. This is unlike mixins in ruby where implementation of ‘each’ method provides us several useful collection methods for free.
Enumerable Interface in Java.
Java provides the Enumeration Interface. But its functionality is different from the Enumerable module of ruby.In Java, the Enumeration interface defines the methods by which you can enumerate (obtain one at a time) the elements in a collection of objects.
Successive calls to the nextElement method return successive elements of the series.
For example, to print all elements of a vector v:
for (Enumeration e = v.elements() ; e.hasMoreElements() ;) { System.out.println(e.nextElement()); }
hasMoreElements: Tests if this enumeration contains more elements.
nextElement: the next element of this enumeration.
Data Mapper
In any software development, we often face situations where our code has to interact with a database. In such situations, we have to have knowledge of a query language like SQL to insert into, delete from or modify a database. In modern programming languages, a feature called Object Relational Mapping is provided. This features allow the user to access the database tuples as if they were objects. All the database operations such as insert, delete,update,etc. are implemented in the language using objects. The programmer need not have a firsthand knowledge of a query language to perform these operations.
In Ruby, Object Relational Mapping is implemented using DataMapper. The DataMapper provides wide variety of features and is thread-safe(multiple threads can call it without interfering with each other.
Following are the steps involved in using the DataMapper
Step 1: Install the dm-core ruby gem – the core of the DataMapper library. This gem has no external dependencies and so, we can install it in the same way we install other gems in ruby.
$sudo gem install dm-core
Step 2: We now need to install an adapter which allows the DataMapper to talk to the database. This is specific to each database provider. '
Eg: For SQLite 3
$ sudo apt-get install libsqlite3-dev $ sudo gem install dm-sqlite-adapter
Step 3: We then need to require the dm-core gem in our application.
Require ‘rubygems’ Require’data_mapper’ Require ‘dm-core’
Now, we have to specify the database connection to which our DataMapper must talk to. This is done using datamapper.setup
DataMapper.setup(:default, “[dataobject]://[relative-path]”) For SQLite, this would be something like this. DataMapper.setup( :default, "sqlite3://#databases/myown.db" )
Step-4 – Define models in a class using DataMapper:
The models can be created as below
# Create and define a class Recipee class Recipee include DataMapper::Resource property :Name, String: key => true property :type, String property :Description, text end
This model can be called using the DataMapper.auto_migrate command. This creates the table if it does not already exist. If the table already exists, it modifies the columns in this table. We can specify primary key by using the key=> true. The serial type is an auto increment integer key. We can create a column ID and define its type as serial to make it a key automatically. Now, we can access these as if they were objects without having knowledge about any query language to insert and update a table. the code
# Create a new record myrecipee = Recipee.new myrecipee.attributes = { :name => 'OrangeJuice', :type => 'beverage', :Description => 'Tasty!' } Insert: myrecipee.save to save Modify: myrecipee.Description=’Tasty and Delicious!’ Delete: Myrecipee.destroy to deletethe tuple in the database Select: puts myrecipee.inspect
DataMapper in Java
In java, Hibernate, iBatis are modern approaches that provide the ORM functionality. Traditionally, JDBC had to be used to access the databases.The functionalities provided by Hibernate are similar to that of DataMapper in ruby- it can access the database as objects.
Hibernate defines a language called HQL(Hybernate Query Language). HQL can be said to be the object oriented version of SQL. Java was created in 1995, but hibernate did not come into existence until 2001. Hibernate was developed by Redhat in Java to introduce ORM in Java.
Singleton Behavior
According to Wikipedia ,” In software engineering, the singleton pattern is a design pattern that is used to restrict instantiation of a class to one object. (This concept is also sometimes generalized to restrict the instance to a specific number of objects . This is useful when exactly one object is needed to coordinate actions across the system.”
The singleton design pattern is used when we desire only one instance of some class, such as one database connection, one logger instance or even one configuration object for an application.
In Ruby, the singleton behavior can be achieved by simply including the ‘Singleton’ Module.
To use ruby singleton module,
- ’require’ the ‘Singleton’ and then include it in desired class.
- Use the instance method to get the instance you need.
Ruby does the following when a singleton module is included in a class.
- New method is made private so that it can’t be used for instantiation.
- A class method called ‘instance’ is added that instantiates only one instance of the class.
Eg
class A include Singleton # ... end
this ensures that only one instance of A be created.
a,b = A.instance, A.instance a == b # => true A.new # NoMethodError - new is private ...
Instance is created at the first call of A.instance(), thus this behavior is preserved under inheritance and cloning.This is achieved by marking A.new as private nd providing (or modifying) the class methods A.inherited() and A.clone() - to ensure that the Singletonpattern is properly inherited and cloned.
In java, the singleton design pattern proposes that at any time there can be a single instance of an object created by JVM. To implement this behavior, the class’s default constructor is made private. This prevents the direct instantiation of the object. A static modifier is applied to the instance method that returns the object as it then makes this method a class level method that can be accessed without creating an object.
For implementing a singleton pattern, consider the following steps:
Step -1: Provide a default private constructor.
Step-2: Define a method to obtain the reference to the singleton Object.
Step 3: The Access method has to be made synchronized to prevent Thread Problems.
Step 4: The Object clone method has to be overridden to prevent cloning.
Example of Singleton:
class SingletonClass { private static SingletonClass singletonObject; /** A private Constructor prevents any other class from instantiating. */ private SingletonClass() { // Optional Code } public static synchronized SingletonClass getSingletonObject() { if (singletonObject == null) { singletonObject = new SingletonClass(); } return singletonObject; } public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } } public class SingletonObjectDemo { public static void main(String args[]) { // SingletonClass obj = new SingletonClass(); //Compilation error not allowed SingletonClass obj = SingletonClass.getSingletonObject(); // Your Business Logic System.out.println("Singleton object obtained"); } }
Mixin vs Interfaces
- What makes mixins so powerful is that the methods of the host class(the class that includes the module) can be accessed in the module even before we define the host class.
Example:
module Wisher def wish puts "Good Day "+self.name #name ie attr_reader method of the host class is used even before the class is define. end end class Person include Wisher def initialize(name,age) @name=name @age=age end attr_reader :name end p=Person.new (“James”,4) p.wish #returns Good Day James.
Such a feature is not supported by interfaces in java.
- Rewriting : When an interface is rewritten, all classes that implemented the older version are now broken because they no longer implement the interface. Hence the programmer has to try to anticipate all uses for the interface he/she is defining and specify it completely from the beginning. Such a problem is not caused in Ruby. Even if the module definition is changed at run-time, the classes that include the module use the modified version of the module.
- Both Java and Ruby support single inheritance.ie A class can inherit features from a single class. Multiple inheritance is achieved in Java through interfaces and in Ruby through Mixins. ie A java class can extend only one class but can implement several interfaces. Hence objects can have multiple types ie the type of their own class and the type of the interfaces that their class Similarly a Ruby class can be subclassed from a single class but can include many modules.(mixins). In Ruby, inheritance and mixins allow us to write code at one place and reuse it in other classes. Inheritance is used when there is an “is-a” relationship. Mixins are used when there is a “uses a” or “has a” relationship. However there is no such advantage with interfaces in java . Hence there can be misuse of inheritance as even unrelated classes can implement an interface.
- One analogy that can be used to compare interfaces in java and mixins in ruby is that interface is like a legal contract while mixin is like a promise. ie a java interface is all about meeting the rules of the extra methods that must be provided where as in ruby there are no such rules to be enforced. Consider the comparable behavior for example. Both mixin and the interface provide similar behavior. But if a class extends Comparable interface but fails to implement the compareTo method a compile time error occurs even if the object of the class does not attempt to use the comparable behavior. But in cases of mixins, if a class includes ‘Comparable’ mixin and does not implement the <=> method there are no errors if the object of the class does not attempt to use the comparable behavior. Hence we can think of it as a promise. If the object uses the comparable behavior ie calls methods like >,<,between? Etc then an runtime error occurs.
eg:
class A include Comparable def hi puts "hi" end end a=A.new a.hi #returns “hi”.
- Also classes implementing interfaces do not inherit code; it is purely something to help more programs type-check in a statically typed language whereas mixins provide actual code to classes that include them. Hence mixins allow code reusability.
Conclusion
Some of the functionality of mixins is provided by interfaces in Java. However, an interface only specifies what the class must support and cannot provide an implementation. Another class, providing an implementation and dependent with the interface, is needed for refactoring common behavior into a single place.Interfaces combined with aspect-oriented programming can produce full fledged mixins in languages that support such features, such as C# or Java. Additionally, through the use of the marker interface pattern, generic programming, and extension methods interfaces may match the power of mixins.
References:
http://ruby.about.com/od/sinatra/a/datamapper.htm .
http://solitude.vkps.co.uk/Archives/2009/01/13/data-mappers/
http://javatemple.blogspot.com/2008/11/features-of-hibernate-in-nutshell.html
http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Comparable.html
http://www.tutorialspoint.com/ruby/ruby_modules.htm
http://www.javabeginner.com/learn-java/java-singleton-design-pattern
http://www.brainbell.com/tutorials/java/Applying_Some_Structure.htm
http://ruby-doc.org/
http://download.oracle.com/javase/tutorial
http://en.wikipedia.org/wiki/Mixin
http://en.wikipedia.org/wiki/Singleton_pattern