CSC/ECE 517 Fall 2010/ch1 1e az

From Expertiza_Wiki
Jump to navigation Jump to search

Programming Paradigms

Every computer program needs a style of writing which specifies how to solve a software engineering problem. This style is represented by the paradigm. Each computer program follows one or more paradigm which differs in representing the elements of a program(such as variables and objects) and the steps needed to compute a task.

Diferent paradigms are:

1. Procedural/imperative paradigms: Assembly, C, C++, Java, C#

2. Object Oriented paradigm : C++, Java, Python, Ruby, Scala, C#

3. Functional Paradigm : Lisp, Haskell, Clojure, Scala, OCaml, Ruby

4. Logic Paradigm: Prolog

Multi-Paradigm Programming

Multiparadigm refers to use of a combination of programming paradigms for solving a computer problem. Some languages subscribe strictly to a single paradigm like Assembly and C. Others like Java, C++, Scala and C# employ more than one paradigm. Every paradigm comes with its own strength and weakness and this quite motivates us to take advantage of each paradigm and use it in a manner that best fits the problem at hand.

Overview of Functional Programming

Functional programming is derived from lambda calculus which models computations as the evaluation of functions and recursions. More emphasis is laid on application of functions rather than changing the state of variables in a program. Functional programming relies heavily on recursions and it is the only way to iterate instead of loops.

How it differs from imperative programming

Imperative programming follows the Von-Neumann architecture and mainly consists of loops and usage of globa states to perform a computation. For example consider the task of computing the sum of numbers from 1 to n.

In imperative style,

       sum := 0         // global state
       for i<- 1 to n do
           sum := sum + i
           

In Functional style,

        func sum(n)        // note that sum is a function and is recursive
          if  n = 1 then
              return 1
          else
              return n + sum(n-1)

Pure and impure functional programming

Purely functional programming exhibit referential transparency [1] which does not involve any global state or I/O changes. If the same functional expression results in the same output value for the same argument x at different stages of execution , then the function is said to be pure which is devoid of any global state change. For example Haskell [2] is purely functional.

Overview of object oriented programming

Typially programs were written with a procedural view where the program's logic was given utmost importance and it follows a sequential structure. But object oriented techniques really cares about the data or objects we want to mainpulate with rather than the logic of a program. Every object contains its own state(in the form of variables) and and a number of methods to manipulate the variables.For example consider the class Add:

          class Add{
          /* Object variables */
                 private int sum = 0;
         /* Object Methods */
                 public void calculate_sum(int n){
                     int i;
                     while(i <= n){
                         sum = sum + i;
                     }
                 }
           }
      
           Add instance1 = new Add();     // instance1 is an object of type Add
           instance1.calculate_sum(100);
          

Principles of object oriented design

1. Encapsulation: Encapsulation refers to hiding the internal representation of the object from the outside view. For example algorithm to compute the accelarate() method may be hidden, but it will present the user with the expected results.

2. Polymorphism: Polymorphism means ability to take multiple forms. For example an operation may exhibit different behaviour at different instances. Consider the operator '+', for numbers it will generate the sum, but for strings it will produce a third string which concatenates the input strings.

3. Inheritance: Inheritance involves base and derived classes with derived class inheriting all the methods and states frm the base class. Inheritance basically forms a hirerachy. For example if shape is an object, then objects square, rectangle, circle all derive the same characteristic as shape does.

Functional + OOP code

Functions as Objects

One of the cornerstone of functional and object oriented code is treating functions as objects.It means that we can pass functions as arguments, store it and return them from other functions. This is highly useful in an user interface code where it can be used as call back functions which get called when an event occurs( in event driven programming)

An example in Scala [3]:

 Object Timer{
   def  action(callback() : () => unit){              // callback() is the function passed as an argument
        while( some condition)                                                            
        { 
           callback();
           Thread.sleep(3000)
        }
    }
    def event(){                                      //  event is the method which tells what to do 
        /* process the event here
        
        */      
    }
       
 }

Another example of functional concept in object oriented design is the concept of blocks especially in Ruby. Blocks are basically nameless functions which can be passed to a function and then that function can invoke the passed in nameless function. This is a common style called higher order function style among languages that handle functions as first class objects. Basically blocks can be designed for loop abstraction and lets the user to design their own way of iterating the values, thereby hiding the implementation details. For example if we want to iterate backwards from the end to the beginning without revealing its internal implementations, we could implement the loop logic inside the block and pass it to a method or function.

Here is a Ruby implementation of block

def printlist(array,&reverse)
   array.each do |element|
      puts "array element: #{element}"
   end
   reverse.call(array)   /* Here it prints the reverse implementation of list*/
   end
 
printlist([1,2,3,4,5,6]) { |array| array.reverse.each do |element| puts "array element: #{element}" end }

External Links