CSC/ECE 517 Fall 2007/wiki1 6 c9: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
 
(12 intermediate revisions by 2 users not shown)
Line 1: Line 1:
                                                         <b><center>Topic 6: Mixins </center></b>
                                                         <b><center>Topic 6: Mixins</center></b>




Line 7: Line 7:




'''Inheritance and Mixins'''
<h2>Inheritance and Mixins</h2>


Some object-oriented languages (notably C++) support multiple inheritance, where a class can have more than one immediate parent, inheriting functionality from each. Although powerful, this technique can be dangerous, as the inheritance hierarchy can become ambiguous.  
Some object-oriented languages (notably C++) support multiple inheritance, where a class can have more than one immediate parent, inheriting functionality from each. Although powerful, this technique can be dangerous, as the inheritance hierarchy can become ambiguous.  
Ruby offers an interesting and powerful compromise, giving you the simplicity of single inheritance and the power of multiple inheritance. A Ruby class can have only one direct parent (i.e no class can inherit from more than one class) and so Ruby is a single-inheritance language. In cases where you want numerous extra behaviors for a class’s instances, Ruby classes provide the multiple inheritance functionality by using mixins. You can use include any number of mixins (a mixin is like a partial class definition). This provides a controlled multiple-inheritance-like capability with none of the drawbacks.  
Ruby offers an interesting and powerful compromise, giving you the simplicity of single inheritance and the power of multiple inheritance. A Ruby class can have only one direct parent (i.e no class can inherit from more than one class) and so Ruby is a single-inheritance language. In cases where you want numerous extra behaviors for a class’s instances, Ruby classes provide the multiple inheritance functionality by using mixins. You can use include any number of mixins (a mixin is like a partial class definition). This provides a controlled multiple-inheritance-like capability with none of the drawbacks.  


<title>''' Mixins '''</title>
<h3> Modules and Mixins </h3>


The process of including a module in a class is also called ‘mixing in’ the
module – which explains why included modules are often called ‘mixins’.
An object can access the instance methods of a module just by including that
module using the include method.


A module looks very similar to class. Modules can have methods, constants and classes. Modules provide a means for grouping related methods, constants and classes. They provide a means for implementing multiple inheritance in Ruby. There are two major features that classes possess but that modules do not: instances and inheritance. Classes can have instances (objects), superclasses (parents) and subclasses (children); modules can have none of these.


There are two major features that classes possess but that modules do not: instances and inheritance. Classes can have instances (objects), superclasses (parents) and subclasses (children); modules can have none of these.
The process of including a module in a class is also called ‘mixing in’ the module – which explains why included modules are often called ‘mixins’.
An object can access the instance methods of a module just by including that module using the include method.


'''Sample'''
 
<h2>Sample</h2>
<pre>
<pre>
  module SampleMixin
module SampleMixin
def do_something
    def do_something
         puts “doing something”
         puts “doing something”
    end
  end
  end
end
 
  class SampleClass
  class SampleClass
include SampleMixin
    include SampleMixin
  end
  end
  s=SampleClass.new
  s=SampleClass.new
  s.do_something   
  s.do_something   
</pre>
</pre>


'''Include '''
<h2>Include </h2>


A couple of points about the ''include'' statement. It has nothing to do with files. C programmers use a preprocessor directive called #include to insert the contents of one file into another during compilation. The Ruby ''include'' statement simply makes a reference to a named module. If that module is in a separate file, you must use require to drag that file in before using ''include''. Second, a Ruby include does not simply copy the module's instance methods into the class. Instead, it makes a reference from the class to the included module. If multiple classes include that module, they'll all point to the same thing. If you change the definition of a method within a module, even while your program is running, all classes that include that module will exhibit the new behavior.
A couple of points about the ''include'' statement. It has nothing to do with files. C programmers use a preprocessor directive called #include to insert the contents of one file into another during compilation. The Ruby ''include'' statement simply makes a reference to a named module. If that module is in a separate file, you must use require to drag that file in before using ''include''. Second, a Ruby include does not simply copy the module's instance methods into the class. Instead, it makes a reference from the class to the included module. If multiple classes include that module, they'll all point to the same thing. If you change the definition of a method within a module, even while your program is running, all classes that include that module will exhibit the new behavior.
Line 42: Line 43:




