CSC/ECE 517 Fall 2009/wiki2 4 va: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
 
(78 intermediate revisions by the same user not shown)
Line 1: Line 1:
<b>Topic: If-statements considered harmful, and can be replaced by uses of polymorphism.</b>
__TOC__
__TOC__


== Introduction ==
== Introduction ==


The <b>IF statement</b>, a conditional language structure, has been available to programmers for quite some time. It was first introduced in FORTRAN in a form of an [http://en.wikipedia.org/wiki/Arithmetic_IF <b>arithmetic IF statement</b>] back in 1957. The control of the program would be redirected to one of the three labels, depending on the value of the analyzed arithmetic expression (which could be negative, positive, or zero). Over the years, this language element had become obsolete and was replaced by a logical IF statement (if-then-else), the one that is still widely used to this day.
The <code>If</code> statement, a conditional language structure, has been available to programmers for quite some time. It was first introduced in [http://en.wikipedia.org/wiki/FORTRAN FORTRAN] in a form of an [http://en.wikipedia.org/wiki/Arithmetic_IF arithmetic <code>If</code> statement] back in 1957 [1]. The logic behind this language element is simple. The control of the program is redirected to one of three labels, depending on the value of the analyzed arithmetic expression (which could be negative, positive, or zero). Over the years, this language feature had become obsolete and was replaced by a [http://en.wikipedia.org/wiki/Conditional_%28programming%29 logical <code>If</code> statement] (if-then-else), the one that is still widely used to this day.
 
The logical <code>If</code> statement is very familiar to most programmers as it is one of the first language concepts they learn. Despite that, it is a cause of many code errors. Since the <code>If</code> statement is more suitable for [http://en.wikipedia.org/wiki/Structured_programming structured programming], most today's [http://en.wikipedia.org/wiki/Object-oriented object-oriented] languages have more sophisticated mechanisms to replace it. One of such approaches is a use of [http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming polymorphism].


The logical IF statement is very familiar to most programmers as it is one of the first language structures they learn. Despite that, it is a cause of many code errors. Being more suitable for [http://en.wikipedia.org/wiki/Structured_programming structured programming], most today's object-oriented languages have more sophisticated mechanisms to replace the IF statement. One of such approaches is a use of polymorphism.
This paper will discuss ways in which a polymorphism technique can be applied to replace the <code>If</code> control structures, will talk about pros and cons of polymorphism, and will demonstrate some code examples written in [http://en.wikipedia.org/wiki/Ruby_language Ruby language].


This paper will discuss ways in which a polymorphism technique can be applied to replace the IF control structures, pros and cons of the both, and will demonstrate some examples written in Ruby language.
== What is wrong with using <code>If</code> statements? ==


== Use of IF statements ==
Most of the time, a correctly written <code>If</code> statement would not cause any harm to one's code. It, however, possesses a potential to be error prone, as demonstrated by the following Ruby code:
i = 1 # or any other number
if i >= 0
  puts "greater or equal to zero"
elsif i < 0
  puts "less than zero"
else
  puts "will never run!!!!"
end


Let's consider a simple code that would illustrate a use of IF statement in an object-oriented code. First, we define a parent class, Vehicle, and two child classes - Car and Truck. We would then ask a user to choose which of the two classes they would like to initialize. Depending on their selection, the code would look up and suggest a type of fuel that would work with the selected vehicle.
As you can see from this example, the condition for the else part of the statement will never be met. This example does not suggest that a use of <code>If</code> statements should be avoided. It simply demonstrates a potential in conditional statements to be error prone.


Below is a Ruby code that implements the above utilizing the IF statement:
== Example with <code>If</code> statements ==
 
Let's consider a simple code that would illustrate a use of <code>If</code> statement in an object-oriented language. First, we define a parent class, <code>Vehicle</code>, and two child classes - <code>Car</code> and <code>Truck</code>. We would then ask a user to choose which of the two classes they would like to initialize. The <code>If</code> statement performs a dynamic type checking, and then depending on the user's selection, suggests a type of fuel that would work with the chosen vehicle.
 
Below is a Ruby code that implements the above utilizing the <code>If</code> statement:


<pre>
<pre>
Line 37: Line 56:


class Driver
class Driver
   puts "Do you have a Car or a Truck?"  
   puts "What kind of vehicle do you have?"
   #Expects Car or Truck, case sensitive
  type = gets # expects Car or Truck, case sensitive
  my_car = eval(type).new
 
  if my_car.class == Car
    puts "I like 87 octane gasoline"
  elsif my_car.class == Truck
    puts "I like diesel"
  end
end
</pre>
 
If we respond with <code>Car</code>, the output would look as follows:
 
What kind of vehicle do you have?
Car
I am a vehicle
I am a passenger car
I like 87 octane gasoline
 
One apparent downside of this solution is that the code is not easily maintainable if the selection of vehicles
grows further. For instance, let's imagine we decided to add two new <code>Vehicle</code> types, <code>SportsCar</code> and <code>Bicycle</code>. In order to support this addition, we would need to add two new classes, as well as to modify the <code>If</code> statement.
 
The updated code of the <code>Driver</code> class would look as follows:
 
<pre>
class Driver
  puts "What kind of vehicle do you have?"  
   #Expects Car, Truck, SportsCar, or Bicycle, case sensitive
   type = gets             
   type = gets             
   my_car = eval(type).new
   my_car = eval(type).new
Line 46: Line 92:
   elsif my_car.class == Truck
   elsif my_car.class == Truck
     puts "I like diesel"
     puts "I like diesel"
  elsif my_car.class == SportsCar    # new class
    puts "I like 93 octane gasoline" # new output
  elsif my_car.class == Bicycle      # new class
    puts "I don't need any fuel"    # new output
   end
   end
end
end
</pre>
</pre>


One apparent downside of this solution is that the code is not easily maintainable if the selection of vehicles grows further. For instance, let's imagine we decided to add two new vehicle types, Motorcycle and Bicycle. In order to support this addition, we would need to add two new classes, as well as to modify the IF statement (or, better to replace it with a more appropriate conditional, such as case.)
== Example of <code>If</code> replaced by polymorphism ==


== Use of polymorphism ==
Now, let's [http://en.wikipedia.org/wiki/Refactor refactor] our code by implementing the same example using [http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming polymorphism]. The first modification is to introduce a method named <code>get_type_of_fuel</code> in all [http://en.wikipedia.org/wiki/Inheritance_%28object-oriented_programming%29 child classes]. Similar to the earlier example, the caller of the method has no way of knowing which class will be chosen as it would be a run-time decision.
 
Again, we will use Ruby code to demonstrate the new approach:


<pre>
<pre>
Line 84: Line 136:


class Driver
class Driver
   puts "Do you have a Car or a Truck?"  
   puts "What kind of vehicle do you have?"  
   #Expects Car or Truck, case sensitive
   type = gets # expects Car or Truck, case sensitive
   type = gets
  my_car = eval(type).new
  puts my_car.get_type_of_fuel 
end
</pre>
 
If <code>Car</code> is selected, the output would remain the same:
 
What kind of vehicle do you have?
Car
I am a vehicle
I am a passenger car
I like 87 octane gasoline
 
It is important to point out that the maintainability of the application has improved. For instance, as we add new <code>Vehicle</code> types, the class <code>Driver</code> would remain completely intact. Thus, the only change would be to add new [http://en.wikipedia.org/wiki/Inheritance_%28object-oriented_programming%29 child classes] (and they must contain a <code>get_type_of_fuel</code> method).
 
For example, the new class could be defined as follows:
 
<pre>
class SportsCar < Vehicle  # this is a new class
  def initialize
    super
    puts "I am a sports car"
  end
 
  def get_type_of_fuel
    "I like 93 octane gasoline"
  end
end
</pre>
 
And the most important part is that the <code>Driver</code> class would remain absolutely unchanged, yet fully support the new addition:
 
<pre>
class Driver
  puts "What kind of vehicle do you have?"
   type = gets # expects Car, Truck, or SportsCar (newly defined), case sensitive
   my_car = eval(type).new
   my_car = eval(type).new
   puts my_car.get_type_of_fuel   
   puts my_car.get_type_of_fuel   
end
end
</pre>
</pre>
== Pros and Cons of Polymorphism ==
=== Pros ===
According to [3], one of the biggest advantages of [http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming polymorphism] is that new class "features" can be added incrementally. Additionally, these separate class "behaviors" are coded independently from each other, "thus minimizing the possible interference."
Another advantage is that we let "an [http://en.wikipedia.org/wiki/Object_%28computer_science%29 object] figure out how it should behave" [5]. With that in mind, methods should be designed so that they are fully responsible for manipulating object's data which should normally be declared as <code>private</code>.
=== Cons ===
One of the cons of polymorphism is that the "behaviors" are spread among multiple classes (abstractions), as opposed to having everything in one conditional statement.
Another downside is that adding new methods/classes increases the complexity and the size of the code. It is "potentially harder to
understand" [3].
Finally, implementing polymorphism in classes takes a lot of preparation and requires more time to be spent up front. Ultimately, the majority of the design decisions are made very early in the [http://en.wikipedia.org/wiki/Development_life_cycle development life cycle]. That requires a great deal of understanding of the issue that is being solved.


== Conclusion ==
== Conclusion ==


xxxxx
As shown in this article, the use of <code>If</code> statements can be a cause of uncertainty. In many cases, <code>If</code> and other conditionals can be successfully transformed to polymorphism, also improving [http://en.wikipedia.org/wiki/Software_maintenance maintainability] and flexibility of the application [3].


== Links ==
== Links ==
[1] http://en.wikipedia.org/wiki/Arithmetic_IF
[1] Arithmetic IF, http://en.wikipedia.org/wiki/Arithmetic_IF
 
[2] Conditional statements, http://en.wikipedia.org/wiki/If_statement
 
[3] Transform Conditionals to Polymorphism, http://scg.unibe.ch/archive/papers/Duca00cTransform.pdf
 
[4] Polymorphism in object-oriented programming, http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming
 
[5] Polymorphism and Interfaces, http://www.artima.com/objectsandjava/webuscript/PolymorphismInterfaces1.html

Latest revision as of 04:04, 15 October 2009

Topic: If-statements considered harmful, and can be replaced by uses of polymorphism.


Introduction

The If statement, a conditional language structure, has been available to programmers for quite some time. It was first introduced in FORTRAN in a form of an arithmetic If statement back in 1957 [1]. The logic behind this language element is simple. The control of the program is redirected to one of three labels, depending on the value of the analyzed arithmetic expression (which could be negative, positive, or zero). Over the years, this language feature had become obsolete and was replaced by a logical If statement (if-then-else), the one that is still widely used to this day.

The logical If statement is very familiar to most programmers as it is one of the first language concepts they learn. Despite that, it is a cause of many code errors. Since the If statement is more suitable for structured programming, most today's object-oriented languages have more sophisticated mechanisms to replace it. One of such approaches is a use of polymorphism.

This paper will discuss ways in which a polymorphism technique can be applied to replace the If control structures, will talk about pros and cons of polymorphism, and will demonstrate some code examples written in Ruby language.

What is wrong with using If statements?

Most of the time, a correctly written If statement would not cause any harm to one's code. It, however, possesses a potential to be error prone, as demonstrated by the following Ruby code:

i = 1 # or any other number

if i >= 0
  puts "greater or equal to zero"
elsif i < 0
  puts "less than zero"
else
  puts "will never run!!!!"
end

As you can see from this example, the condition for the else part of the statement will never be met. This example does not suggest that a use of If statements should be avoided. It simply demonstrates a potential in conditional statements to be error prone.

Example with If statements

Let's consider a simple code that would illustrate a use of If statement in an object-oriented language. First, we define a parent class, Vehicle, and two child classes - Car and Truck. We would then ask a user to choose which of the two classes they would like to initialize. The If statement performs a dynamic type checking, and then depending on the user's selection, suggests a type of fuel that would work with the chosen vehicle.

Below is a Ruby code that implements the above utilizing the If statement:

class Vehicle
  def initialize
    puts "I am a vehicle"
  end
end

class Car < Vehicle
  def initialize
    super
    puts "I am a passenger car"
  end
end

class Truck < Vehicle
  def initialize
    super
    puts "I am a commercial truck"
  end 
end

class Driver
  puts "What kind of vehicle do you have?" 
  type = gets # expects Car or Truck, case sensitive
  my_car = eval(type).new

  if my_car.class == Car
    puts "I like 87 octane gasoline"
  elsif my_car.class == Truck
    puts "I like diesel"
  end
end

If we respond with Car, the output would look as follows:

What kind of vehicle do you have?
Car
I am a vehicle
I am a passenger car
I like 87 octane gasoline

One apparent downside of this solution is that the code is not easily maintainable if the selection of vehicles grows further. For instance, let's imagine we decided to add two new Vehicle types, SportsCar and Bicycle. In order to support this addition, we would need to add two new classes, as well as to modify the If statement.

The updated code of the Driver class would look as follows:

class Driver
  puts "What kind of vehicle do you have?" 
  #Expects Car, Truck, SportsCar, or Bicycle, case sensitive
  type = gets             
  my_car = eval(type).new

  if my_car.class == Car
    puts "I like 87 octane gasoline"
  elsif my_car.class == Truck
    puts "I like diesel"
  elsif my_car.class == SportsCar    # new class
    puts "I like 93 octane gasoline" # new output
  elsif my_car.class == Bicycle      # new class
    puts "I don't need any fuel"     # new output
  end
end

Example of If replaced by polymorphism

Now, let's refactor our code by implementing the same example using polymorphism. The first modification is to introduce a method named get_type_of_fuel in all child classes. Similar to the earlier example, the caller of the method has no way of knowing which class will be chosen as it would be a run-time decision.

Again, we will use Ruby code to demonstrate the new approach:

class Vehicle
  def initialize
    puts "I am a vehicle"
  end
end

class Car < Vehicle
  def initialize
    super
    puts "I am a passenger car"
  end
  
  def get_type_of_fuel
    "I like 87 octane gasoline"
  end
end

class Truck < Vehicle
  def initialize
    super
    puts "I am a truck"
  end
  
  def get_type_of_fuel
    "I like diesel"
  end
end

class Driver
  puts "What kind of vehicle do you have?" 
  type = gets # expects Car or Truck, case sensitive
  my_car = eval(type).new
  puts my_car.get_type_of_fuel  
end

If Car is selected, the output would remain the same:

What kind of vehicle do you have?
Car
I am a vehicle
I am a passenger car
I like 87 octane gasoline

It is important to point out that the maintainability of the application has improved. For instance, as we add new Vehicle types, the class Driver would remain completely intact. Thus, the only change would be to add new child classes (and they must contain a get_type_of_fuel method).

For example, the new class could be defined as follows:

class SportsCar < Vehicle  # this is a new class
  def initialize
    super
    puts "I am a sports car"
  end
  
  def get_type_of_fuel
    "I like 93 octane gasoline"
  end
end

And the most important part is that the Driver class would remain absolutely unchanged, yet fully support the new addition:

class Driver
  puts "What kind of vehicle do you have?" 
  type = gets # expects Car, Truck, or SportsCar (newly defined), case sensitive
  my_car = eval(type).new
  puts my_car.get_type_of_fuel  
end

Pros and Cons of Polymorphism

Pros

According to [3], one of the biggest advantages of polymorphism is that new class "features" can be added incrementally. Additionally, these separate class "behaviors" are coded independently from each other, "thus minimizing the possible interference."

Another advantage is that we let "an object figure out how it should behave" [5]. With that in mind, methods should be designed so that they are fully responsible for manipulating object's data which should normally be declared as private.

Cons

One of the cons of polymorphism is that the "behaviors" are spread among multiple classes (abstractions), as opposed to having everything in one conditional statement.

Another downside is that adding new methods/classes increases the complexity and the size of the code. It is "potentially harder to understand" [3].

Finally, implementing polymorphism in classes takes a lot of preparation and requires more time to be spent up front. Ultimately, the majority of the design decisions are made very early in the development life cycle. That requires a great deal of understanding of the issue that is being solved.

Conclusion

As shown in this article, the use of If statements can be a cause of uncertainty. In many cases, If and other conditionals can be successfully transformed to polymorphism, also improving maintainability and flexibility of the application [3].

Links

[1] Arithmetic IF, http://en.wikipedia.org/wiki/Arithmetic_IF

[2] Conditional statements, http://en.wikipedia.org/wiki/If_statement

[3] Transform Conditionals to Polymorphism, http://scg.unibe.ch/archive/papers/Duca00cTransform.pdf

[4] Polymorphism in object-oriented programming, http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming

[5] Polymorphism and Interfaces, http://www.artima.com/objectsandjava/webuscript/PolymorphismInterfaces1.html