Front page | perl.perl6.compiler |
Postings from July 2005
Definition of containers.
Thread Next
From:
Autrijus Tang
Date:
July 30, 2005 15:48
Subject:
Definition of containers.
Message ID:
20050730224910.GB5372@aut.dyndns.org
I have just checked in the container type part of the new PIL runcore:
http://svn.openfoundry.org/pugs/src/PIL.hs
In the Pugs directory, you can run a sample test with:
*PIL> tests
==> %ENV =:= %ENV;
True
==> %ENV =:= %foo;
False
==> untie(%ENV); my %foo := %ENV;
()
==> my %foo := %ENV;
Following is a semi-formal treatment for containers, directly transliterated
from the Haskell source.
Containers come in two flavours: Non-tieable and Tieable. Both are typed,
mutable references. There is no way in runtime to change the flavour.
data Container s a
= NCon (STRef s (NBox a))
| TCon (STRef s (TBox a))
A Non-tieable container is comprised of an Id and a storage of that type, which
can only be Scalar, Array or Hash. Again, there is no way to cast a Scalar
container into a Hash container at runtime.
type NBox a = (BoxId, a)
A Tieable container also contains an Id and a storage, but also adds a
tie-table that intercepts various operations for its type.
type TBox a = (BoxId, a, Tieable a)
The type of tie-table must agree with the storage type. Such a table
may be empty, as denoted by the nullary constructor "Untied". Each of
the three storage types comes with its own tie-table layout.
data Tieable a where
Untied :: Tieable a
TieScalar :: TiedScalar -> Tieable Scalar
TieArray :: TiedArray -> Tieable Array
TieHash :: TiedHash -> Tieable Hash
Binding only happens between containers of the same type:
bind :: Container s a -> Container s a -> ST s ()
Additionally, the compiler needs to compile ($x := @y) into ($x := \@y).
To bind a container to another, we first check to see if they are of the
same tieableness. If so, we simply overwrite the target one's Id,
storage and tie-table (if any):
bind (TCon x) (TCon y) = writeSTRef x =<< readSTRef y
bind (NCon x) (NCon y) = writeSTRef x =<< readSTRef y
To bind an non-tieable container to a tieable one, we implicitly remove
any current ties on the target, although it can be retied later:
-- %*ENV := %foo
bind (TCon x) (NCon y) = do
(id, val) <- readSTRef y
writeSTRef x (id, val, Untied)
To bind a tieable container to a tied one, we first check if it is
actually tied. If yes, we throw a runtime exception. If not, we
proceed as if both were non-tieable.
-- %foo := %*ENV
bind (NCon x) (TCon y) = do
(id, val, tied) <- readSTRef y
case tied of
Untied -> writeSTRef x (id, val)
_ -> fail "Cannot bind a tied container to a non-tieable one"
We can compare two containers for Id equivalence. If the container types
differ, this should never return True:
(=:=) :: Container s a -> Container s b -> ST s Bool
x =:= y = do
x_id <- readId x
y_id <- readId y
return (x_id == y_id)
Untie an non-tieable container is a no-op:
untie (NCon x) = return ()
For a tieable container, we first invokes the "UNTIE" handler, then set
its "tied" slot to Untied:
untie (TCon x) = do
(id, val, tied) <- readSTRef x
case tied of
Untied -> return ()
_ -> do
tied `invokeTie` UNTIE
writeSTRef x (id, val, Untied)
Thanks,
/Autrijus/
Thread Next
-
Definition of containers.
by Autrijus Tang