'''Including Modules From Files'''
<h2>Including Modules From Files</h2>


Often it is more useful to define modules in separate files and include them as needed. The first thing you have to do in order to use code from another file is to load that file using the require method, like this:
Often it is more useful to define modules in separate files and include them as needed. The first thing you have to do in order to use code from another file is to load that file using the require method, like this:
Line 58: Line 59:




<center>'''EXAMPLE'''</center>
<center><h2>EXAMPLE</h2></center>




Line 78: Line 79:
end
end
end
end


module Emplike
module Emplike
          attr_accessor :salary
    attr_accessor :salary
         def getsalary
         def getsalary
         return "#{salary}"
         return "#{salary}"
Line 88: Line 87:
end
end


class Employee
    include Personlike
    include Emplike
end




 
s=Employee.new
  class Employee
s.name="Federer"
 
s.age=26
      include Personlike
s.salary=100000
      include Emplike
puts (s.getname)
 
puts(s.getage)
  end
puts(s.getsalary)
 
 
  s=Employee.new
  s.name="Federer"
  s.age=26
  s.salary=100000
  puts (s.getname)
  puts(s.getage)
  puts(s.getsalary)




Line 114: Line 108:
</pre>
</pre>


<b>Disadvantages of Mixins in Ruby</b>
The class Employee includes modules Personlike and Emplike. So we can access the methods getname(), getage() and getsalary() as if they are methods in Employee class itself. This provides the functionality of multiple inheritance using mixins.
 
<h3>Disadvantages of Mixins in Ruby</h3>


A mixin will not warn if the mixin and the user define the same method.(i.e if there are methods with same name in mixin and also in the class, the method in the class is executed without warning the user).
A mixin will not warn if the mixin and the user define the same method.(i.e if there are methods with same name in mixin and also in the class, the method in the class is executed without warning the user).
Line 122: Line 118:
<pre>
<pre>
module Emplike
module Emplike
          attr_accessor :salary
    attr_accessor :salary
         def getsalary
         def getsalary
         return "#{salary}"
         return "#{salary}"
Line 128: Line 124:
end
end


 
class Employee
 
 
    class Employee
       include Personlike
       include Personlike
       include Emplike
       include Emplike  
     
           def getsalary
           def getsalary
             return" This is the salary of user defined getsalary"
             return" This is the salary of user defined getsalary"
           end
           end
      end
end
 
 
  s=Employee.new
  s.salary=100000
  puts(s.getsalary)


s=Employee.new
s.salary=100000
puts(s.getsalary)
   
   


Line 154: Line 144:




 
<h2>Implementation in Java</h2>
 
'''Implementation in Java'''


The class "emp" implements "emplike" and "personlike" packages in this example.
The class "emp" implements "emplike" and "personlike" packages in this example.
Line 165: Line 153:


public interface personlike {
public interface personlike {
String getname();
    String getname();
int getage();
    int getage();
}
}


package assignment;
package assignment;


public interface emplike {
public interface emplike {
float getsalary();
    float getsalary();
}
}


package assignment;
package assignment;
Line 182: Line 167:
public class emp implements assignment.emplike,assignment.personlike  
public class emp implements assignment.emplike,assignment.personlike  
{
{
String name1;
    String name1;
int age1;
    int age1;
float salary1;
    float salary1;
emp(String name,int age,float salary)
    emp(String name,int age,float salary)
{
    {
name1=name;age1=age;salary1=salary;
name1=name;age1=age;salary1=salary;
}
    }
public String getname()
    public String getname()
{
    {
return name1;
return name1;
    }
}
    public int getage()
public int getage()
    {
{
return age1;
return age1;
    }
}
    public float getsalary()
public float getsalary()
    {
{
return salary1;
return salary1;
    }
}
}
}


package assignment;
package assignment;
Line 226: Line 206:




 
The class emp implements the interfaces emplike, personlike. So the methods in those interfaces can be implemented by emp class.This provides the functionality of multiple inheritance even thought we are not directly inheriting from a multiple classes.In this example using java,multiple inheritance is achieved by using interfaces.
 
''' Implementation in C++ '''
<h2>Implementation in C++ </h2>


