1 17-214 Principles of Software Construction: Objects, Design, and Concurrency Part 1: Design for reuse Behavioral subtyping Josh Bloch Charlie Garrod
1 17-214
PrinciplesofSoftwareConstruction: Objects,Design,andConcurrencyPart1:DesignforreuseBehavioralsubtypingJoshBloch CharlieGarrod
2 17-214
Administrivia
• Homework1gradedsoon• PleasesignandreturncollaborationpolicytoGradescope
• Readingduetoday:EffectiveJava,Items17and50– OptionalreadingdueThursday– RequiredreadingduenextTuesday
• Homework2dueSunday11:59p.m.
3 17-214
Requiredreadingparticipationquiz
• https://bit.ly/32x0vsU
4 17-214
DesigngoalsforyourHomework1solution?
Functionalcorrectness Adherenceofimplementationtothespecifications
Robustness Abilitytohandleanomalousevents
Flexibility Abilitytoaccommodatechangesinspecifications
Reusability Abilitytobereusedinanotherapplication
Efficiency Satisfactionofspeedandstoragerequirements
Scalability Abilitytoserveasthebasisofalargerversionoftheapplication
Security Levelofconsiderationofapplicationsecurity
Source: Braude, Bernstein, Software Engineering. Wiley 2011
5 17-214
OneHomework1solution…
classDocument{privatefinalStringurl;publicDocument(Stringurl){this.url=url;}publicdoublesimilarityTo(Documentd){…ourText=download(url);…theirText=download(d.url);…ourFreq=computeFrequencies(ourText);…theirFreq=computeFrequencies(theirText);returncosine(ourFreq,theirFreq);}…}
6 17-214
ComparetoanotherHomework1solution…
classDocument{privatefinalStringurl;publicDocument(Stringurl){this.url=url;}publicdoublesimilarityTo(Documentd){…ourText=download(url);…theirText=download(d.url);…ourFreq=computeFreq(ourText);…theirFreq=computeFreq(theirText);returncosine(ourFreq,theirFreq);}…}
classDocument{privatefinal…frequencies;publicDocument(Stringurl){…ourText=download(url);frequencies=computeFrequencies(ourText);}publicdoublesimilarityTo(Documentd){returncosine(frequencies,d.frequencies);}…}
7 17-214
UsingtheDocumentclass
Foreachurl:ConstructanewDocumentForeachpairofDocumentsd1,d2:Computed1.similarityTo(d2)…
• Whatistherunningtimeofthis,fornurls?
8 17-214
LatencyNumbersEveryProgrammerShouldKnowJeffDean,SeniorFellow,Google
PRIMITIVELATENCY:nsusmsL1cachereference0.5Branchmispredict5L2cachereference7Mutexlock/unlock25Mainmemoryreference100Compress1KbyteswithZippy3,0003Send1Kbytesover1Gbpsnetwork10,00010Read4KrandomlyfromSSD*150,000150Read1MBsequentiallyfrommemory250,000250Roundtripwithinsamedatacenter500,000500Read1MBsequentiallyfromSSD*1,000,0001,0001Diskseek10,000,00010,00010Read1MBsequentiallyfromdisk20,000,00020,00020SendpacketCA->Netherlands->CA150,000,000150,000150
9 17-214
Thepoint
• Constantsmatter• Designgoalssometimesclearlysuggestonealternative
10 17-214
DesigngoalsforyourHomework2solution?
Functionalcorrectness Adherenceofimplementationtothespecifications
Robustness Abilitytohandleanomalousevents
Flexibility Abilitytoaccommodatechangesinspecifications
Reusability Abilitytobereusedinanotherapplication
Efficiency Satisfactionofspeedandstoragerequirements
Scalability Abilitytoserveasthebasisofalargerversionoftheapplication
Security Levelofconsiderationofapplicationsecurity
Source: Braude, Bernstein, Software Engineering. Wiley 2011
11 17-214
KeyconceptsfromlastThursday
12 17-214
KeyconceptsfromlastThursday
• Exceptions• Specifyingprogrambehavior:contracts• Testing:
– Continuousintegration,practicaladvice– Coveragemetrics,statementcoverage
• Thejava.lang.Objectcontracts
13 17-214
Selectingtestcases
• Writetestsbasedonthespecification,for:– Representativecases– Invalidcases– Boundaryconditions
• Writestresstests– Automaticallygeneratehugenumbersoftestcases
• Thinklikeanattacker• Othertests:performance,security,systeminteractions,…
14 17-214
Methodscommontoallobjects
• Howdocollectionsknowhowtotestobjectsforequality?• Howdotheyknowhowtohashandprintthem?• TherelevantmethodsareallpresentonObject
– toString-returnsaprintablestringrepresentation– equals-returnstrueifthetwoobjectsare“equal”– hashCode-returnsanintthatmustbeequalforequalobjects,andislikelytodifferonunequalobjects
15 17-214
ThehashCodecontract
Wheneveritisinvokedonthesameobjectmorethanonceduringanexecutionofanapplication,thehashCodemethodmustconsistentlyreturnthesameinteger,providednoinformationusedinequalscomparisonsontheobjectismodified.Thisintegerneednotremainconsistentfromoneexecutionofanapplicationtoanotherexecutionofthesameapplication.– Iftwoobjectsareequalaccordingtotheequals(Object)method,thencallingthe
hashCodemethodoneachofthetwoobjectsmustproducethesameintegerresult.
– Itisnotrequiredthatiftwoobjectsareunequalaccordingtotheequals(Object)method,thencallingthehashCodemethodoneachofthetwoobjectsmustproducedistinctintegerresults.However,theprogrammershouldbeawarethatproducingdistinctintegerresultsforunequalobjectsmayimprovetheperformanceofhashtables.
16 17-214
ThehashCodecontractinEnglish
• Equalobjectsmusthaveequalhashcodes– IfyouoverrideequalsyoumustoverridehashCode
• Unequalobjectsshouldhavedifferenthashcodes– Takeallvaluefieldsintoaccountwhencalculatingit
• Hashcodemustnotchangeunlessobjectmutated– Useadeterministicfunctionofthefieldvalues
17 17-214
hashCodeoverrideexample
publicfinalclassPhoneNumber{privatefinalshortareaCode;privatefinalshortprefix;privatefinalshortlineNumber;@OverridepublicinthashCode(){intresult=17;//Nonzeroisgoodresult=31*result+areaCode;//Constantmustbeoddresult=31*result+prefix;//""""result=31*result+lineNumber;//""""returnresult;}...}
18 17-214
AlternativehashCodeoverrideLessefficient,butotherwiseequallygood!
publicfinalclassPhoneNumber{privatefinalshortareaCode;privatefinalshortprefix;privatefinalshortlineNumber;@OverridepublicinthashCode(){returnObjects.hash(areaCode,prefix,lineNumber);}...}
Aoneliner.NoexcuseforfailingtooverridehashCode!
19 17-214
Formorethanyouwanttoknowaboutoverridingobjectmethods,seeEffectiveJavaChapter2
20 17-214
Today
• Behavioralsubtyping– LiskovSubstitutionPrinciple
• Designforreuse:delegationandinheritance(Thursday)– Java-specificdetailsforinheritance
21 17-214
Recall:Theclasshierarchy
• TherootisObject(allnon-primitivesareObjects)• AllclassesexceptObjecthaveoneparentclass
– Specifiedwithanextendsclause:classGuitarextendsInstrument{...}
– Ifextendsclauseisomitted,defaultstoObject• Aclassisaninstanceofallitssuperclasses
Object
ToyInstrument
YoyoGuitar
22 17-214
Behavioralsubtyping
• e.g.,Compiler-enforcedrulesinJava:– Subtypescanadd,butnotremovemethods– Concreteclassmustimplementallundefinedmethods– Overridingmethodmustreturnsametypeorsubtype– Overridingmethodmustacceptthesameparametertypes– Overridingmethodmaynotthrowadditionalexceptions
Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.
Barbara Liskov
This is called the Liskov Substitution Principle.
23 17-214
Behavioralsubtyping
• e.g.,Compiler-enforcedrulesinJava:– Subtypescanadd,butnotremovemethods– Concreteclassmustimplementallundefinedmethods– Overridingmethodmustreturnsametypeorsubtype– Overridingmethodmustacceptthesameparametertypes– Overridingmethodmaynotthrowadditionalexceptions
• Alsoappliestospecifiedbehavior.Subtypesmusthave:– Sameorstrongerinvariants– Sameorstrongerpostconditionsforallmethods– Sameorweakerpreconditionsforallmethods
Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.
Barbara Liskov
This is called the Liskov Substitution Principle.
24 17-214
LSPexample:CarisabehavioralsubtypeofVehicle
abstractclassVehicle{intspeed,limit;//@invariantspeed<limit;//@requiresspeed!=0;//@ensuresspeed<\old(speed)abstractvoidbrake();}
classCarextendsVehicle{intfuel;booleanengineOn;//@invariantspeed<limit;//@invariantfuel>=0;//@requiresfuel>0&&!engineOn;//@ensuresengineOn;voidstart(){…}voidaccelerate(){…}//@requiresspeed!=0;//@ensuresspeed<\old(speed)voidbrake(){…}}
Subclass fulfills the same invariants (and additional ones) Overridden method has the same pre and postconditions
25 17-214
LSPexample:HybridisabehavioralsubtypeofCar
classCarextendsVehicle{intfuel;booleanengineOn;//@invariantspeed<limit;//@invariantfuel>=0;//@requiresfuel>0&&!engineOn;//@ensuresengineOn;voidstart(){…}voidaccelerate(){…}//@requiresspeed!=0;//@ensuresspeed<\old(speed)voidbrake(){…}}
classHybridextendsCar{intcharge;//@invariantcharge>=0;//@invariant…//@requires(charge>0||fuel>0)
&&!engineOn;//@ensuresengineOn;voidstart(){…}voidaccelerate(){…}//@requiresspeed!=0;//@ensuresspeed<\old(speed)//@ensurescharge>\old(charge)voidbrake(){…}}Subclass fulfills the same invariants (and additional ones)
Overridden method start has weaker precondition Overridden method brake has stronger postcondition
26 17-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//methods
}
classSquareextendsRectangle{Square(intw){ super(w,w);}
}
27 17-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//methods
}
classSquareextendsRectangle{Square(intw){ super(w,w);}
}
(Yes.)
28 17-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//methods
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
}
29 17-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//methods
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
}
(Yes.)
30 17-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//@requiresfactor>0;
voidscale(intfactor){ w=w*factor; h=h*factor;}
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
}
31 17-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//@requiresfactor>0;
voidscale(intfactor){ w=w*factor; h=h*factor;}
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
}
(Yes.)
32 17-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//@requiresfactor>0;
voidscale(intfactor){ w=w*factor; h=h*factor;}
//@requiresneww>0;voidsetWidth(intneww){ w=neww;}
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
}
33 17-214
IsthisSquareabehavioralsubtypeofRectangle?
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//@requiresfactor>0;
voidscale(intfactor){ w=w*factor; h=h*factor;}
//@requiresneww>0;voidsetWidth(intneww){ w=neww;}
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
}
← Invalidates stronger invariant (h==w) in subclass
classGraphicProgram{voidscaleW(Rectangler,intf){r.setWidth(r.getWidth()*f);}}
(Yes! But the Square is not a square…)
34 17-214
ThisSquareisnotabehavioralsubtypeofRectangle
classRectangle{//@invarianth>0&&w>0;inth,w;Rectangle(inth,intw){ this.h=h;this.w=w;}
//@requiresfactor>0;
voidscale(intfactor){ w=w*factor; h=h*factor;}
//@requiresneww>0;//@ensuresw==neww&&h==old.h;
voidsetWidth(intneww){ w=neww;}
}
classSquareextendsRectangle{//@invarianth>0&&w>0;//@invarianth==w;
Square(intw){ super(w,w);}
//@requiresneww>0;//@ensuresw==neww&&h==neww;@OverridevoidsetWidth(intneww){w=neww;h=neww;}}
35 17-214
Today
• Behavioralsubtyping– LiskovSubstitutionPrinciple
• Designforreuse:delegationandinheritance(Thursday)– Java-specificdetailsforinheritance