composite objects learning outcomes at the end of this lecture you should be able to: identify when...
TRANSCRIPT
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
fieldname2
:
: Type1
: Type2
The Time Type
Assume that a time value consists of an hour, minute and second value. We can define the following type:
This Time type can now be used like any other type in your specification
Time :: hour
minute
second
: : :
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)
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: Integersector: Integer
Specifying the data model in VDM-SL
types
state DiskScanner ofdamagedBlocks:
init mk-DiskScanner (dB)
end
Block : : track: sector:
Block-set
dB = { }
addBlock ( )
ext
pre
post
The addBlock operation
trackIn: , sectorIn:
damagedBlocks: Block-setwr
cksdamagedBlodamagedBlocks = { mk-Block (trackIn, sectorIn)}
mk-Block (trackIn, sectorIn) damagedBlocks
removeBlock ( )
ext
pre
post
The removeBlock operation
trackIn: , sectorIn:
damagedBlocks: Block-setwr
cksdamagedBlodamagedBlocks = \ { mk-Block (trackIn, sectorIn)}
mk-Block (trackIn, sectorIn) damagedBlocks
isDamaged ( )
ext
pre
post
The isDamaged operation
trackIn: , sectorIn: query:
damagedBlocks: Block-setrd
query
mk-Block (trackIn, sectorIn) damagedBlocks
TRUE
getBadSectors ( )
ext
pre
post
The getBadSectors operation
trackIn: list: -set
damagedBlocks: Block-setrd
list = { | }
? ?
?
b damagedBlocks
b.track = trackInb.sector
TRUE
A process management system
blockwakeup
timeout
dispatchterminateadmit
new ready terminatedrunning
blocked
The ProcessManagement class
ProcessManagament
running: String
waiting: Process[*]
admit(String)
dispatch()
timeOut()
block()
wakeUp(String)
terminate()
Analysing the types
Process
id: Stringstatus: Status
A process consists of an id and status
<<enumeration>>Status
READYBLOCKED
The status of a process is either ready or blocked.
Specifying the types in VDM-SL
types
String = Char*
= <READY> | <BLOCKED>Status
Process :: id : Stringstatus : Status
Specifying the state in VDM-SL
state ProcessManagement ofrunningwaiting
inv mk-ProcessManagement (run, wait) ( )
( )
init mk-ProcessManagement (run, wait) end
: [String]: Process*
run = nil wait = [ ]
run = nili inds wait wait(i).id = run no waiting id should match the running id
i,j inds wait i j wait(i).id wait(j).idthe ids in the waiting queue should be unique
Specifying a findPos function
findPos(qIn : Process*, idIn : String) pos :
pre p elems qIn p.id = idIn
post qIn(pos).id = idIn
Specifying a findNext function
findNext( )
pre
post
qIn : Process* pos :
qIn(pos).status = <READY>
i {1,…,pos-1} qIn(i).status = <READY>
p elems qIn p.status = <READY>
remove(qIn : Process*, posIn : ) qOut : Process*
pre posIn inds qIn
post qOut = qIn(1,…, posIn-1) ^ qIn(posIn+1,…,len qIn)
Specifying a remove function
admit( idIn: String)
ext
pre
post
The admit operation
waiting: Process*wr
running: [String]rd
waitingwaiting = ^ [mk-Process(idIn, <READY>)]
(running = nil idIn running )
p elems waiting p.id idIn
dispatch()
ext
pre
post
The dispatch operation
running: [String]
waiting: Process*
wr
wr
waitingwaitingrunning = (findNext( )) .id
waiting waiting waiting = remove( , findNext( ))
running = nil
p elems waiting p.status = <READY>
timeOut()
ext
pre
post
The timeOut operation
running: [String]
waiting: Process*
wr
wr
waitingrunning
waiting = ^ [mk-Process( , <READY>)]
running = nil
running nil
block()
ext
pre
post
The block operation
running: [String]
waiting: Process*
wr
wr
waitingrunning
waiting = ^ [mk-Process( , <BLOCKED>)]
running = nil
running nil
wakeUp( idIn: String)
ext
pre
post
The wakeUp operation
waiting: Process*wr
waitingwaiting
waiting = † {findPos( , idIn)
mk-Process(idIn, <READY>)}
waiting(findPos(waiting, idIn)).status = <BLOCKED>
terminate()
ext
pre
post
The terminate operation
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
in expression(name)
Re-writing postcondition of dispatch
post running = ( findNext( ) ).id
waiting = remove( , findNext( ))
waiting waiting
waiting waiting
post let next = findNext( )
in running = ( next ) .id
waiting = remove( , next)
waiting
waiting
waiting
Nested let…in clauses
post let pos = findPos( , idIn)
in let wakeProcess = mk-Process(idIn, <READY>)
in waiting = † {pos wakeProcess }
waiting
waiting
post waiting = † {findPos( , idIn)
mk-Process(idIn, <READY>)}
waitingwaiting