The class "emp" extends "personlike" and "employeelike" classes.
The class "emp" extends "personlike" and "employeelike" classes.
Line 236: Line 216:
  #include<stdio.h>
  #include<stdio.h>
  #include<string.h>
  #include<string.h>
  using namespace std;
using namespace std;


  class personlike
  class personlike
Line 292: Line 272:
</pre>
</pre>


C++ provides multiple inheritance. So class emp extends personlike and employeelike classes. Now getage(), getsal() and getname() methods can be accessed by emp class object.




<b>Conclusion</b>
<b><h3>Conclusion</h3></b>


C++ multiple inheritance can sometimes become knotted and lead to unordered hierarchy .
C++ multiple inheritance can sometimes become knotted and lead to unordered hierarchy .
Line 303: Line 284:


        
        
  ''' <center>References Used</center>'''
  ''' <center><h2>References Used</h2></center>'''





Latest revision as of 01:44, 20 September 2007

Topic 6: Mixins


Compare the use of Ruby mixins with how one would solve the same problem in Java or C++. In Java, you might use interfaces or the decorator pattern (p. 91 of Head-First Design Patterns). In C++, you would probably use multiple inheritance. Give code in all three languages and compare the solutions on the basis of verbosity and elegance.


Inheritance and Mixins

Some object-oriented languages (notably C++) support multiple inheritance, where a class can have more than one immediate parent, inheriting functionality from each. Although powerful, this technique can be dangerous, as the inheritance hierarchy can become ambiguous. Ruby offers an interesting and powerful compromise, giving you the simplicity of single inheritance and the power of multiple inheritance. A Ruby class can have only one direct parent (i.e no class can inherit from more than one class) and so Ruby is a single-inheritance language. In cases where you want numerous extra behaviors for a class’s instances, Ruby classes provide the multiple inheritance functionality by using mixins. You can use include any number of mixins (a mixin is like a partial class definition). This provides a controlled multiple-inheritance-like capability with none of the drawbacks.

Modules and Mixins


A module looks very similar to class. Modules can have methods, constants and classes. Modules provide a means for grouping related methods, constants and classes. They provide a means for implementing multiple inheritance in Ruby. There are two major features that classes possess but that modules do not: instances and inheritance. Classes can have instances (objects), superclasses (parents) and subclasses (children); modules can have none of these.

The process of including a module in a class is also called ‘mixing in’ the module – which explains why included modules are often called ‘mixins’. An object can access the instance methods of a module just by including that module using the include method.


Sample

 module SampleMixin
     def do_something
        puts “doing something”
     end
 end

 class SampleClass
     include SampleMixin
 end

 s=SampleClass.new
 s.do_something  

Include

A couple of points about the include statement. It has nothing to do with files. C programmers use a preprocessor directive called #include to insert the contents of one file into another during compilation. The Ruby include statement simply makes a reference to a named module. If that module is in a separate file, you must use require to drag that file in before using include. Second, a Ruby include does not simply copy the module's instance methods into the class. Instead, it makes a reference from the class to the included module. If multiple classes include that module, they'll all point to the same thing. If you change the definition of a method within a module, even while your program is running, all classes that include that module will exhibit the new behavior.


Including Modules From Files

Often it is more useful to define modules in separate files and include them as needed. The first thing you have to do in order to use code from another file is to load that file using the require method, like this: require( "testmod.rb" )

The required file must be in the current directory, on the search path or in a folder listed in the predefined array variable $:. You can add a directory to this array variable using the usual array-append method, << in this way: $: << "C:/mydir" The require method returns a true value if the specified file is successfully loaded; otherwise it returns false. If in doubt, you can simply display the result: puts(require( "testmod.rb" ))

Pre-Defined Modules

The following modules are built in to the Ruby interpreter: Comparable, Enumerable, FileTest, GC, Kernel, Math, ObjectSpace, Precision, Process, Signal


EXAMPLE


Consider a scenario of an employee. An employee has the features of a person ( having name,age and other attributes) and also that of an employee( having salary, hours of work and other attributes). In our example, we explain multiple inheritance by showing how modules "Emplike" and "Personlike" are inherited by "Employee" class. Thus we illustrate mixins in ruby.


Implementation in Ruby

module Personlike
     attr_accessor :name
     attr_accessor :age
        def getname
           return "#{name}"
        end
        def getage
           return "#{age}"
	end
