CSC/ECE 517 Fall 2010/ch1 1e az: Difference between revisions
No edit summary |
|||
Line 101: | Line 101: | ||
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. | 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 | Here is a Ruby implementation of block | ||
def printlist(array,&reverse) | def printlist(array,&reverse) |
Revision as of 00:32, 9 September 2010
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
MultiParadigm 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-Nuemann 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 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 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 object car:
class car{ /* Object variables */ enum color; int model; String manufacturer; float speed /* Object Methods */ public void accelerate(){ /* some code here */ } public void decelerate(){ /* some code here */ } public void maxspeed(){ /* some code here */ } }
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 and store them 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:
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 }