So far we have only had examples for type definitions where outer values and inner values were the same. For abstract datatypes, this is usually not the case: the inner value determines the internal representation of the datatype, and the outer value determines how the datatype looks like to its clients.
To examine abstract datatypes in Babel-17, let us define a new type orderedSet
which represents sets that are ordered by a given order:
module com.obua.util.orderedSet
private (orderedSet), ins
typedef orderedSet (leq, list) = nil
def empty leq = (leq, [])
def insert (orderedSet (leq, list), y) = (orderedSet (leq, ins (leq, list, y))
def toList (orderedSet (leq, list)) = list
def ins (leq, [], y) = [y]
def ins (leq, x::xs, y) =
if leq (y, x) then
if leq (x, y) then x::xs else y::x::xs end
else
x::(ins (leq, xs, y))
end
end
To use this module somewhere else in our code, we first import it via
import com.obua.util.orderedSet
Now we can play around with orderedSet
s:
val r = empty ((x, y) => x <= y)
for i in 1 to 10 do
r = insert r (random i)
end
toList r
Note that the only way for us to create values of type orderedSet
is by calling empty
and insert
, because of the declaration private (orderedSet)
. Note also that there is no other way to see the elements of an orderedSet
except via the toList
function.
There may be other types around which also have an empty
function to create empty versions of them. If we want to use these types together, it will be inconvenient to import the com.obua.util.orderedSet
module. It is then more convenient to import com.obua.util
and to write orderedSet.empty
and orderedSet.insert
. The only thing that is somewhat ugly is that now we have to refer to the type via orderedSet.orderedSet
. But we can remedy this by introducing the following rule into Babel-17: if the name of a type is the same as the name of the module it is defined in, then the name of the module can be used as a synonym for the name of the type. In our case this means that the type com.obua.util.orderedSet.orderedSet
is also accessible as com.obua.util.orderedSet
.
We would like to add the following features to orderedSet
- ordered sets should be comparable in a way that makes sense; right now, the expression
insert (empty leq, 1) == insert (empty leq, 2)
evaluates to true because both values have outer value nil
.
- Instead of
insert (r, x)
we just want to write r + x
.
- Instead of
toList r
it should be OK to write r.list
.
- We want to be able to write
for x in r do ... end
- We want to be able to write
with empty leq do
yield a
yield b
yield c
end
We can achieve this (and much more, see section 25.8 in the Babel-17 reference) by replacing the outer value nil
with an object that implements the desired functionality. Therefore we replace the line typedef orderedSet (leq, list) = nil
by the following:
typedef orderedSet (leq, mylist) = object
/* 1. */
def rank_ = mylist
/* 2. */
def plus_ x = insert (this, x)
/* 3. */
def list x = mylist
/* 4. */
def iterate_ =
match mylist
case [] => ()
case (x::xs) => (x, orderedSet (leq, xs))
end
/* 5. */
def collector_close_ = this
def collector_add_ x = this + x
def empty = orderedSet (leq, [])
end
Note that we reintroduced the keyword this
into the Babel-17 language, and also note that the above code only works if this
does not refer to the original object definition, but to the object definition that has been retyped as an orderedSet
. Applying the same reasoning to object inheritance, we can resolve our earlier beef with this
that led to the temporary removal of this
from Babel-17.