end

module Emplike
     attr_accessor :salary
        def getsalary
         return "#{salary}"
	end
end

class Employee
    include Personlike
    include Emplike
end


s=Employee.new
s.name="Federer"
s.age=26
s.salary=100000
puts (s.getname)
puts(s.getage)
puts(s.getsalary)


Output:
Federer
26
100000

The class Employee includes modules Personlike and Emplike. So we can access the methods getname(), getage() and getsalary() as if they are methods in Employee class itself. This provides the functionality of multiple inheritance using mixins.

Disadvantages of Mixins in Ruby

A mixin will not warn if the mixin and the user define the same method.(i.e if there are methods with same name in mixin and also in the class, the method in the class is executed without warning the user).

Consider the above example: Incase we include a getsalary method in both the module and also in the class, the method in the class is executed without warning.

module Emplike
     attr_accessor :salary
        def getsalary
         return "#{salary}"
	end
end

class Employee
      include Personlike
      include Emplike    
          def getsalary
            return" This is the salary of user defined getsalary"
          end
end

s=Employee.new
s.salary=100000
puts(s.getsalary)
 

Output:
This is the salary of user defined getsalary


Implementation in Java

The class "emp" implements "emplike" and "personlike" packages in this example.


package assignment;

public interface personlike {
     String getname();
     int getage();
}

package assignment;

public interface emplike {
     float getsalary();
}

package assignment;

public class emp implements assignment.emplike,assignment.personlike 
{
    String name1;
    int age1;
    float salary1;
    emp(String name,int age,float salary)
    {
	name1=name;age1=age;salary1=salary;
    }
    public String getname()
    {
	return name1;	
    }
    public int getage()
    {
	return age1;
    }
    public float getsalary()
    {
	return salary1;
    }
}

package assignment;

public class emptest {

	public static void main(String args[])
	{
		emp ob=new emp("Federer",26,100000);
		String name=ob.getname();
		int age=ob.getage();
		float sal=ob.getsalary();
		System.out.println("name is "+name+"age is "+age+"salary is "+sal);
		
	}
}


The class emp implements the interfaces emplike, personlike. So the methods in those interfaces can be implemented by emp class.This provides the functionality of multiple inheritance even thought we are not directly inheriting from a multiple classes.In this example using java,multiple inheritance is achieved by using interfaces.

Implementation in C++

The class "emp" extends "personlike" and "employeelike" classes.

 #include<iostream.h>
 #include<stdio.h>
 #include<string.h>
 using namespace std;

 class personlike
 {
	public:
	char* name;
	int age;
	personlike(char* a,int b)
	{
		name=new char[10];
		strcpy(name,a);
		age=b;
	}
	char* getname()
	{
		return name;
	}
	int getage()
	{
		return age;
	}
};
class employeelike
{
	public:
	int salary;
	employeelike(int a)
	{
		salary=a;
	}
	int getsal()
	{
		return salary;
	}
};
class emp:public personlike,public employeelike
{
	public:
	emp(char* a,int b,int c):personlike(a,b),employeelike(c)
	{
	}
	
};


int main()
{
	emp* a=new emp("Federer",26,100000);
	cout<<a->getname()<<endl;;
	cout<<a->getage()<<endl;
	cout<<a->getsal()<<endl;
	cout<<a->name<<"\t"<<a->age<<"\t"<<a->salary<<endl;
	return 0;
}

C++ provides multiple inheritance. So class emp extends personlike and employeelike classes. Now getage(), getsal() and getname() methods can be accessed by emp class object.


Conclusion

C++ multiple inheritance can sometimes become knotted and lead to unordered hierarchy . Java, even though is a single inheritance language can exhibit multiple inheritance using interfaces. However, care has to be taken in Java to implement all the interfaces and it can be a lengthy procedure. Ruby is unambiguous, elegant and concise.



References Used


1) The Little Book of Ruby http://www.sapphiresteel.com/The-Little-Book-Of-Ruby

2) Programming Ruby: The Pragmatic Programmer’s guide http://www.rubycentral.com/pickaxe/tut_modules.html

3) Bowler Ruby http://www.softwaresummit.com/2006/speakers/BowlerRubyForJavaProgrammers.pdf