<< Prev | - Up - | Next >> |
Functors are abstract datatypes that are concretely realized using chunks. In order to be able to safely distinguish functors from other chunks, a special feature is added to the representation: a chunk is a functor iff it has this feature. The feature, displayed here as <N:functorID>
is an Oz name. This is a common technique for implementing safe abstract datatypes, i. e. datatypes which cannot be forged/faked.
For example, we have seen before an implementation of a bag:
fun {NewBag}
C={NewCell nil}
in
bag(put : proc {$ X} L in {Exchange C L X|L} end
toList : fun {$} {Access C} end)
end
We might test whether a given value is a bag by looking at the label of the record, but that's a test which is easy to fool. Instead, we can create a private name, known only to the implementation of the abstract datatype:
local
CELL_ID = {NewName}
in
fun {NewBag}
C={NewCell nil}
in
{NewChunk
bag(
CELL_ID : unit
push : proc {$ X} L in {Exchange C L X|L} end
toList : fun {$} {Access C} end)}
end
fun {IsBag X}
{IsChunk X} andthen {HasFeature X CELL_ID}
end
end
NewChunk
is a library function which takes a record as an argument and returns a chunk with the same features. Why doesn't NewBag
return the record directly? Here is why:
declare R=foo(a:1) {Inspect {Arity R}}
By invoking Arity
, anyone could obtain all the features of the record, including CELL_ID
which was supposed to be private. By design, it is not possible to obtain the arity of a chunk, which makes chunk ideal for implementing type-safe abstract datatypes.
<< Prev | - Up - | Next >> |