I've been using Pascal a while, but it was only recently that I decided to use Pascal for OO programming. Having only used records and typed files up to this point, I'm wondering how objects are saved to stream.
Am I right in supposing that only instance variables are saved? If so, then what about the instance variables of objects inside an object? And the instance variables of objects inside an object, that's inside an object (and... you get the idea)?
I know I should just try it and see for myself, but there are times when trial-and-error must take a backseat to give way to asking, and I think this is one of those times.
TIA.
Neil Santos wrote:
I've been using Pascal a while, but it was only recently that I decided to use Pascal for OO programming. Having only used records and typed files up to this point, I'm wondering how objects are saved to stream. ... snip ...
Section 6.7.5.2 of ISO10206 standard spells it all out.
CBFalconer wrote:
Neil Santos wrote:
I've been using Pascal a while, but it was only recently that I decided to use Pascal for OO programming. Having only used records and typed files up to this point, I'm wondering how objects are saved to stream. ... snip ...
Section 6.7.5.2 of ISO10206 standard spells it all out.
Not really. ISO does not make any statements about the representation of data in the file. If defines any abstract idea of a file whose relation to a file on disk (if at all) is completely unspecified.
Even if assuming that a typed file will store the elements to equally sizes and structured chunks in the file (which is reasonable to assume, and given by GPC), the structure of a chunk is still unknown. In GPC (like probably most other compilers) it corresponds to the layout in memory which again is unspecified in general and can depend on options (alignment etc.).
Second, as "OO" implies, `object' here clearly has the OOP meaning. ISO Pascal doesn't deal with OOP at all.
To answer the original question, we have to know how you save objects. Typed files, untyped files and `BlockWrite', the Chief's FreeVision unit? I suppose the latter when you say "stream", and in this case, probably the Chief should answer.
Generally though, objects are stored mostly like records -- however with an additional field (VMT pointer). The FreeVision unit should take care of that field, I suppose. Objects inside an object (i.e., not a pointer, but a field that is an object) are like records within a record, but *both* with a VMT pointer. (I don't know if the FreeVision unit handles this case.)
Pointers (to objects and in general) are more tricky in files since they need to be encoded. (The memory location is meaningless when loading the file from another process.) I wrote some thoughts about this before (cf. "GPI files"). AFAIK, the FreeVision unit doesn't do anything about it.
The most useful answer, though, may be, the file format is undefined. You can expect to read it back with the program, compiled with the same compiler, as long as the relevant data structures are not changed, on the same platform, not much more. To create/read portable files, you'll have to use types with fixed size (attribute `Size' in GPC) and take care of endianness, or convert everything to/from a byte stream or similar yourself.
Frank
Thanks to everyone that replied (didn't get your e-mail again, CBFalconer); I'll try out what you've told me as soon as I'm able, and I'll post what I learn.
Thanks again. :)
[P.S. You may have noticed I sent two slightly different messages to the list; the first with a good PGP signature, the other with a bad one. Ignore the one with the GOOD signature--my blood was low on caffeine when I wrote that, and wasn't thinking too straight.
The one with the bad signature came to be when I edited the first one; obviously with more caffeine, but still not enough to remember that the signatures wouldn't match.]
On 2 May 2004 at 18:43, Neil Santos wrote:
I've been using Pascal a while, but it was only recently that I decided to use Pascal for OO programming. Having only used records and typed files up to this point, I'm wondering how objects are saved to stream.
Am I right in supposing that only instance variables are saved? If so, then what about the instance variables of objects inside an object? And the instance variables of objects inside an object, that's inside an object (and... you get the idea)?
I know I should just try it and see for myself, but there are times when trial-and-error must take a backseat to give way to asking, and I think this is one of those times.
You would do it however it suits your needs. In the FreeVision objects unit (copy obtainable from gnu-pascal.de/contrib/chief/) there is a TStream object and a few descendants. There are Get and Put methods which you can override. The unit is compatible with the BP objects unit.
Here is a simple example of what you could do (this example compiles under BP, gpc, Virtual Pascal, and Delphi - it works, but has virtually no error checking). You are obviously free to do stuff that is much more complex than this:
Program StrmTest; { usage: "strmtest stream.bin" }
USES objects;
{$ifdef Win32} {$H+} {$ifndef VirtualPascal} {$apptype console} {$endif} {$else} {$endif}
{$ifdef __GPC__} TYPE Word = Word16; {$endif}
TYPE pMyStream = ^TMyStream; TMyStream = OBJECT ( TDosStream ) Size, SelfID : Longint; Name : String [32]; PROCEDURE Put ( P : PObject ); FUNCTION Get : PObject; END;
FUNCTION schar ( CONST s : string ) : {$ifdef Win32}pchar{$else}string{$endif}; BEGIN schar := {$ifdef Win32}pchar{$endif} ( s ); END;
PROCEDURE TMyStream.Put ( P : PObject ); BEGIN IF ( p <> NIL ) THEN Size := Sizeof ( p^ ) ELSE Size := 0; WRITE ( Size, Sizeof ( Size ) ); { Store object size } IF ( p <> NIL ) THEN WRITE ( p^, Size ); { store object itself } END;
FUNCTION TMyStream.Get : PObject; VAR p : pObject; BEGIN READ ( Size, Sizeof ( Size ) ); { read stored object size } IF ( Size = 0 ) THEN Get := NIL ELSE BEGIN Getmem ( p, Size ); READ ( p^, Size ); { read stored object } Get := p; END; END;
{ tests writing to a stream } PROCEDURE StreamTest ( Const s, code : string ); VAR p : pMyStream; t : TMyStream; i : Word; BEGIN IF s = '' THEN Exit; IF ( code = 'r' ) THEN i := stOpen { read = "r"} ELSE IF ( code = 'w' ) THEN i := stCreate { else create new file } ELSE exit;
t.init ( sChar ( s ), i ); IF t.status = stok THEN WITH t DO BEGIN IF i = stCreate THEN BEGIN Name := 'I am a customised stream' + #0#0; SelfID := 1022; Size := Sizeof ( t ); p := @t; Put ( p ); Writeln ( 'Name=', Name ); writeln ( 'handle=', handle ); Writeln ( 'SelfID=', SelfID ); Writeln ( 'Size=', Size ); END ELSE BEGIN pObject ( p ) := Get; WITH TMyStream ( p^ ) DO BEGIN Writeln ( 'SelfID=', SelfID ); writeln ( 'handle=', handle ); Writeln ( 'Name=', Name ); Writeln ( 'Size=', Size ); END; Dispose ( p ); END; { if i = stCreate } Done; END;{ with t} END;
{ Program } VAR s, s1 : String [255]; BEGIN Writeln ( 'Now we shall read from/write to a STREAM (file)!' ); IF ParamCount = 1 THEN s := ParamStr ( 1 ) ELSE BEGIN WRITE ( 'Filename to read from/write to stream: ' ); Readln ( s ); END; WRITE ('Access code ("w"= write to stream; "r" - read from stream):'); Readln ( s1 );
StreamTest ( s, s1 ); END.
Best regards, The Chief -------- Prof. Abimbola A. Olowofoyeku (The African Chief) web: http://www.bigfoot.com/~african_chief/