41
OO as a language for acm OO phrase Mental model of key concepts

OO as a language for acm l OO phrase l Mental model of key concepts

Embed Size (px)

Citation preview

  • OO as a language for acmOO phrase Mental model of key concepts

  • HistoryBirth of OO dates to Simula 6735 years agoSimula introduced all the fundamental OO concepts

  • HistorySimula (and OO) are rooted in abstract data types, separation of concerns, classification schemes dating from Aristotle, discrete event simulationFormal foundations in behavioral subtyping (LSP), object calculiAspect-oriented programming (modularity in more than one dimension)

  • ModulesClass Ada83 package spec that defines a record type & associated operationsObject instance of record type

    A

  • Data

    Attribute Record fieldpublic (+)private (-)protected (#)

    A

  • Code

    Operation subprogram specAlso public (+), protected (#), private (-)Method subprogram bodySignature, e.g. m (p: Integer)OverloadingConstructorDestructorA

  • Generics

    Template class generic packageAparameters

  • Phrase book, page 1 ClassAttributePublicPrivateProtectedOperationMethodSignature

  • Phrase book, page 2OverloadingConstructorDestructorClass instance = objectTemplate class

  • Callsx: A;x.m(i);

    Declared type

    Remaining arguments

    Target object

    Am(a: int)

  • Interfaces concrete classesInterfaceclient operations only

    Abstract classsome attributes some operations, some methodsConcrete classattributesmethodsA

    BC

  • Phrase book, page 3Declared typeTarget objectInterfaceAbstract classConcrete class

  • ContractsPreconditionPostconditionInvariant

    A

  • Interface inheritanceGeneralizationSuperinterface ASubinterface BAB

  • Interface inheritanceB inherits the operations of A It may also override them And may add operations of its own

    m (a: int) n (x: int) : float o () n (a: int): floatAB

  • Inheritance math

  • Liskov Substitution Principle n (x: int) : float

    n (x: int) : float

    Precondition of , must require the same or less than the precondition of Postcondition of , must deliver the same or more than the postcondition of We can test for this by inheriting all test cases

  • SubstitutabilityAll Bs are AsAnywhere we use an A, we use a BAB

  • Interface inheritanceA superinterface may also have more than one subinterface

    BAC

  • Phrase book, page 4Interface inheritanceSuperinterfaceSubinterface Overriding

  • Phrase book, page 5GeneralizationLiskov Substitution Principle (LSP)PreconditionPostconditionInvariant

  • Interface implementationRealizationClass B realizes interface AIn accordance with LSPAB

  • Multiple implementationsMore than one class may realize a given interface

    Partial implementation by abstract subclass

    Full implementation by concrete subclass

    ABCD

  • Implementation inheritanceSuperclassSubclassStill in accordance with LSP

    CD

  • Implementation inheritanceA superclass may have more than one subclass

    DCE

  • Polymorphism x: A = new B;x.m(i);

    Variable may reference any object of its declared type or any of its subtypes (polymorphism)Run time type of an object is set when it is created, and never changes

    Run-time typeDeclared type

    A BCDm(a: int)

    m(a: int)m(a: int)

  • Polymorphism for each display element element.draw()end

    DisplayElementimportance : int xOrigin : CoordinateValue yOrigin : CoordinateValue draw() highlight() hide() NonTextualElement highlight() PrimitiveNonTextualElement draw() highlight() AltitudeTape width : GraphicsDistance height : GraphicsDistance colorScheme : ColorScheme displayedValue : Altitude draw() getDisplayedValue() : Altitude setDisplayedValue(altitude : Altitude) AirspeedTape draw() getDisplayedValue() : Airspeed setDisplayedValue(airspeed : Airspeed) Compass radius : GraphicsDistance colorScheme : ColorScheme displayedValue : Heading draw() getDisplayedValue() : Heading setDisplayedValue(heading : Heading) TextualElement width : GraphicsDistance height : GraphicsDistance displayedValue : String draw() highlight() getDisplayedValue() : String setDisplayedValue(string : String) width : GraphicsDistanceheight : GraphicsDistance colorScheme : ColorSchemedisplayedValue : Altitude

  • Dynamic dispatchPolymorphism + multiple methods dispatchAll display elements have a draw operationWe need to call the right implementation of drawRight = the one that matches the run time type associated with the object when it was created

  • Dynamic DispatchCall to draw is semantically equivalent to a case statementfor each display elementcase of display elements run time typecase (AltitudeTape)call AltitudeTape.draw()case (AirspeedTape)call AirspeedTape.draw()case (Compass)call Compass.draw() case (PrimitiveNonTextualElement)call PrimitiveNonTextualElement.draw()case (TextualElement)call TextualElement.draw()endend

  • Dynamic DispatchIn general, method selection is a function of the run time type and the method signatureConceptually there is a single dispatch routine for all calls containing a pair of nested case statementscase of target objects run time type - (1)case ()case of method signature - (2)case ()call defined by -- (3)endendIn practice, calls to this universal dispatch method are inlined at the point of call

  • Dynamic DispatchTypically implemented using dispatch tablesSmall, fixed overheadAt the point of call: (1) get the dispatch table associated with the target object, (2) index it by a number associated with the method signature, and (3) invoke the method

    dispatch table for typetargetObjectrun time type

  • Phrase book, page 6RealizationPolymorphismDeclared typeRun-time typeDynamic dispatchDispatch table

  • Multiple interface inheritance

    More than one superinterfaceInherited elements represent only specsNo code or dataBAC

  • Multiple implementation inheritance

    More than one superclassInherited elements represent code and data in addition to specsInherited elements may reference one anotherBAC

  • Phrase book, page 7Multiple interface inheritanceMultiple implementation inheritance

  • Whole-part associationsAggregationXYCompositionWhole PartXY

  • Delegation ABDelegatem(a: int)m(a: int)Delegation, e.g., of all calls to B::m(int) to A::m(int)Do it yourself inheritance

  • Inheritance + delegation

    Single inheritance + delegationInheritance of implementation from one superclassDelegation to the implementation of the otherBAC

  • Phrase book, page 8AssociationAggregationCompositionDelegation

  • Other related conceptsUse casesPatternsAspects, join points, aspect weaving

  • Primary advantages of OOImproved coupling/cohesionIsolation of likely future changesProduct familiesReuse - of specifications, code, test casesExplicit specification of when one component is substitutable for anotherExplicit criteria for testing this (LSP)

    Basic introduction to key OO concepts and terms.The intent is to provide a phrase book for those in the audience more familiar with DO-178B and Ada83 than OO.And a mental model of OO concepts, cast in more familiar and fundamental terms.The terminology and graphical notation are based on the Object Management Groups Unified Modeling Language (UML).

    But first a bit of history.OO is old hat. Simula 67, now 35 years old, introduced all the fundamental concepts:Classes, encapsulation, inheritance, polymorphism and dynamic dispatch, etc.

    Simula also has a history.Like Ada, it is rooted in work on abstract data types.In Parnas separation of concerns.In classification schemes dating from Aristotle.And in discrete event simulation (accounting for its name).

    OO has formal foundations based on theories of behavioral subtyping (Liskov and Wing, Leavens, Castagna) and the object calculi of Abadi and Cardelli.

    More recently, OO has spawned work in Aspect-Oriented Programming (AOP), which supports the encapsulation of cross cutting strategies and policies. Modularity in more than one dimension.A code level representation of design patterns.An effective means of representing sets of related features (use cases).And organizing OO software in a manner that makes it easier to analyze.

    Class Ada83 package spec defining a single record type and a set of related operations.The operations must each have a parameter or return value of the record type.As a matter of good practice, the record type should be private, although this is not required.Making the type private also provides control over assignment and equality, which may be required.

    One difference between Ada and the other OO languages of prime interest (C++ and Java) is that Ada is all or nothing with respect to data hiding.Either all the data associated with the class is private, or all is public.Attribute record field.The values of an objects attributes collectively define its state.ButNo variant records. Variants are defined as subclasses.

    Public = in the visible part of the package spec (UML prefix +)Private = in the private part (UML prefix -)Protected = not public, but visible to subclasses (UML prefix #)

    Java and C++ allow the visibility of each attribute (record field) to be specified individually (individually wrapped as it were).

    Operation = subprogram specification.Also public (in the spec), private (in the package body), or protected (no Ada83 equivalent).Method = subprogram body.Signature = name + parameter types.May/may not include return type, depending on language.Implicit first parameter (self or this), in OO languages other than Ada95 (where all parameters are explicit).

    Overloading is possible, i.e. same name, different signatures.Overloading is complicated by implicit type conversion, e.g. in C++.Constructor = special type of method, always called immediately after object allocated, guarantees initialization.Destructor, conversely, is always called immediately before object deallocated.Template class = generic package.

    We are at roughly the Ada83 package level. What is termed object-based (rather than object-oriented).Although the terminology is different, there is a direct mapping to a subset of Ada83. Ada83 with restricted version of package: single record type, no variant records, associated set of subprograms.

    Overloading as in Ada83.But constructors and destructors are new.Generics = templates.

    But, so far, no pure interface specifications or abstract classes. [Ada83 does support specs with no corresponding bodies, but only in a limited way, i.e. no abstract operations. These show up only in Ada95]No subclasses or inheritance. No polymorphism or dynamic dispatch.The declared type is the type of an object at its point of declaration.Most OO languages use a dot notation for calls.Format = TargetObject.operation(remainingArguments);The target object is distinguished from the remaining arguments because it plays a distinct role with regard to dynamic dispatch (dynamic binding).The dot notation is used by Ada95 for tasks, protected types, but not ordinary packages.Interface Ada package spec without a package body. Optionally marked with stereotype .Provides a type declaration but no definition (no attributes). Only client operation specifications, i.e. public operations.Note: In UML, an operation with a body is a method. While in Ada we talk of operation specifications (operations) and operations with bodies (methods).

    Abstract class Ada package with some method definitions or record field definitions.Class name appears in italics (in UML).Can be completely abstract, like an interface, but does not have to be.Operations and attributes need not be public, and attributes (as a matter of style) typically are not.

    Concrete class Ada83 package. Full definition of type and all methods.

    A declared type can be any of the three.But we can only create instances (objects) from concrete classes.Declared type has the expected meaning.It refers to the declared types of variables, attributes, and parameters.

    Calls are typically of the form TargetObject.operation(remainingArguments), where the target object (whose state may be affected by the operation) appears separate from the remaining arguments.

    An interface is a class that defines only a set of public operations. It defines no implementation of any kind.A concrete class provides a full implementation, including all data structures (attributes) and code (methods).An abstract class lies in between. It may be completely abstract, but typically provides at least a partial implementation.

    We can only create objects as instances of concrete classes.We, however, can declare variables, attributes, and parameters whose declared type is an interface or abstract class.OO permits the local proof of key system properties, invariants.Precondition = what is expected of client.Postcondition = what is expected of implementation.For example, size of queue > 0 before dequeue. If true, return oldest element.Invariant = always true from clients perspective.Assuming synchronized access, this means before and after every method call, i.e., the points at which the state of the object may be observed.For example, windows of display always in priority order, front to back. Number of elements of a bounded data structure always in bounds.For classes, constructor, pre = space allocated, post = invariant.Other operations, invariant is a part of pre and post. Work together to maintain invariant.Destructor, pre = invariant.For interfaces, no constructor or destructor but still pre/post/invariant. Invariant specifies what (yet to be defined constructors) must do.Formal spec = basis for test cases.No extra work, if not too formal, i.e. if only enough to generate test cases.Formal specs and invariants are not just for individual classes, but for compositions of classes, subsystems, and complete systems.We now move on to more distinctly OO concepts, but remain within the conceptual bounds of Ada83.Interface inheritance Ada83 derived type.UML symbol represents generalization (subtyping), a.k.a. isa.Implies substitutability.Open headed arrow points to the more general or the two interfaces.

    Note: We omit the use of stereotypes for interfaces in diagrams (as permitted by UML). The distinction between interfaces, abstract classes, and classes is still present in the model.

    Now lets add some operations to the diagram.Different shapes represent different signatures, color coded by class of origin.This is not UML, just a convenient way to abbreviate the signatures and indicate where they are defined.The rest of the notation, however, is strictly by the book.

    B inherits the operations of A.It may override some of them, providing its own specialized version of them.And it may define additional operations.Column 1. Operation defined by class, not inherited.Column 2. Operation not defined by class, inherited.Column 3. Operation overridden, must be compatible.Compatible in terms of the language rules (for signatures).And compatible in terms of its behavior (if we insist that subclasses to be subtypes, in accordance with LSP).This is the interesting case.Compiler understands only signatures.Basis for matching calls to methods.But not enough to ensure substitutability.In addition to signatures, we must be concerned with actual behavior (pre/post).Liskov substitution principle (LSP) defines rules for substitutability.Think of these in terms of promises to the client, a contract.Subclass/subinterface cannot break the promises made to the client by its superclass/superinterface.We test for this by running the supers test cases against the subclass (for every concrete class in the system).Generalization in UML implies LSP, as known as behavioral subtyping.In terms of our previous example.This is common, and causes no problems.Both a Dog and a Cat, for instance, may be classified as Mammals.Or a PrimaryFlightDisplay (PFD) and a MultiFunctionDisplay (MFD) may be classified as AvionicsDisplays. We are now at the Ada83 package level + calls + derived types.These are the formal relationships expected even for Ada83 derived types, but especially in OO systems where substitutability plays a large role.Here we have a figure similar to the previous.But broken line = no inheritance.Still the triangular arrow implies generalization, LSP.Similar to relationship between Ada package spec and body, but more flexible (as we will see in the next slide).Unlike Ada83, more than one implementation of the same specification.Implementing classes may also be only partial implementations (abstract classes).Although ultimately we must define everything (define leaf classes to be concrete classes) for the hierarchy to be useful.For example, as in the relationship between C and D which we will discuss in the next slide.It, however, is not necessary for all leaf classes to be concrete for the hierarchy to be correct or well formed.Triangular arrow head implies LSP, as before.Inherited elements are now methods and attributes, in addition to operations.Implementation inheritance is complicated by the fact that the inherited elements reference one another.Methods may call inherited methods.Methods may reference inherited attributes.Again, this is common, and causes no problems.Interface vs. class = what vs. how.Can assign an instance of any concrete subclass to a variable declared as a more general type.Same variable may reference objects of different run-time types at different times.Although the same variable may reference objects of different types (polymorphism), the run time class of a given object is set when the object is created and never changes.Or for each hardware device, diagnose it.Generalization over a group of objects at a given level of abstraction.Different levels of abstraction for different clients.Given that the run time type of an object never changes.If the selection of the method to be called is based on the run time type, then the behavior of the object is also fixed.Replacing the call to draw with a case statement.With a case for each subclass of the declared type that implements the method.Dispatch in three steps.To get the single case statement given in the previous slide, we inline the dispatch routine at the point of call.We then optimize the result, accounting for the fact that we know the method signature at the point of call, but not the run time type of the target object.This allows us to eliminate step 2.With this approach, we reduce the amount of code associated with each call at the point of call.The code sequence is identical for every call, although the method index may be different.There is a small (but not significant) performance cost (associated with fetching the dispatch table address from the object).Polymorphism (from the Greek), means many shapes. It refers to the ability of a variable to reference instance of different subclasses of its declared type.Declared type, as before, associated with variables, attributes, parameters.Run-time type is associated with an object at the time it is created. Never changes.Dynamic dispatch refers to selection of the method associated with the run time type of an object referenced by a variable with a more general declared type.Typically implemented by associating a dispatch table with each object.Flow = against the arrow, but from more than one source.Flow = against the arrow, but from more than one source.Interface inheritance involves only specifications of client operations.Implementation inheritance involves data (attributes), code (methods), and associations (references to other objects). Inherited elements may reference one another.Association = run time relationship, usually implemented as a pointer, or a collection of pointers.In OO modeling, whole-part relationships are second in importance only to subtype/subclass relationships.The two are also related (through the use of delegation).Similar UML notation for aggregation and composition: Diamond filled in to indicate composition.Aggregation: lifetime of the part not tied to that of the whole. Components may be shared.Composition: Lifetime of the part tied to the whole. Components are not shared.Delegation = an alternative to inheritance.Delegates to replaces inherits from.All calls to a given method (e.g., m) of a class (e.g., A) are redirected to an equivalent method of an associated class (e.g., B).Forwarding of calls is explicitly coded (in current OO languages).Typically delegate to components.But may delegate to any associated object, or may have aggregation/composition without delegation.In contrast to inheritance, we can change the delegate at run time, i.e. delegation is more dynamic than inheritance.Components (delegates) may have access to attributes of composite, or they may not.A design choice.

    Inheritance from one superclass, delegation to the other.Avoids multiple inheritance.But requires hand coding of dispatch to delegate.Delegation not supported well by current languages.Java inner classes get us half way there, but only half way.Aggregation: lifetime of the part not tied to that of the whole. Components may be shared.Composition: Lifetime of the part tied to the whole. Components are not shared.Delegation. Calls to a given method are forwarded to an associated object rather than executed as part of the class.Requirements use cases describe required interactions between users and the system, at an abstract level.Each use case is specified in terms of a precondition (initial assumed state), a postcondition (desired outcome), and a sequence of interactions between participants (users, system components, and entities in the environment) that connect the two.Assumptions (which hold throughout execution of the use case) and guarantees (which must be maintained by the participants) can also be specified formally.

    Patterns describe well known solutions to common analysis and design problems. Inspired by the architectural patterns of Christopher Alexander (for the design of buildings and towns). Used by the AVSI Guide and workshop position papers to describe acceptable use of OO features in DO-178B certifiable systems.

    OO defines modularity based on isolation of likely future changes.Aspects describe cross cutting strategies and policies involving multiple objects. Can be used to represent use cases and patterns at the code level. Aspects are like classes, whose methods are woven with the core functionality of the system at specified join points.Weaving is typically done at a source code level.Allow us to avoid problems related to distribution of features across many classes (a common complaint with respect to OO decomposition)..