CSC/ECE 517 Fall 2012/ch1a 1w16 br
Overview
Mixins are Ruby modules. A module is a grouping of objects under a single name. The objects may be constants, methods, classes, or other modules. Modules are defined in Ruby using the keyword module. They can be incorporated into a class with Ruby’s include statement. This is called a mixin. Modules are for sharing behavior (methods), while classes are for modeling relationship between objects. Ruby classes can Mixin a module and receive all its methods for free. An Interface in Java programming language is an abstract type that classes must implement. Interfaces are declared using the interface keyword, and may only contain method signature and constant declarations. A class that implements an interface must implement all of the methods described in the interface, or be an abstract class.
Definitions
Mixins
Modules provide a structure to collect classes, methods, and constants into a single, separately defined unit. They provide the simplest and an elegant way to adhere to the Don't repeat yourself<ref>Don't_repeat_yourself</ref> principle. This is useful so as to avoid clashes with existing classes, methods, and constants. Modules are defined in Ruby using the module keyword. A Mixin is a class that is mixed with a module or a set of modules i.e. the implementation of the modules and the class are intertwined and combined together <ref>Mixins </ref>. This gives us a neat and controlled way of adding new functionality to classes. Modules are similar to classes in that they hold a collection of methods, variables constants and other modules and class definitions. However, the real usage of a Mixin is exploited when the code in the Mixin starts to interact with code in the class that uses it. Below is an example for modules and Mixins: The module ParkingSlot consists of the methods park and unpark
module ParkingSlot def park #code to park the car end def unpark #code to unpark the car end end
The module ParkingMeter consists of the methods calculate and printreceipt
module ParkingMeter def calculate #code to calculate the parking fee end def printreceipt #code to print the receipt end end
When a class includes a module via include Module Name, all the methods on that module become instance methods on the class.
class Parking include ParkingSlot include ParkingMeter def printcardetails #code to print the details and type of car end end
The modules ParkingSlot and ParkingMeter are “included” in the Parking class. All the variables and the instance methods of the modules ParkingSlot and ParkingMeter are now said to be “mixed in” into the class. It is now possible for class instances to use these methods defined in the modules as and when required.
p=Parking.new p.park # -> Method park from module ParkingSlot p.unpark # -> Method unpark from module ParkingSlot p.calculate # -> Method calculate from module ParkingMeter p.printreceipt # -> Method printreceipt from module ParkingMeter p.printcardetails # -> Calls printCarDetails from class
The class Parking inherits from both the modules and the module methods are now available in Parking. Hence, it is now possible to use the methods with an instance of the Parking class p.
Hence, Mixins can be thought of taking different methods and variables defined in different modules making them available as instance methods in the class as well, thereby extending the class’ functionality. Effectively mixed in modules behave as superclass.
Interfaces
In object-oriented programming languages such as Java, C#, an interface<ref>Interfaces </ref> is a reference type, similar to a class that can contain only constants, method signatures, and nested types. There are no method bodies. Interfaces cannot be instantiated and they can only be implemented by classes or extended by other interfaces. All methods are public by default and any fields declared in an interface are by default static and final. Example:
public interface ParkingLot { boolean add(Car car, int slot); boolean remove(Car car); boolean findCar(Int number); int freeSlotsCount(); int occupiedSlots(); int parkingType(); int calculateParkingFee(int hours, int charge, int duration); int findParkingSlot(); } public class Mall implements ParkingLot { boolean add(Car car, int slot) { //... Code to add a car into the parking lot... } boolean remove(Car car){ // do something } boolean findCar(Int number){ // do something } int freeSlotsCount(){ // do something } int occupiedSlots(){ // do something } int parkingType(){ // do something } int calculateParkingFee(int hours, int charge, int duration){ // do something } int findParkingSlot(){ // do something } }
Interfaces play another important role in the object-oriented programming language. Interfaces are not part of the class hierarchy, although they work in combination with classes.
Mixins vs. Interfaces
Similarities and Differences
Mixins and Interfaces can be considered as a block of code having some variables and methods that can be used by a class. The difference between them is that a Mixin can contain method definitions whereas an Interface cannot.
Multiple method definition
In a class, when more than one module is Mixed in where some modules have overloaded methods, the method from the module that was last Mixed in into the class will be executed.
module Frog def sound() puts "croak..." end end
module Dinosaur def sound() puts "roar..." end end
class Frogosaur include Frog include Dinosaur end
Frogosaur.new.sound
Output:
roar...
This is because the class Frogosaur can contain only one definition for each method. The users have the flexibility to make use of methods from different modules by rearranging the order of include. Interfaces, on the other hand, do not offer the flexibility to have different implementation for a same method. This is because the class implementing the interface can provide only one implementation for each method. Hence they offer only one method definition for the user.
public interface Frog { void sound(); } public interface Dinasour { void sound(); }
public class Frogosaur implements Frog,Dinasour{ public void sound() { System.out.println("barks......"); }
public static void main(String args[]) { new Frogosaur().sound();; } }
Output:
barks...
Multiple object behavior
In Ruby, a class’s instance can extend a module and exhibit different behavior than the other instances of the same class.
module Frog def sound() puts "croak..." end end
module Dinasour def sound() puts "roar..." end end
class Frogosaur def sound() puts "barks..." end end
beast1= Frogosaur.new beast2= Frogosaur.new beast1.extend(Frog) beast1.sound beast2.sound Output:
croak...
barks...
Interfaces are implemented by a class and all instances of the class behave in the same way. They can only use the methods of the class to which they belong to.
public class Frogosaur implements Frog,Dinasour{ public void sound() { System.out.println("Sounds..."); } public static void main(String args[]) { Frogosaur beast1 = new Frogosaur(); Frogosaur beast2 = new Frogosaur(); object1.sound(); object2.sound(); } }
Output:
Sounds...
Sounds...
Enumerable – module and interface
Ruby’s Arrays have several methods defined in them. To use them, the classes need not be a subclass of Array. The classes can include Enumerable <ref>Enumerables</ref> and define the each method to use the array’s methods for free.
class EnumExer include Enumerable def initialize(*arrays) @arrays = arrays end def each @arrays.each { |a| a.each { |x| yield x } } end end ma = EnumExer.new([4, 1], [3], [2]) puts ma.sort
Output:
1
2
3
4
You can observe that although the arguments passed to the ma instance did not have a similar structure, the sort method was able to identify each entry and sort them. This is because the each method was defined to identify and serve all the entries to the sort method. The methods that are defined for Enumerable modules are:
["all?", "any?", "collect", "detect", "each_with_index", "entries","find", "find_all", "grep", "include?", "inject", "map", "max","member?", "min", "partition", "reject", "select", "sort", "sort_by","to_a", "zip"]
In Java, to use the methods of Enumerable interface, the class should be a subclass of Array.
public class EnumExer { static String content_string = "zyxwvutsrqponmlkjihgfedcba"; String a="1", b="2"; public static void main(String args[]) { char[] content_array = content_string.toCharArray(); java.util.Arrays.sort(content_array); content_string=new String(content_array); System.out.println(content_string); } }
Output:
Abcdefghijklmnopqrstuvwxyz
In the above example, the string object was converted to a character array to be able to use with the sort method.
Inheritance
Java interfaces can inherit other interfaces whereas Ruby modules cannot although they can contain classes and methods.
module Wrapper class Base # Class Body end end
public interface Dinasour extends Frog{ //variables and method Declarations }
Achieving Multiple Inheritance
Modules and Interfaces help acheive multiple inheritance.
Interfaces are used in Java to achieve multiple inheritance<ref> Mulitple Inheritance </ref>. Similarly, modules in Ruby help achieve multiple inheritance.
In Ruby,
module Frog def jump() //Method definition end end
module Dinosaur def strength() //Method definition end end
class Frogosaur include Frog include Dinosaur end
In Java,
public interface Frog { void jump(); }
public interface Dinasour { void strength(); }
public class Frogosaur implements Frog,Dinasour{ //Method Implementations }
Frogosaur inherits the methods of both frog and dinosaur.
Comparison
Mixins | Interfaces |
---|---|
The number of lines of code is lesser since the modules contain method definitions. |
The number of lines of code is bigger since the classes have to define the methods. |
More modules in a class makes code less readable. | The code is more readable since the class contain the method definition. |
Modules cannot be inherited and cannot form is-a hierarchy. | Interfaces can extend another interface and hence can form is-a hierarchy. |
Drawbacks
The drawbacks of the technique of Mixins are very much debated. Though Mixins provide us with an easy way to write flexible and decoupled code they pose their own problems. In large programs there could be large number of modules and each module could have loads of methods each performing a certain task. To trace the origin of the methods and to remember the hierarchy is difficult. Mixins suffer from silent method overriding. Silent method overriding refers to a condition when different modules are included in a class and each module have a method with the same definition. In such a case, the method which gets executed depends upon the way it is included in the class and this is done without any sort of message to the user (silently). In large scale applications this could certainly be an issue considering the number of modules that would be mixed in and it would be difficult to keep track of the hierarchy in which the modules were included. Although Java provides polymorphic behavior with the use of interfaces, they sometimes tend to be very slow. The implementation of interfaces is also limited to public methods and constants with no implementation.
Conclusion
Modules and Interfaces are similar in the fact that they enable additional features in object-oriented programming languages. They are dissimilar in the way they are implemented but add more flexibility to object-oriented programming and are easy to maintain.
References
<references/>
See Also
1. http://ruby.about.com/od/beginningruby/a/mixin.htm/
2. http://juixe.com/techknow/index.php/2006/06/15/mixins-in-ruby/
3. http://www.innovationontherun.com/why-rubys-mixins-gives-rails-an-advantage-over-java-frameworks/
4. http://pg-server.csc.ncsu.edu/mediawiki/index.php?title=CSC/ECE_517_Fall_2010/ch3_3b_sv&printable=yes
5. http://expertiza.csc.ncsu.edu/wiki/index.php/CSC/ECE_517_Fall_2011/ch2_2c_ds
6. Lucas Carlson; Leonard Richardson (July 2006), Ruby Cookbook, O'Reilly Media, ISBN 10:0-596-52369-6