280 likes | 472 Views
Objects were first introduced in Simula 67 although the intent in Simula was not to provide a new programming paradigm, but instead to offer a construct to easily build models for simulation purposes OOP was developed fully in Smalltalk
E N D
Objects were first introduced in Simula 67 although the intent in Simula was not to provide a new programming paradigm, but instead to offer a construct to easily build models for simulation purposes OOP was developed fully in Smalltalk the object can be thought of as an extension to ADTs except that the structure can be extended for easy modification leading to a hierarchically organization message-passing was implemented rather than function calls encapsulation was enforced through the class construct different types of objects call upon the same method if the objects were related hierarchically, leading to polymorphism and generic methods OOPL was later included in many languages C++ (a descendent of C with many of Smalltalk’s class ideas) Common Lisp (added to CL was CLOS, the Common Lisp Object System) Ada 95 (Ada 83 + objects) Java and C# introduce a newer generation of OOPLs related to C++ but cleaner and easier to understand Scripting languages started adding objects with JavaScript and has continued with both Python and Ruby (Ruby is the only pure OOPL since Smalltalk) Object-Oriented Programming
Pure OOP: all computation done by message passing Hybrid OOP: computation shared between message passing and function calls most OOPLs are hybrids (C++, Ada 95, Delphi, Common Lisp, C#) Java would be pure if not for the 8 primitive types Inheritance: to solve the modification problem; controls what definitions a subclass obtains from a parent class to control inheritance, the language might include modifiers such as private, public and protected question: can a subclass override a parent’s definition? if so, can the parent item still be accessed or is it hidden? question: is multiple inheritance available? (C++ and CLOS have this) Polymorphism: variables that can reference any subclass of a given class we need a mechanism to bind a message to the proper method, which is often done at run time so is called dynamic type binding OOPL Definitions
Class/Subclass Relationships • Aside from C++ and Common Lisp, classes in other languages must have one (and only one) parent • any defined class needs a parent, what is that parent’s parent? • with this restriction, such languages will offer a starting class • usually called Object • what if a parent class is not specific enough to have an implementation for its methods but all child classes should have the given methods? • in this case, we can make the methods in the parent class abstract (also known as virtual) • this forms what is known as an interface in Java • an interface means that the pre-specified abstract methods must be implemented in any class that implements (inherits from) the interface • classes with abstract entities cannot themselves be instantiated, but can be extended into subclasses
Design Issues • Exclusitivity of Objects • are all types classes, or are there other types? • dictates whether all communication is via message passing or if other forms are provided and whether the language is pure OOP or hybrid • Subclass relationships • is a subclass a descendant of the class (is-a relationship) • or some different relationship such as a subrange or subset • Inheritance and information hiding • how are these provided? is information hiding enforced? • Type checking and polymorphism • is type checking done and if so, when? • can variables be polymorphic? • Single vs. multiple inheritance • which is allowed? • Allocation and Deallocation of Objects • when and how is this performed? Note: we will explore sample programs from many of the languages discussed here on-line so this set of notes largely omits specific examples
Smalltalk • Programs consist only of objects and messages • variables are local (private) or global (shared) • all vars are pointed to by ptrs • inheritance • single inheritance only, subclasses inherit everything from the parent • class methods/data • can be overridden in the derived class • the parent’s methods/data are only hidden but still accessible (using super) • Dynamic binding for polymorphism • when a method is called, a search takes place at the child’s location for that method’s definition • if not found, the search continues up the hierarchy until the method’s definition is found (if none found, error) • if parameters and return type are the same for all classes that a polymorphic variable can take on, then type checking can be done at compile time, otherwise it is done at run-time
All items in Smalltalk are objects, so all operations are methods and specifying actions is done strictly through message passing (even if it doesn’t look like it!) messages contain object for whom the message is sent method to invoke any needed parameters some examples: 21 + 2 // object 21 receives message + and parameter 2 sum / count //sum receives message to divide by count firstArray at: 1 put: 5 // firstArray gets message at with // parameter 1 and put 5, or // firstArray[1] = 5; ourPen home; up; goto: 500@500; down; home graphics routine with multiple messages passed to ourPen Smalltalk Messages and Methods
Message Types Continued • 3 forms of methods: • unary methods (message without params) • binary methods (as with 21 + 2 or sum / count, mostly used for arithmetic operations) • and the general form shown below where key# is a keyword for the object • key1: param1 key2: param2 … key n: param n • Assignments statements operate as follows • any message expression, variable or literal object on RHS • LHS is a data instance • total 22 • sales deducts grossPay: 350.0 dependents: 4
Defining a Class • Much like Java, you define your class, its variables and its methods • In Smalltalk, you have class variables and instance variables • class variables are like Java’s static instance variables – that is, you define a variable to be classwide • The notation is: • Object subclass: #superclassname • instanceVariableNames: ‘’ • classVariableNames: ‘’ • poolDictionaries: ‘’ • Category: ‘classname’ • If you have variables to define in any section, separate them by spaces within the ‘’ as in ‘x y z’ • the poolDictionary contains variables that are not owned by this class, so you can use this to define global variables that this class might manipulate – bad idea of course!
Defining Methods • Since Smalltalk is interpreted, you typically define your methods interactively after you have defined your class rather than wrap them up in a single definition • Methods by default do not expect to receive parameters • If you want your method to receive a single parameter, add : param after the method’s name as in • setX: newValue • If you have multiple parameters, you must have specific keywords for all but the first as in • setValues: val1 Value2: val2 Value3: val3 • In this case, you would call the method as setValues: 5 Value2: 3 Value3: 10 • Local variables are declared in | | notation as in | x y z | • To return a value at the end, use ^ returnvalue
Object subclass: #NameOfSubclass instanceVariableNames: ‘p1 p2' classVariableNames: '' poolDictionaries: '' category: 'Point‘ getP1 ^p1. getP2 ^p2. init: x second: y p1:=x. p2:=y. distance: point2 | temp1 temp2 | temp1:=(p1 - point2 getP1)*(p1 – point2 getP1). temp2:=(p2 - point2 getP2)*(p2 – point2 getP2). ^ (temp1 – temp2) sqrt. Example: Point Here is how we can interact with Points: point1 := Point new. point1 init: 5 second :10. point2 := Point new. point2 init: 12 second :7. point1 distance: point2.
Blocks are specified in [ ] with instructions separated by .’s block code is only executed when the message value is sent to the block addIndex [sum <- sum + index] addIndex value value is a message to addIndex to execute the block Blocks can contain relational expressions and return True or False providing a mechanism for conditional blocks conditional blocks can be used to form a pretest loop method called whileTrue: x 1. sum 0. [x <=20] whileTrue: [sum sum+x. xx+1] another loop is timesRepeat: which is provided an integer value Selection statements use ifTrue and ifFalse as in [x > 0] ifTrue: [y x + 1. x x – 1] ifFalse: [y 0.] Blocks and Control Structures
Small language, simple (?) syntax mathematically limited less efficient than imperative languages because of dynamic type checking, errors often not caught until run-time First real OOPL and the only pure OOPL until Ruby successor languages did not like to force everything to be message passing and therefore most OOPLs are hybrids of some form Smalltalk pioneered many of the ideas found common in all OOPLs LOGO was a system built using Smalltalk to provide a graphical programming environment objects are windows, menus, cursor, lines, … messages include down, up, turn:degrees, go:distance, goto: point, home, north, … Pen is the general class designated to draw To draw a triangle: OurPen Pen new defaultNib: 2. OurPen up; goto: 800@300; down OurPen go: 100; turn: 120; go: 100; turn: 120; go: 100 Evaluation of Smalltalk
C++ • Based on C (same types) but adds classes • updates Smalltalk’s object system as follows: • classes can either be a derived class (from a superclass) or stand alone without having a superclass • some or all data and functions can be inherited from base class(es) • objects can be either stack dynamic or heap dynamic (these require a destructor method to deallocate memory) • both forms require a constructor • whereas Smalltalk’s use of classes was consistent and fairly simple (because the language itself was small), C++’s use of classes is very complex and the language is quite large • C++ is the most used OOPL in spite of (or maybe because of) having complex object-oriented mechanisms • such as multiple inheritance and complete flexibility in controlling what is inherited
Class members can be private, protected or public private members are only accessible by member functions and friends of the class friends are functions/classes explicitly declared as friends by the given class public members are accessible by any function protected members are like private members except that derived classes can modify access rights for inheriting members Controlling Inheritance class base_class { private: int a; float x; protected: int b; float y; public: int c; float z; } class sub1 : public base_class {…}; class sub2 : private base_class {…}; in sub1: b and y are protected, c and z are public in sub2: b, y, c and z are private and no derived class of sub2 will have access to any of these a and x are not accessible to sub1 or sub2 note that since sub2 is a derived private class, no member of the parent class is explicitly visible, and so b, c, y and z must be re-exported to be used in an instance of sub2 – this is done using : : as in base_class : : c;
Example class stack : public single_linked_list { public: stack( ) { } void push(int value) { single_linked_list::insert_at_head (int value); } int pop( ) { single_linked_list::remove_at_head( ); } }; class queue : public single_linked_list { public: queue( ) { } void enqueue(int value) { single_linked_list::insert_at_tail (int value); } int dequeue( ) { single_linked_list::remove_at_head( ); } }; class single_linked_list { class node { friend class single_linked_list; private: node *link; int contents; }; private: single_linked_list( ) {head = 0}; void inset_at_head(int); void insert_at_tail(int); int remove_at_head( ); int empty( ); }; The nested inner class, node, lists single_linked_list as a friend so that single_linked_list can access node’s private parts Both stack and queue extend single_linked_list but both are public derivations, we should restrict that by making them private – see the code on Page 540-542
Objects can be referenced through ordinary variables these objects are stack dynamic and all method calls would be statically bound Otherwise, objects are referenced via pointers these objects are heap dynamic any pointer of a class can point at any derived class of that class thus, pointers can be polymorphic variables but non-pointers cannot if the variable is polymorphic then method calls are dynamically bound any method that will be dynamically bound must be declared as a virtual function C++ Object Binding
Example public class shape { public: virtual void draw( ) = 0; // indicates that draw is a pure virtual function } // that is, that there is no implementation here // so shape is an abstract class public class circle : public shape { public: virtual void draw( ) {…} } public class rectangle : public shape { public: virtual void draw( ) {…} } public class square : public rectangle { public: virtual void draw( ) {…} } square s; // s is dynamically rectangle r; // bound to draw shape &ref_shape = s; ref_shape.draw( ); // whereas r is statically r.draw( ); // bound to draw
Java • Most of you are familiar with Java, so we will only cover a few highlights of objects in Java • all entities in Java are objects except for the primitive types so all Java programs require class definitions • the class with the main method is an object that creates or calls upon all other objects • Java restricts inheritance to single inheritance • all objects must have a parent (no stand-alone objects), by default, the parent is Object • multiple inheritance can somewhat be simulated through interfaces • all objects are heap dynamic and pointed to by reference variables (a pointer that does not require dereferencing) • all method calls are dynamically bound (unless a class is denoted as final which means it can not be extended, so it will not have subclasses) • Java includes a finalize method that will be invoked before the object’s memory is returned to the heap • Java has no destructor since garbage collection is used • Java is simpler and less powerful than C++ • but that might be a good thing!
C# • C# offers constructs for the class (similar to Java) and struct (similar to C++) • structs are stack dynamic, objects are heap dynamic • C#’s syntax is more like C++ for class definitions, for example: • public class NewClass : ParentClass {…} • dynamic binding is done only if methods are specially indicated as virtual where overridden methods in derived classes must be specially indicated through the word override • classes that contain abstract methods must be declared as abstract and abstract classes cannot be instantiated (see page 534 for example) • like Java, C# offers only single inheritance and all classes must have a parent (no stand-alone classes) with the parent class defaulting to Object • the Object class implements ToString, Finalize and Equals, which are inherited to all classes
Ada 83 included the Package for encapsulating ADTs Objects were added for Ada 95 as an extension for this Objects became a new type called a tagged type Tagged types are either records or private types private types are true objects as they offer information hiding Packages can be separately compiled giving Ada 95 the ability to offer classes much like Java, C++, and C# Ada offers both static and dynamic binding of objects to procedure calls Dynamic binding is available through the tagged type’s classwide type denoted as Name’class or by using a polymorphic variable Ada objects: No implicit calling of constructors and destructors if desired, they must be invoked explicitly, but they are not needed Single inheritance although multiple inheritance can be simulated to some extent using generic classes Subclasses inherit all items from a parent class and to restrict this, you would have to use child library packages (nested directly inside of the parent’s package) Objects in Ada 95
Ada Example Package PERSON_PKG is type PERSON is tagged private; procedure DISPLAY(P : in out PERSON); private type PERSON is tagged record NAME : STRING(1..30); ADDRESS : STRING(1..30); AGE : INTEGER; end record; end PERSON_PKG; with PERSON_PKG; use PERSON_PKG; Package STUDENT_PKG is type STUDENT is new PERSON with record GRADE_POINT_AVERAGE : FLOAT; GRADE_LEVEL : INTEGER; end record; procedure DISPLAY (ST: in STUDENT); end STUDENT_PKG; Note:DISPLAY is being overridden fromperson_PKG P : PERSON; S : STUDENT; Pcw : PERSON’class; // classwide … // version of Person DISPLAY(P); // call Person’s display DISPLAY(S); // call Student’s display Pcw := P; DISPLAY(Pcw); // Person’s display Pcw := S; DISPLAY(Pcw); // Student’s display Ada’s mechanisms for objects is built on top of previous mechanisms and so is both awkward and less flexible than C++, and inconsistent as compared to Java/C#
Ruby • Like Smalltalk, everything in Ruby is an object and all computation is done via message passing • class definitions are executable, meaning that a class’ definition (structure or available methods) can change at run time • for instance, you could have code that modifies a class at run-time so that the class gains a new method • at run-time, a class is the union of all definitions that have been executed • all variables are reference variables to objects and all are typeless • instance variable names are denoted by starting with @ • instance variables are always private (accessor methods must be written if you want to provide external access to an instance variable) • methods default to public, but can be private or protected • accessor/mutator methods can be easily generated by using the shortcut functions attr_reader and attr_writer respectively • for instance: attr_reader :member1, :member2 will automatically generate a getter method to return the value of member1
More on Ruby • Deriving a subclass is done through < as in • class subclass < parentclass • access control to methods can be changed at the subclass level (for instance, if subclass above inherits method foo, subclass can alter the access control from public to private or protected) • The Ruby module is used to control encapsulation and namespaces • All variables are polymorphic (they are typeless and so only bound to a given object when assigned to point at it) and are therefore dynamically bound to methods • While Ruby is a pure OOPL (and therefore will satisfy some OO programmers), it is generally a weaker language than C++, Java or C# in that it lacks the ability to more tightly control • what is inherited and how (no multiple inheritance) • access control • other OOPL features like abstract classes
JavaScript • JavaScript – primarily use is for dynamic html pages • JavaScript is similar to Java in syntax and • JavaScript, like Java, uses two types of data • objects and primitive data types • but from there, the treatment of objects differs: • Java: statically typed language • JavaScript: dynamically typed language with all variables being reference variables (implicit pointers) much like in Lisp • JavaScript: does not have a class, objects are created dynamically without a formal definition • so JavaScript does not support inheritance or polymorphism • JavaScript does not require that variables be declared, but even if they are, they do not have to be typed • types are determined when the variable is assigned a value, and the type changes as the value assigned changes (much like Lisp) • any variable can reference any primitive type or any object
JavaScript Objects • Objects have a collection of properties • These properties are their data members and methods • each data member is a pair • the name and its current value • functions and methods are objects themselves and referenced by variables which point to them • to create an any object, new is used, creating a blank object • example: var my_object = new Object( ); • to add to an object, assignment statements are used • example: my_object.name = “Frank Zappa”; and my_object.occupation = “musician”; • objects can be nested by now doing my_object.education = new Object( ); and assigning my_object.education.college = “none”; • if access is made to a property that does not exist, the value undefined is returned • to remove from an object, use delete as in delete my_object.occupation;
Functions/methods are defined similar to properties: define the function function f( ) {…} assign a variable to point at the function var x = f constructors are defined as ordinary functions and called (if defined) whenever new is used example: function musician(style, instrument, age) {this.style = style; this.instrument = instrument; this.age = age);} my_object = new musician(“rock”, “guitar”, 37); JavaScript is like Java in that it contains most of the same control structures as Java the same arithmetic operators as Java and the same style of assignment statement many of the same String operations as Java JavaScript is not intended for large-scale applications so this primitive and flexible treatment of objects is satisfactory if you need objects in your script but if you want to do OOP, you would never choose JavaScript More on JavaScript
Implementing Objects • To implement an object, there needs to be at least two mechanisms available for easy construction and use: • a description of the data storage needed for the object • pointers to the object’s methods so that, if dynamically bound, the method call can quickly be made • Both of these can be captured by having the compiler generate a class instance record (CIR) at compile-time • any newly instantiated object uses the CIR as a template to generate the storage space needed for the object • the CIR could contain a pointer to all methods, but either the CIR would have to modified at run-time whenever the variable is altered to point at a subclass (if the variable is polymorphic), or we would have to disallow polymorphic variables – so we will use a different approach • instead, we might use a virtual method table for each class – this will differ for a subclass • the CIR then points at the VMT for the class it is currently assigned to, and this pointer changes whenever the variable is assigned to a different class
Example of CIRs public class A { public int a, b; public void draw( ) {…} public int area( ) {…} } public class B extends A { public int c, d; public void draw( ) {…} public void sift() {…} } This becomes more complicated if multiple inheritance is allowed, see figure 12.3 on page 563 to illustrate this in C++