440 likes | 840 Views
Composite Objects. Learning Outcomes. At the end of this lecture you should be able to:. Identify when it is appropriate to use a composite object type Use the composite object operators ( make , selection and mu ) Add an invariant to a composite object type
E N D
Composite Objects Learning Outcomes At the end of this lecture you should be able to: • Identify when it is appropriate to use a composite object type • Use the composite object operators (make, selection and mu) • Add an invariant to a composite object type • Use the composite object type to help model systems in VDM-SL • Use a let…in clause to simplify expressions in VDM-SL
Composite Types So far, we have always associated a single type with each item of data in our VDM specifications. temp: robot: Status permission: Aircraft-set There will be occasions, however, when you need to associate more than one type with an object. We call such a type a composite object type in VDM-SL.
Defining Composite Object Types To define a type to be composite we use a composite type definition. TypeName :: fieldname1 : Type1 fieldname2 : Type2 :
The Time Type Assume that a time value consists of an hour, minute and second value. We can define the following type: Time :: hour : minute : second : This Time type can now be used like any other type in your specification importantTimes: Time-set
The make function The most important composite object operator is the make function that creates a new object of a given composite type. mk-CompositeObjectTypeName (parameter list) Returning to the Time example: someTime = mk-Time ( ) 16 , 20 , 44
Adding invariants to composite objects Not all combinations of hour/minute/time are valid. For example: strangeTime = mk-Time (36, 20, 44) Solution? add an invariant to the type definition: Time:: hour: minute: second: inv mk-Time (h, m, s) h< 24 m < 60 s < 60
Composite object selectors We can refer to a particular field of a composite object by using a selector operator. Individual fields are selected by the dot operator '.' followed by the name of a field. For example: someTime.minute = 20 someTime.hour = 16
The mu function The mu function returns one composite object from another but with one or more fields changed. For example, to change the hour of a particular time we may use the function as follows: newTime = (someTime, hour 15) More than one field may be changed in a mu function. For example thisTime = (someTime, minute 0, second 0) thisTime = mk-Time (someTime.hour, 0, 0)
The surface of a disk consists of a collection of blocks tracks sector block
The DiskScanner class DiskScanner damagedBlocks: Block [*] addBlock(Integer, Integer) removeBlock (Integer, Integer) isDamaged(Integer, Integer): Boolean getBadSectors(Integer): Integer [*]
Analysing the Block type further A block consists of a track and a sector number. Block track: Integer sector: Integer
Specifying the data model in VDM-SL types stateDiskScanner of damagedBlocks: initmk-DiskScanner (dB) end Block : : track: sector: Block-set dB = { }
damagedBlocks = { mk-Block (trackIn,sectorIn)} The addBlock operation addBlock ( ) ext pre post trackIn: , sectorIn: wr damagedBlocks: Block-set mk-Block (trackIn,sectorIn) damagedBlocks
damagedBlocks = \ { mk-Block (trackIn,sectorIn)} The removeBlock operation removeBlock ( ) ext pre post trackIn: , sectorIn: wr damagedBlocks: Block-set mk-Block (trackIn,sectorIn) damagedBlocks
The isDamaged operation isDamaged ( ) ext pre post trackIn: , sectorIn: query: rd damagedBlocks: Block-set TRUE query mk-Block (trackIn,sectorIn) damagedBlocks
The getBadSectors operation getBadSectors ( ) ext pre post trackIn: list: -set rd damagedBlocks: Block-set TRUE bdamagedBlocks { | } b.sector ? ? list = b.track= trackIn ?
running terminated new ready blocked A process management system timeout admit terminate dispatch block wakeup
The ProcessManagement class ProcessManagament running: String waiting: Process[*] admit(String) dispatch() timeOut() block() wakeUp(String) terminate()
<<enumeration>> Status READY BLOCKED Process id: String status: Status Analysing the types A process consists of an id and status The status of a process is either ready or blocked.
Specifying the types in VDM-SL types String = Char* Status = <READY> | <BLOCKED> : String Process :: id : Status status
Specifying the state in VDM-SL stateProcessManagementof running waiting invmk-ProcessManagement (run, wait) ( ) ( ) initmk-ProcessManagement (run, wait) end : [String] : Process* i indswait wait(i).id = run run = nil no waiting id should match the running id i,j inds wait i j wait(i).id wait(j).id the ids in the waiting queue should be unique run = nilwait = [ ]
Specifying a findPos function findPos(qIn : Process*, idIn : String) pos : prepelems qIn p.id = idIn post qIn(pos).id = idIn
Specifying a findNext function qIn : Process* findNext() pre post pos : pelems qIn p.status = <READY> qIn(pos).status = <READY> i {1,…,pos-1}qIn(i).status = <READY>
Specifying a remove function remove(qIn : Process*, posIn : ) qOut : Process* preposIninds qIn post qOut = qIn(1,…, posIn-1) ^ qIn(posIn+1,…,len qIn)
waiting = ^ [mk-Process(idIn, <READY>)] The admit operation admit( idIn: String) ext pre post waiting: Process* wr rd running: [String] (running = nilidIn running ) p elems waiting p.id idIn
running = (findNext( )) .id waiting = remove( , findNext( )) The dispatch operation dispatch() ext pre post running: [String] wr wr waiting: Process* running = nil pelems waiting p.status = <READY>
waiting = ^ [mk-Process( , <READY>)] The timeOut operation timeOut() ext pre post wr running: [String] wr waiting: Process* running nil running = nil
waiting = ^ [mk-Process( , <BLOCKED>)] The block operation block() ext pre post wr running: [String] wr waiting: Process* running nil running = nil
waiting = † {findPos( , idIn) mk-Process(idIn, <READY>)} The wakeUp operation wakeUp( idIn: String) ext pre post wr waiting: Process* waiting(findPos(waiting, idIn)).status = <BLOCKED> idInelems waiting
The terminate operation terminate() ext pre post running: [String] wr running nil running = nil
The let…in clause To improve readability expressions, local names can be given to sub-expressions and these names can then be used in place of the longer sub-expression. These local names are created in let…in clauses. A let…in clause takes the following general form let name = sub-expression inexpression(name)
postrunning = ( findNext( ) ).id waiting = remove( , findNext( )) post letnext = findNext( ) in running = ( next ) .id waiting = remove( , next) Re-writing postcondition of dispatch
post waiting = † {findPos( , idIn) mk-Process(idIn, <READY>)} post let pos = findPos( , idIn) in let wakeProcess = mk-Process(idIn, <READY>) in waiting = † {pos wakeProcess } Nested let…in clauses