From: Nick Roberts <nickroberts@blueyonder.co.uk>
Subject: Re: Persistence of limited tagged types
Date: Wed, 09 Apr 2003 11:05:36 +0100
Date: 2003-04-09T11:05:36+01:00 [thread overview]
Message-ID: <oprncwzmkubqmqul@news.cis.dfn.de> (raw)
In-Reply-To: <oprm9kpdkkbqmqul@news.cis.dfn.de>
I hope it won't be taken too amiss that a post a piece of code here.
This little test program is to illustrate the how the 'lifetime' concept (a
fairly significant concept in computer science these days) applies to the
persistence of 'live' objects.
A live object is an object which parallels (analogises, models) some
conceptual or real-world entity, and therefore cannot validly be copied
(unless it is to model the parallel entity also being duplicated). Live
objects, therefore (to my mind) correspond, in Ada terms, to a limited type
(hierarchy).
Live objects, because they cannot just be copied, cannot be directly
archived or restored, but must first be properly deactivated and
reactivated, by specific operations that have the correct specific logic
for each live (limited) type.
In my example 'lifetime' package I have declared roots for the live objects
(Root_Object) and for a co-hierarchy of their mothballed equivalents
(Root_Parcel). To deactivate a live object you must call Mothball, and to
reactivate one you must call Reinstate. (These names may not be the most
appropriate, but they do at least suggest their function.)
There are many other aspects to the lifetime concept, but the conversion
between different forms of an object is one of the basic aspects.
----------------------------------------------------------------------
-- Test out lifetime and persistence concepts in Ada.
with Ada.Streams.Stream_IO, Ada.Text_IO, Ada.Unchecked_Deallocation;
use Ada.Streams.Stream_IO, Ada.Text_IO;
procedure Persist1 is
------------------------------------------------------------
package Lifetime is
type Root_Object is abstract tagged limited private;
type Object_Ref is access Root_Object'Class;
type Root_Parcel is abstract tagged private;
type Parcel_Ref is access Root_Parcel'Class;
procedure Mothball (Object: in out Root_Object;
Parcel: out Parcel_Ref) is abstract;
procedure Reinstate (Object: out Object_Ref;
Parcel: in Root_Parcel) is abstract;
private
type Root_Object is abstract tagged limited null record;
type Root_Parcel is abstract tagged null record;
end Lifetime;
------------------------------------------------------------
package Banking is
type Active_Account is new Lifetime.Root_Object with private;
type Dead_Account is new Lifetime.Root_Parcel with private;
function New_Account (Initial_Balance: in Integer) return
Lifetime.Object_Ref;
function Current_Balance (Account: in Active_Account) return Integer;
procedure Mothball (Active: in out Active_Account;
Dead: out Lifetime.Parcel_Ref);
procedure Reinstate (Active: out Lifetime.Object_Ref;
Dead: in Dead_Account);
private
type Active_Account is new Lifetime.Root_Object with
record
Balance: Integer;
end record;
type Dead_Account is new Lifetime.Root_Parcel with
record
Balance: Integer;
end record;
end Banking;
------------------------------------------------------------
package body Banking is
function New_Account (Initial_Balance: in Integer) return
Lifetime.Object_Ref is
Account: Lifetime.Object_Ref := new Active_Account;
begin
Active_Account(Account.all).Balance := Initial_Balance;
return Account;
end;
function Current_Balance (Account: in Active_Account) return Integer
is
begin
return Account.Balance;
end;
procedure Mothball (Active: in out Active_Account;
Dead: out Lifetime.Parcel_Ref) is
begin
-- here need to be actions to suspend the Active account
Dead := new Dead_Account'( Lifetime.Root_Parcel with Balance =>
Active.Balance );
end;
procedure Reinstate (Active: out Lifetime.Object_Ref;
Dead: in Dead_Account) is
begin
Active := new Active_Account;
Active_Account(Active.all).Balance := Dead.Balance;
-- here need to be actions to reactivate Active account
end;
end banking;
------------------------------------------------------------
type Object_Array is
array (Positive range <>) of Lifetime.Object_Ref;
procedure Free is
new
Ada.Unchecked_Deallocation(Lifetime.Root_Object'Class,Lifetime.Object_Ref);
procedure Save (File: in out Ada.Streams.Stream_IO.File_Type;
Item: in out Object_Array) is
Temp: Lifetime.Parcel_Ref;
begin
for i in Item'Range loop
Lifetime.Mothball(Item(i).all,Temp);
Free(Item(i)); -- make sure it is deallocated
Lifetime.Root_Parcel'Class'Output(Stream(File),Temp.all);
end loop;
end Save;
procedure Load (File: in out Ada.Streams.Stream_IO.File_Type;
Item: out Object_Array;
Last: out Natural) is
i: Natural := Item'First-1;
begin
while not End_of_File(File) loop
declare
subtype LRPC is Lifetime.Root_Parcel'Class;
Temp: Lifetime.Parcel_Ref := new LRPC'(LRPC'Input(Stream(File)))
;
begin
i := i+1;
Lifetime.Reinstate(Item(i),Temp.all);
end;
end loop;
Last := i;
end Load;
Accounts: Object_Array(1..10);
Datafile: Ada.Streams.Stream_IO.File_Type;
Last: Natural;
begin
Put("Creating test array ...");
for i in Accounts'Range loop
Accounts(i) := Banking.New_Account(i);
end loop;
Put(" Done.");
New_Line;
Put("Saving test array ...");
Create(Datafile,Out_File,"TESTDAT1.BIN");
Save(Datafile,Accounts);
Close(Datafile);
Put(" Done.");
New_Line;
Put("Reloading test array ...");
Open(Datafile,In_File,"TESTDAT1.BIN");
Load(Datafile,Accounts,Last);
Close(Datafile);
Put(" Done.");
New_Line;
Put("Checking test array ...");
if Last /= Accounts'Last then
Put(" *** FAILED!");
goto Final_Stuff;
end if; for i in Accounts'Range loop
if Banking.Current_Balance(Banking.Active_Account(Accounts(i).all))
/= i then
Put(" *** FAILED!");
goto Final_Stuff;
end if;
end loop;
Put(" Done. Success!");
<<Final_Stuff>>
New_Line;
end;
----------------------------------------------------------------------
Based on this idea, persistence of a live (limited) type will be done in
two steps: the deactivation (mothballing) of the live type (derived from
Root_Object) to get its storable equivalent (derived from Root_Parcel), and
reactivation (reinstatement) of the stored equivalent to get back to the
live object; the actual storage and retrieval of the storable (mothballed)
types.
I think it is important not to confuse the two concepts of
deactivation/reactivation of live (limited) objects and of persistence
(which is really just the automatic, or transparent, storage and
restoration of data).
Of course this little program is only a trivial test of the concept, but I
think you will find it scales up nicely in practice.
Look particularly at the implementation of the Load and Save procedures,
and how they use polymorphic (dispatching) calls both to obtain the
appropriate input and output routines for objects of types derived from
Root_Parcel and also to obtain the appropriate mothballing and
reinstatement routines.
Hope this is of interest!
--
Nick Roberts
Jabber: debater@charente.de [ICQ: 159718630]
next prev parent reply other threads:[~2003-04-09 10:05 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-04-07 12:47 Persistence of limited tagged types Jano
2003-04-07 14:47 ` Nick Roberts
2003-04-09 10:05 ` Nick Roberts [this message]
2003-04-10 3:32 ` tmoran
2003-04-09 23:09 ` Matthew Heaney
2003-04-10 14:40 ` Nick Roberts
2003-04-10 23:37 ` Robert A Duff
2003-04-11 16:39 ` Nick Roberts
2003-04-10 18:49 ` Randy Brukardt
2003-04-10 1:12 ` Matthew Heaney
2003-04-07 18:11 ` Stephen Leake
2003-04-07 19:07 ` Hyman Rosen
2003-04-07 22:09 ` Jano
2003-04-08 13:58 ` Matthew Heaney
2003-04-10 11:41 ` Julio Cano
2003-04-10 19:14 ` Jano
2003-04-11 12:54 ` Julio Cano
2003-04-07 20:17 ` Robert Spooner
2003-04-07 21:14 ` Stephen Leake
2003-04-08 12:56 ` Robert Spooner
2003-04-08 13:41 ` Jano
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox