NON-VIEW OBJECTS INCLUDING STREAMS. ----------------------------------- Thus far the object types considered have all been views, descendant from TView. The non-view types, descendant from the root object type TObject include streams, resource files, collections and string lists. A stream is a generalized object for handling input and output. TStream is the base abstract object providing polymorphic I/O to and from a storage device. A resource file is a special kind of stream where generic objects can be indexed via string keys. Collections involve TCollection which implements a general set of items, including arbitrary objects of different types. String lists are formed from TStringList which implements a special kind of string resource in which strings can be accessed via a numerical index. Collections. ------------ A TCollection type is an object designed to extend the normal behaviour of a Pascal array. It has built-in methods for handling the array and it also allows dynamic sizing. It is polymorphic by virtue of the fact that it uses untyped pointers and so allows the collection to consist of objects, and non-objects, of different types and sizes. This release from the normal strict type checking of Pascal requires care on the part of the programmer. Furthermore, if non-TObject items are used in a collection, then GetItem, PutItem and FreeItem must be modified, as done in TStringCollection. TCollection (pp221-226) has four fields, a pointer to an array of item pointers, a count of the current number of items, the currently allocated size (limit), an increment value (delta) for use when the collection has to grow . There are 23 methods, including Init, Load, Store, Insert, Done and three iterator methods ForEach, FirstThat, LastThat. The example program TVGUID17.PAS illustrates the use of collections for a client account object type, TClient, whose data fields are Account, Name and Phone, all of type PString. PClient points to the object TClient, whose constructor requires three parameters, NewAccount, NewName and NewPhone, all of type string. The NewStr function is used in this constructor to provide the PString types to the data fields as shown: Account := NewStr(NewAccount); Name := NewStr(NewName); Phone := NewStr(NewPhone); Similarly, in the destructor TClient.Done the DisposeStr function is used, as follows: DisposeStr(Account); ... The New function is used to allocate and initialize the collection as follows: ClientList := New(PCollection, Init(10, 5); pointer of type PCollection, initialized with limit of 10 and delta 5. One of TCollection's methods, the Insert procedure, is then used to insert an item into the collection. One parameter is required, the item pointer, itself derived from the New function, including initialization, as follows: WITH ClientList^ DO BEGIN Insert(New(PClient, Init('91-100', 'Anders, Smitty', '(406) 111-2222'))); ... ... The ForEach iterator method is used in the example program to assist in printing the information relating to all clients. Essentially a procedure Printall, which has one parameter, a pointer C of type PCollection, is written with a nested procedure PrintClient, which does the actual printing for each client. The main procedure then calls the nested one as follows: C^.ForEach(@PrintClient); {for each item in C} Details of the iterator methods are given on pages 141-143 of the Guide. All iterators must call FAR local procedures, as explained on page 142 of the Guide. Program TVGUID18.PAS deals with sorted collections, whilst TVGUID19.PAS relates to string collections. Thus far, the items of each collection are of the same type, but it is possible to have items treated polymorphically. Collections can store any object that is a descendant of TObject and they can be mixed. The example program TVGUID20.PAS puts three different graphical objects into a collection. (Note the warning in the Guide and in the program about the full graph save option -g, the use of the GRAPH unit and the path to the BGI file). A procedure MakeCollection, with parameter 'List', uses a pointer P to GraphObject types, which may be points, rectangles or circles to insert the objects into the collection with the statement: List^.Insert(P); This graphics collection is used in an extended version of this program, TVGUID21.PAS, which puts the collection on a stream to a disk file GRAPHICS.STM, which is then read by another program TVGUID22.PAS, as explained below. Streams. -------- A Turbo Vision stream is a collection of objects directed to or from a file, EMS, a serial port or some other device. The I/O transfer occurs at the object level rather than the data level, which is typical of a record. Turbo Pascal requires that files must be typed and that the type must be determined at compile time, but it does not allow the creation of a typed file of objects. Objects probably contain virtual methods, whose address is determined at run-time, so that storing the VMT information outside the program is pointless. Streams provide a simple means of storing object data outside the program, provided the object is a descendant of TObject. All standard Turbo Vision objects are ready to be used with streams and all Turbo vision streams know about the standard objects. New object types derived from one of the standard objects can easily be prepared for stream use and streams alerted to their existence. Each Turbo Vision object type is assigned a unique registration number, which is written to the stream ahead of the object's data. Then when the object is read back from the stream, the registration number is received first and Turbo Vision knows how much data to read and what VMT to attach to it. Stream registration is a simple two-step process of defining a stream registration record which is then passed to the global procedure RegisterType. Stream registration records are of type TStreamRec, which is defined as follows: PStreamRec = ^TStreamRec; TStreamRec = RECORD ObjType: Word; VmtLink: Word; Load: Pointer; Store: Pointer; Next: Word; END; By convention, all Turbo Vision stream registration records are given the same name as the corresponding object type, with the initial letter 'T' replaced by 'R'. Thus the registration record for TDeskTop is RDeskTop. The 'object type' field is a unique type-identifier number (ID), in the range 100-65535, assigned by the programmer (0-99 reserved for the standard objects). The programmer must keep a library of ID numbers and make them available to users of any units. The 'VmtLink' field is a link to the object's virtual method table assigned as the offset of the type of object: RSomeObject.VmtLink := Ofs(TypeOf(TSomeObject)^); The 'Load' and 'Store' fields contain the addresses of the Load and Store methods of the object, respectively: RSomeObject.Load := @TSomeObject.Load; RSomeObject.Store := @TSomeObject.Store; The final field, 'Next', is assigned by 'RegisterType' (see below) and not by the programmer. It involves an internal linked list of stream registration records. Examples of registration records for graphical objects are shown in the programs TVGUID21.PAS AND TVGUID22.PAS, which write a stream to disk and read the stream from disk, respectively. Since the type TStreamRec is already defined in OBJECTS.TPU, the registration record is a record constant, for example: CONST RGraphPoint: TStreamRec = ( ObjType: 150; VmtLink: Ofs(TypeOf(TGraphPoint)^); Load: @TGraphPoint.Load; Store: @TGraphPoint.Store; After the construction of the stream registration record, the standard procedure 'RegisterType' (p 364) is called with the record as its parameter. Thus in TVGUID21.PAS there are statements like: RegisterType(RGraphPoint); The actual reading and writing of objects to the stream is handled by methods called Load and Store. Each object must have these methods to be usable by streams, but they are not called directly. They are called by the Get and Put methods of TStream (pp 296-7). Thus in the demonstration programs TVGUID21.PAS and TVGUID22.PAS the variable declarations are: VAR GraphicsList: PCollection; GraphicsStream: TBufStream; TBufStream inherits the static method 'Put' from TStream, but has its own Init method: CONSTRUCTOR Init(FileName: FNameStr; Mode, Size: Word); So the appropriate statements for putting the stream on disk are: GraphicsStream.Init('GRAPHICS.STM', stCreate, 1024); GraphicsStream.Put(GraphicsList); GraphicsStream.Done; Whilst for reading from the disk the statements are: WITH GraphicsStream DO BEGIN Init('GRAPHICS.STM', stOpen, 1024); GraphicsList := PCollection(Get); Done; ... END; Both the two graphics demonstration programs mentioned above contain over 200 lines of statements, but most relate to graphical object programming and the part relating to streams has been sufficiently described for the complete understanding of these programs. As an exercise, the user is invited to add other graphical objects to the program, such as a full line and an arc and to add these to the stream. Another exercise could involve 'streaming' the objects of another program, such as TVGUID17.PAS or any other object program. STREAMS.TXT 25.3.91