CSC/ECE 517 Fall 2011/ch1 2c bs

From Expertiza_Wiki
Revision as of 20:13, 22 September 2011 by Sthirum (talk | contribs) (→‎Using Mixins)
Jump to navigation Jump to search

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 your 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.

Comparision

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.

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 functionalities 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