CSC/ECE 517 Fall 2011/ch1 2c bs: Difference between revisions
(8 intermediate revisions by 2 users not shown) | |||
Line 2: | Line 2: | ||
An [http://en.wikipedia.org/wiki/Interface_(computing) interface] in the [http://en.wikipedia.org/wiki/Java_(programming_language) Java] programming language is an abstract type that is used to specify an interface that classes must implement. Interface may only contain [http://en.wikipedia.org/wiki/Method_signature method signature] and constant declarations. An interface may never contain method definitions. Interfaces cannot be instantiated. A class that implements an interface must implement all of the methods described in the interface, or be an [http://en.wikipedia.org/wiki/Abstract_type abstract] class. Object references in Java may be specified to be of an interface type; in which case, they must either be null, or be bound to an object that implements the interface. | An [http://en.wikipedia.org/wiki/Interface_(computing) interface] in the [http://en.wikipedia.org/wiki/Java_(programming_language) Java] programming language is an abstract type that is used to specify an interface that classes must implement. Interface may only contain [http://en.wikipedia.org/wiki/Method_signature method signature] and constant declarations. An interface may never contain method definitions. Interfaces cannot be instantiated. A class that implements an interface must implement all of the methods described in the interface, or be an [http://en.wikipedia.org/wiki/Abstract_type abstract] class. Object references in Java may be specified to be of an interface type; in which case, they must either be null, or be bound to an object that implements the interface. | ||
In object-oriented programming languages, a [http://en.wikipedia.org/wiki/Mixin mixin] is a class that provides a certain functionality to be inherited or just reused by a subclass. Some of the functionality of mixins is provided by interfaces in popular languages like Java and C#. 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. | In object-oriented programming languages, a [http://en.wikipedia.org/wiki/Mixin mixin] is a class that provides a certain functionality to be inherited or just reused by a subclass. Some of the functionality of mixins is provided by interfaces in popular languages like Java and [http://en.wikipedia.org/wiki/C_Sharp_(programming_language) C#]. 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. | ||
One benefit of using interfaces is that they simulate [http://en.wikipedia.org/wiki/Multiple_inheritance multiple inheritance]. All classes in Java other than [https://matrix.senecac.on.ca:8443/wiki/javaSE/index.php/Java.lang.Object java.lang.Object], must have exactly one base class; multiple inheritance of classes is not allowed. | One benefit of using interfaces is that they simulate [http://en.wikipedia.org/wiki/Multiple_inheritance multiple inheritance]. All classes in Java other than [https://matrix.senecac.on.ca:8443/wiki/javaSE/index.php/Java.lang.Object java.lang.Object], must have exactly one base class; multiple inheritance of classes is not allowed. | ||
==Overview== | ==Overview== | ||
===Mixins in Ruby=== | ===Mixins in Ruby=== | ||
In Java you just have classes (both abstract and concrete) and interfaces. The Ruby language provides classes, modules, and a mix of both. Inheriting from a mixin is not a form of specialization but is rather a means of collecting functionality. A class may inherit most or all of its functionality from one or more mixins through multiple inheritance. A mixin can also be viewed as an interface with implemented methods. When a class includes a mixin, the class implements the interface and includes, rather than inherits, all the mixins’ attributes (fields, properties) and methods. They become part of the class during compilation. A mixin can defer definition and binding of methods until runtime, though attributes and instantiation parameters are still defined at compile time. In the Ruby language a mixin is a class that is mixed with a module. | In Java you just have [http://en.wikipedia.org/wiki/Class_(computer_programming) classes] (both abstract and concrete) and interfaces. The [http://en.wikipedia.org/wiki/Ruby Ruby] language provides classes,[http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_modules.html modules], and a mix of both. Inheriting from a mixin is not a form of specialization but is rather a means of collecting functionality. A class may inherit most or all of its functionality from one or more mixins through multiple inheritance. A mixin can also be viewed as an interface with implemented methods. When a class includes a mixin, the class implements the interface and includes, rather than inherits, all the mixins’ attributes (fields, properties) and methods. They become part of the class during compilation. A mixin can defer definition and binding of methods until runtime, though attributes and instantiation parameters are still defined at compile time. In the Ruby language a mixin is a class that is mixed with a module. | ||
====Module==== | ====Module==== | ||
A module is a degenerate abstract class. A module can’t be instantiated and no class can directly extend it but it can fully implement methods. A class can leverage the implementation of a module by including the module’s methods. A module can define methods that can be shared in different and separate classes either at the class or instance level. | A [http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_modules.html module] is a degenerate abstract class. A module can’t be instantiated and no class can directly extend it but it can fully implement methods. A class can leverage the implementation of a module by including the module’s methods. A module can define methods that can be shared in different and separate classes either at the class or instance level. We can view an example module that converts a numeric value to its English word. | ||
# Convert a integer value to English. | # Convert a integer value to English. | ||
Line 29: | Line 28: | ||
end | end | ||
The Stringify module above makes use of a @value instance variable. The class that will be mixed with this module needs to define and set a @value instance variable since the Stringify module uses it but does not define it. In addition to instance variables a module could invoke methods not defined in the module but in the class that it will be mixed with. | The Stringify module above makes use of a @value [http://en.wikipedia.org/wiki/Instance_variable instance variable]. The class that will be mixed with this module needs to define and set a @value instance variable since the Stringify module uses it but does not define it. In addition to instance variables a module could invoke methods not defined in the module but in the class that it will be mixed with. | ||
Line 43: | Line 42: | ||
The methods in the Math module are intended to be invoked like class methods, also known as static methods. The add method in the Math module accepts two integer values and returns an instance of BigInteger. | The methods in the Math module are intended to be invoked like class methods, also known as [http://en.wikipedia.org/wiki/Method_(computer_programming)#Static_methods static] methods. The add method in the Math module accepts two integer values and returns an [http://en.wikipedia.org/wiki/Instance_(computer_science) instance] of BigInteger. | ||
====Using Mixins==== | ====Using Mixins==== | ||
Implementation of the class and module are joined, | Implementation of the class and module are joined, interwined, combined, etc. A mixin is a different mechanism to the extend construct used to add concrete implementation to a class. With a mixin you can extend from a module instead of a class. | ||
This is the implementation of BigInteger class. The BigInteger class defines one constructor and directly inherits one method from the Number base class. To mix in the methods implemented in the Stringify and Math modules with the BigInteger class you will note the usage of the include and extend methods, respectively. | This is the implementation of BigInteger class. The BigInteger class defines one constructor and directly inherits one method from the Number base class. To mix in the methods implemented in the Stringify and Math modules with the BigInteger class you will note the usage of the include and extend methods, respectively. | ||
Line 111: | Line 110: | ||
puts bigint1.format # will generate an error | puts bigint1.format # will generate an error | ||
Modules that will be mixed with a class via the include or extend method could define something like a | Modules that will be mixed with a class via the include or extend method could define something like a constructor or initializer method to the module. The module initializer method will be invoked at the time the module is mixed with a class. When a class extends a module the module’s self.extended method will be invoked: | ||
module Math | module Math | ||
Line 197: | Line 196: | ||
==Mixins vs Interfaces== | ==Mixins vs Interfaces== | ||
Because of this mixin feature, a developer can add arbitrary methods and modify behavior of core classes at runtime. This is amazingly powerful if you are trying to write plugins and extensions to the framework. Because you can add functionality to existing objects, users can install | Because of this mixin feature, a developer can add arbitrary methods and modify behavior of core classes at runtime. This is amazingly powerful if you are trying to write plugins and extensions to the [http://en.wikipedia.org/wiki/Software_framework framework]. Because you can add functionality to existing objects, users can install their [http://en.wikipedia.org/wiki/Plug-in_(computing) plugin] and start taking advantage of new functionality without having to make changes to the objects that they are instantiating in their application. | ||
In frameworks written in other languages, such as Java, plugging in new functionality means that you need to change how your objects are instantiated. This will require code changes and/or potentially configuration changes which makes it hard to develop, hard to maintain, and a pain for plugin developers to support. But because of the mixin feature, Rails plugin developers can customize the base objects and the users of the plugins do not have to change any of their code or configuration logic. | In frameworks written in other languages, such as Java, plugging in new functionality means that you need to change how your objects are instantiated. This will require code changes and/or potentially configuration changes which makes it hard to develop, hard to maintain, and a pain for plugin developers to support. But because of the mixin feature, Rails plugin developers can customize the base objects and the users of the plugins do not have to change any of their code or configuration logic. | ||
=== | ===Differences=== | ||
These is a general comparision: | These is a general comparision: | ||
Line 239: | Line 238: | ||
|} | |} | ||
===Comparable Functionality=== | ===Functionality and Behavior Comparison=== | ||
The functionality and behavior of Mixins in Ruby is compared with Interfaces in Java | |||
====Comparable Functionality==== | |||
Sometime we are required to compare the class members of different objects of the same class and/or sort them. This is the comparable functionality that we are trying to achieve for a given class. This functionality can be achieved by both the Ruby using mixins and Java using interfaces. There is not much difference using both. | Sometime we are required to compare the class members of different objects of the same class and/or sort them. This is the comparable functionality that we are trying to achieve for a given class. This functionality can be achieved by both the Ruby using mixins and Java using interfaces. There is not much difference using both. | ||
'''Ruby''' | '''Ruby''' | ||
The Comparable mixin is used by classes whose objects may be ordered. The 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?. | The [http://www.ruby-doc.org/core/classes/Comparable.html Comparable] mixin is used by classes whose objects may be ordered. The 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?. | ||
class SizeMatters | class SizeMatters | ||
Line 277: | Line 279: | ||
'''Java''' | '''Java''' | ||
In | In Java, comparable functionality is achieved by extending the “Comparable” interface. List of objects that implement this interface can be sorted automatically by sort method of the list interface. This interface has compareTo() method that is used by the sort() method of the list. Here compareTo() method can also be used to compare two objects with respect to the implementation in compareTo() implementation in the derived class. It returns ‘0’ , ‘1’ and ‘-1’ corresponding to whether one is equal to , greater than or lesser than other. | ||
In this example code Employee class is implementing Comparable interface and have method compareTo(). | In this example code Employee class is implementing Comparable interface and have method compareTo(). | ||
public class Employee implements Comparable { | public class Employee implements Comparable { | ||
Line 341: | Line 343: | ||
Sal 70000.0 | Sal 70000.0 | ||
===Singleton Behaviour=== | ====Singleton Behaviour==== | ||
A Singleton is a class guaranteed to have only a single instance, with a single global access point to that instance. It can be implemented in Ruby and Java. In Ruby we can include a module to acquire all the functionality of the singleton module. The code is already there and we are just reusing the code and adding that similar functionality into our class. Here our intention is to add the functionality of singleton to the class which is achieved using mixins. In java, implementation of interfaces means that the class which implements the interface becomes a type of that class, which is not the intention here. So, there is not interface which class can implement to get the functionality in itself. It has to implement the functionality itself without implementing any interface. | A [http://en.wikipedia.org/wiki/Singleton_pattern Singleton] is a class guaranteed to have only a single instance, with a single global access point to that instance. It can be implemented in Ruby and Java. In Ruby we can include a module to acquire all the functionality of the singleton module. The code is already there and we are just reusing the code and adding that similar functionality into our class. Here our intention is to add the functionality of singleton to the class which is achieved using mixins. In java, implementation of interfaces means that the class which implements the interface becomes a type of that class, which is not the intention here. So, there is not interface which class can implement to get the functionality in itself. It has to implement the functionality itself without implementing any interface. | ||
'''Ruby''' | '''Ruby''' | ||
Line 370: | Line 372: | ||
AppConfig.new rescue(puts $!) #=> new method is private | AppConfig.new rescue(puts $!) #=> new method is private | ||
===Enumerable Behaviour=== | ====Enumerable Behaviour==== | ||
This enumerable functionality adds support to the array members of the class. We can achieve this functionality using mixins in Ruby while it is not possible to do it in Java using interfaces. | This [http://www.ruby-doc.org/core/classes/Enumerable.html enumerable] functionality adds support to the array members of the class. We can achieve this functionality using mixins in Ruby while it is not possible to do it in Java using interfaces. | ||
'''Implementation in Ruby:''' | '''Implementation in Ruby:''' | ||
Line 399: | Line 401: | ||
===Data Mapper=== | ====Data Mapper==== | ||
DataMapper is an API which comes with the ability to use the same API to talk to a multitude of different datastores. There are adapters for the usual RDBMS suspects, NoSQL stores, various file formats and even some popular webservices. This is implemented in ruby using mixins. We need not use interfaces to implement. | [http://datamapper.org/docs/ DataMapper] is an API which comes with the ability to use the same API to talk to a multitude of different datastores. There are adapters for the usual RDBMS suspects, NoSQL stores, various file formats and even some popular webservices. This is implemented in ruby using mixins. We need not use interfaces to implement. | ||
'''Implementation in Ruby:''' | '''Implementation in Ruby:''' | ||
Line 410: | Line 412: | ||
==Conclusion== | ==Conclusion== | ||
The point to take away from this is not that Ruby Mixins are more powerful than Java Interfaces. The mixin feature of Ruby allows for the development of easy to use but powerful plugins that will be hard for any non-Ruby based framework to compete with. Java has many other ways of implementing the | The point to take away from this is not that Ruby Mixins are more powerful than Java Interfaces. The mixin feature of Ruby allows for the development of easy to use but powerful plugins that will be hard for any non-Ruby based framework to compete with. Java has many other ways of implementing the functionality mixins are capable of. It is just that it does not use Interfaces to achieve the functionality. Even though both of them are a way of achieving multiple inheritance in their respective languages, they achieve quiet different goals. Inheritance in Java is mainly to overcome the confusion which arises with multiple inheritance, while Mixins in Ruby is mainly to add an additional functionality to the existing class apart from the ‘primary functionality’ of the class. | ||
When a class implements Interface, it indicates that it is of the type interface class and forms a hierarchy with the interface class, while ruby mixins are mainly intended for code reuse and including an additional functionality to the class. It does not form any hierarchy as it is only using module of the class. | When a class implements Interface, it indicates that it is of the type interface class and forms a hierarchy with the interface class, while ruby mixins are mainly intended for code reuse and including an additional functionality to the class. It does not form any hierarchy as it is only using module of the class. | ||
Line 417: | Line 420: | ||
* http://en.wikipedia.org/wiki/Interface_(Java) | * http://en.wikipedia.org/wiki/Interface_(Java) | ||
* http://carboni.ca/blog/p/Modules-How-Do-They-Work | * http://carboni.ca/blog/p/Modules-How-Do-They-Work | ||
* http://rubylearning.com/satishtalim/modules_mixins.html | * http://rubylearning.com/satishtalim/modules_mixins.html | ||
* http://www.innovationontherun.com/why-rubys-mixins-gives-rails-an-advantage-over-java- | * http://www.innovationontherun.com/why-rubys-mixins-gives-rails-an-advantage-over-java- |
Latest revision as of 00:23, 23 September 2011
Introduction
An interface in the Java programming language is an abstract type that is used to specify an interface that classes must implement. Interface may only contain method signature and constant declarations. An interface may never contain method definitions. Interfaces cannot be instantiated. A class that implements an interface must implement all of the methods described in the interface, or be an abstract class. Object references in Java may be specified to be of an interface type; in which case, they must either be null, or be bound to an object that implements the interface.
In object-oriented programming languages, a mixin is a class that provides a certain functionality to be inherited or just reused by a subclass. Some of the functionality of mixins is provided by interfaces in popular languages like Java and C#. 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. One benefit of using interfaces is that they simulate multiple inheritance. All classes in Java other than java.lang.Object, must have exactly one base class; multiple inheritance of classes is not allowed.
Overview
Mixins in Ruby
In Java you just have classes (both abstract and concrete) and interfaces. The Ruby language provides classes,modules, and a mix of both. Inheriting from a mixin is not a form of specialization but is rather a means of collecting functionality. A class may inherit most or all of its functionality from one or more mixins through multiple inheritance. A mixin can also be viewed as an interface with implemented methods. When a class includes a mixin, the class implements the interface and includes, rather than inherits, all the mixins’ attributes (fields, properties) and methods. They become part of the class during compilation. A mixin can defer definition and binding of methods until runtime, though attributes and instantiation parameters are still defined at compile time. In the Ruby language a mixin is a class that is mixed with a module.
Module
A module is a degenerate abstract class. A module can’t be instantiated and no class can directly extend it but it can fully implement methods. A class can leverage the implementation of a module by including the module’s methods. A module can define methods that can be shared in different and separate classes either at the class or instance level. We can view an example module that converts a numeric value to its English word.
# Convert a integer value to English. module Stringify # Requires an instance variable @value def stringify if @value == 1 "One" elsif @value == 2 "Two" elsif @value == 3 "Three" end end end
The Stringify module above makes use of a @value instance variable. The class that will be mixed with this module needs to define and set a @value instance variable since the Stringify module uses it but does not define it. In addition to instance variables a module could invoke methods not defined in the module but in the class that it will be mixed with.
Self Contained Module:
# A Math module akin to Java Math class. module Math # Could be called as a class, static, method def add(val_one, val_two) BigInteger.new(val_one + val_two) end end
The methods in the Math module are intended to be invoked like class methods, also known as static methods. The add method in the Math module accepts two integer values and returns an instance of BigInteger.
Using Mixins
Implementation of the class and module are joined, interwined, combined, etc. A mixin is a different mechanism to the extend construct used to add concrete implementation to a class. With a mixin you can extend from a module instead of a class.
This is the implementation of BigInteger class. The BigInteger class defines one constructor and directly inherits one method from the Number base class. To mix in the methods implemented in the Stringify and Math modules with the BigInteger class you will note the usage of the include and extend methods, respectively.
# Base Number class class Number def intValue @value end end # BigInteger extends Number class BigInteger < Number # Add instance methods from Stringify include Stringify # Add class methods from Math extend Math # Add a constructor with one parameter def initialize(value) @value = value end end
Using the class:
# Create a new object bigint1 = BigInteger.new(10) # Call a method inherited from the base class puts bigint1.intValue # --> 10
The extend method will mix a module’s methods at the class level. The method defined in the Math module can be used as a class/static method.
# Call class method extended from Math bigint2 = BigInteger.add(-2, 4) puts bigint2.intValue # --> 2
The include method will mix a module’s methods at the instance level, meaning that the methods will become instance methods. The method defined in the Stringify module can be used as an instance method.
# Call a method included from Stringify puts bigint2.stringify # --> 'Two'
There is another use of the extend method. You can enhance an object instance by mixing it with a module at run time. This ‘CurrencyFormatter’ is used to extend an object, changing it’s responsibilities at runtime.
# Format a numeric value as a currency module CurrencyFormatter def format "$#{@value}" end end
To mix an object instance with a module you can do the following:
# Add the module methods to # this object instance, only! bigint2.extend CurrencyFormatter puts bigint2.format # --> '$2'
Calling the extend method on an instance will only extend that one object; objects of the same class will not be extended with the new functionality.
puts bigint1.format # will generate an error
Modules that will be mixed with a class via the include or extend method could define something like a constructor or initializer method to the module. The module initializer method will be invoked at the time the module is mixed with a class. When a class extends a module the module’s self.extended method will be invoked:
module Math def self.extended(base) # Initialize module. end end
The self prefix indicates that the method is a static module level method. The base parameter in the static extended method will be either an instance object or class object of the class that extended the module depending whether you extend a object or class, respectively. When a class includes a module the module’s self.included method will be invoked.
module Stringify def self.included(base) # Initialize module. end end
The base parameter will be a class object for the class that includes the module. It is important to note that inside the included and extended initializer methods you can include and extend other modules.
module Stringify def self.included(base) base.extend SomeOtherModule end end
Interfaces in Java
Interfaces define a standardized set of commands that a class will obey. The commands are a set of methods that a class implements. The interface definition states the names of the methods and their return types and argument signatures. There is no executable body for any method. Example:
interface Bicycle { void changeCadence(int newValue); // wheel revolutions per minute void changeGear(int newValue); void speedUp(int increment); void applyBrakes(int decrement); }
Implementation is independent to each class that implements the interface. Once a class implements an interface, the Java compiler knows that an instance of the class will contain the specified set of methods. Therefore, it will allow you to call those methods for an object referenced by a variable whose type is the interface. Implementing an interface enables a class to be "plugged in" in any situation that requires a specific behavior (manifested through the set of methods).
class ACMEBicycle implements Bicycle { //implementation specific to this class int cadence = 0; int speed = 0; int gear = 1; void changeCadence(int newValue) { cadence = newValue; } void changeGear(int newValue) { gear = newValue; } void speedUp(int increment) { speed = speed + increment; } void applyBrakes(int decrement) { speed = speed - decrement; } void printStates() { System.out.println("cadence:"+cadence+" speed:"+speed+" gear:"+gear); } }
class MOUNTAINBicycle implements Bicycle { int cadence = 2; int speed = 3; int gear = 5; void changeCadence(int newValue) { cadence = newValue + 10; } void changeGear(int newValue) { gear = newValue + 4; } void speedUp(int increment) { speed = speed + increment + 10; } void applyBrakes(int decrement) { speed = speed – decrement – 10; } void printStates() { System.out.println("cadence:"+cadence+" speed:"+speed+" gear:"+gear); } }
Using an interface rather than inheritance to specify a certain set of methods allows a class to inherit from some other class. In other words, if a class needs two different sets of methods, so it can behave like two different types of things, it could inherit one set from class A, and use an interface B to specify the other. You could then reference one of these objects with either an A reference or a B reference. Implementing an interface allows a class to become more formal about the behavior it promises to provide. Interfaces form a contract between the class and the outside world, and this contract is enforced at build time by the compiler. If your class claims to implement an interface, all methods defined by that interface must appear in its source code before the class will successfully compile.
Mixins vs Interfaces
Because of this mixin feature, a developer can add arbitrary methods and modify behavior of core classes at runtime. This is amazingly powerful if you are trying to write plugins and extensions to the framework. Because you can add functionality to existing objects, users can install their plugin and start taking advantage of new functionality without having to make changes to the objects that they are instantiating in their application.
In frameworks written in other languages, such as Java, plugging in new functionality means that you need to change how your objects are instantiated. This will require code changes and/or potentially configuration changes which makes it hard to develop, hard to maintain, and a pain for plugin developers to support. But because of the mixin feature, Rails plugin developers can customize the base objects and the users of the plugins do not have to change any of their code or configuration logic.
Differences
These is a general comparision:
Mixins in Ruby | Interfaces in Java |
---|---|
'include' or 'extend' keywords used to include the module in the class. | 'implement' keyword is used to implement interface |
Need not implement the module methods in the class. | Should implement the interface methods. |
The methods are not copied into the class in which they are included. They are referenced. | The methods’ implementation is in the class itself. |
The included method definition is decided at ‘run time’. If the definition changes while running the function points to the changed code. | The definition is known compile time and will not change until the code is compiled and run again. |
Modules inclusion does not provide a superclass and subclass relationship. | Interface extending provides a superclass and subclass relationship. |
When we use mixins we included only a module of the class. | We include the entire interface class. |
Mainly for code reuse and does not provide any hierarchy. | It provides a hierarchy. |
Functionality and Behavior Comparison
The functionality and behavior of Mixins in Ruby is compared with Interfaces in Java
Comparable Functionality
Sometime we are required to compare the class members of different objects of the same class and/or sort them. This is the comparable functionality that we are trying to achieve for a given class. This functionality can be achieved by both the Ruby using mixins and Java using interfaces. There is not much difference using both.
Ruby
The Comparable mixin is used by classes whose objects may be ordered. The 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?.
class SizeMatters include Comparable attr :str def <=>(anOther) str.size <=> anOther.str.size end def initialize(str) @str = str end def inspect @str end end
using class:
s1 = SizeMatters.new("Z") s2 = SizeMatters.new("YY") s3 = SizeMatters.new("XXX") s4 = SizeMatters.new("WWWW") s5 = SizeMatters.new("VVVVV")
output:
s1 < s2 #=> true s4.between?(s1, s3) #=> false s4.between?(s3, s5) #=> true [ s3, s2, s5, s4, s1 ].sort #=> [Z, YY, XXX, WWWW, VVVVV]
Java
In Java, comparable functionality is achieved by extending the “Comparable” interface. List of objects that implement this interface can be sorted automatically by sort method of the list interface. This interface has compareTo() method that is used by the sort() method of the list. Here compareTo() method can also be used to compare two objects with respect to the implementation in compareTo() implementation in the derived class. It returns ‘0’ , ‘1’ and ‘-1’ corresponding to whether one is equal to , greater than or lesser than other. In this example code Employee class is implementing Comparable interface and have method compareTo().
public class Employee implements Comparable { int EmpID; String Ename; double Sal; static int i; public Employee() { EmpID = i++; Ename = "dont know"; Sal = 0.0; } public Employee(String ename, double sal) { EmpID = i++; Ename = ename; Sal = sal; } public String toString() { return "EmpID " + EmpID + "\n" + "Ename " + Ename + "\n" + "Sal" + Sal; } public int compareTo(Object o1) { if (this.Sal == ((Employee) o1).Sal) return 0; else if ((this.Sal) > ((Employee) o1).Sal) return 1; else return -1; } }
ComparableDemo.java is showing the use of this interface. This class first makes a list of objects of type Employee and call sort method of java.util.Collections, which internally uses compareTo() method of Employee class and sort the list accordingly.
import java.util.*; public class ComparableDemo{ public static void main(String[] args) { List ts1 = new ArrayList(); ts1.add(new Employee ("Tom",40000.00)); ts1.add(new Employee ("Harry",20000.00)); ts1.add(new Employee ("Maggie",50000.00)); ts1.add(new Employee ("Chris",70000.00)); Collections.sort(ts1); Iterator itr = ts1.iterator(); while(itr.hasNext()){ Object element = itr.next(); System.out.println(element + "\n"); } }
}
Output:
EmpID 1 Ename Harry Sal 20000.0 EmpID 0 Ename Tom Sal 40000.0 EmpID 2 Ename Maggie Sal 50000.0 EmpID 3 Ename Chris Sal 70000.0
Singleton Behaviour
A Singleton is a class guaranteed to have only a single instance, with a single global access point to that instance. It can be implemented in Ruby and Java. In Ruby we can include a module to acquire all the functionality of the singleton module. The code is already there and we are just reusing the code and adding that similar functionality into our class. Here our intention is to add the functionality of singleton to the class which is achieved using mixins. In java, implementation of interfaces means that the class which implements the interface becomes a type of that class, which is not the intention here. So, there is not interface which class can implement to get the functionality in itself. It has to implement the functionality itself without implementing any interface.
Ruby
When you include the singleton method inside your class it makes the new method private so that you cannot use it. Including ‘singleton’ adds a class method called instance that instantiates only one instance of the class
# require singleton lib require 'singleton' class AppConfig # mixin the singleton module include Singleton # do the actual app configuration def load_config(file) # do your work here puts "Application configuration file was loaded from file: #{file}" end end
output:
conf1 = AppConfig.instance conf1.load_config "/home/khelll/conf.yml" #=>Application configuration file was loaded from file: /home/khelll/conf.yml conf2 = AppConfig.instance puts conf1 == conf2 #=>true # notice the following 2 lines won’t work AppConfig.new rescue(puts $!) #=> new method is private
Enumerable Behaviour
This enumerable functionality adds support to the array members of the class. We can achieve this functionality using mixins in Ruby while it is not possible to do it in Java using interfaces.
Implementation in Ruby:
It adds the functionality of map, inject, select etc to the class which includes the ‘Enumerable’ module. The class which includes should represent a collection of items. Enumerable requires that your class contain an each method that serves up the items in the collection. All the other Enumerable methods rely on this. Example: This is a Team class that manages a group of members:
class Team include Enumerable attr_accessor :members def initialize @members = [] end def each &block @members.each{|member| block.call(member)} end end
Enumerable requires that your class contain an each method that serves up the items in the collection. All the other Enumerablemethods rely on this. Now we can use the map method, for instance:
team = Team.new team.members = ['joshua', 'gabriel', 'jacob'] team.map{|member| member.capitalize} # => ["Joshua", "Gabriel", "Jacob"]
Now we can call any Enumerable methods on our team object itself, and it will assume we want to work with the members array within.
Data Mapper
DataMapper is an API which comes with the ability to use the same API to talk to a multitude of different datastores. There are adapters for the usual RDBMS suspects, NoSQL stores, various file formats and even some popular webservices. This is implemented in ruby using mixins. We need not use interfaces to implement.
Implementation in Ruby:
class Post include DataMapper::Resource property :id, Serial end
Conclusion
The point to take away from this is not that Ruby Mixins are more powerful than Java Interfaces. The mixin feature of Ruby allows for the development of easy to use but powerful plugins that will be hard for any non-Ruby based framework to compete with. Java has many other ways of implementing the functionality mixins are capable of. It is just that it does not use Interfaces to achieve the functionality. Even though both of them are a way of achieving multiple inheritance in their respective languages, they achieve quiet different goals. Inheritance in Java is mainly to overcome the confusion which arises with multiple inheritance, while Mixins in Ruby is mainly to add an additional functionality to the existing class apart from the ‘primary functionality’ of the class.
When a class implements Interface, it indicates that it is of the type interface class and forms a hierarchy with the interface class, while ruby mixins are mainly intended for code reuse and including an additional functionality to the class. It does not form any hierarchy as it is only using module of the class.
References
- http://en.wikipedia.org/wiki/Mixin
- http://en.wikipedia.org/wiki/Interface_(Java)
- http://carboni.ca/blog/p/Modules-How-Do-They-Work
- http://rubylearning.com/satishtalim/modules_mixins.html
- http://www.innovationontherun.com/why-rubys-mixins-gives-rails-an-advantage-over-java-
- http://datamapper.org/
- http://www.dsource.org/projects/tutorials/wiki/SingletonPattern
- http://corelib.rubyonrails.org/classes/Comparable.html
- http://kconrails.com/2010/11/30/ruby-enumerable-primer-part-1-the-basics/
- http://stackoverflow.com/questions/575920/is-a-ruby-module-equivalent-to-a-java-interface