DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 
G2++ Tutorial - G2++(3C++)

Record Definition

Suppose that we want to extend usr records by adding a field of some user-defined type. The type of interest may already be defined in an existing header file; or, it may be a new type that we have yet to define. As we will see, there are only two unavoidable restrictions that G2++ imposes on a user-defined type: (1) the type must have an assignment operator The assignment operator is used by the extractor to assign values to structure members of that type. (2) if the type occurs in an array, it must have a parameterless constructor. This restriction is inherited from C++.

For example, suppose that we decide to add a field named last_login of type Time(3C++) to usr records. g2++comp(1C++) requires that a user-defined type be explicitly declared with the keyword USER prior to its first use in a record definition. Here, then, is the simplest .g file that will compile without error:

   usr.g
           Time    USER
           usr
                   login   6
                   last_login      Time
                   id
                           usr     LONG
                           grp     SHORT
                   name    20
                   proj
                           4       LONG

Given only the information that Time is a user-defined type, g2++comp(1C++) will be forced to make a few assumptions. First, it will assume that there is a file named Time.h that defines a type named Time (this assumption happens to be correct). Accordingly, it generates the following header file:

   usr.h
           #include "Time.h"
           typedef struct USR{
              ...
              Time last_login;
              ...
           }USR;

g2++comp(1C++) will also assume that Time.h declares inserters and extractors capable of writing or reading external representations of Time values to or from an ostream(3C++) or an istream(3C++), respectively. These operators are needed because the USR inserter and extractor delegate insertion and extraction of Time values to them:

        USR u;
        cout << u;  delegates insertion of last_login field to Time::operator<<
        cin >> u;   delegates extraction of last_login field to Time::operator>>

This last assumption is not correct, at least insofar as extraction is concerned, but let us continue anyway. Other assumptions made by g2++comp(1C++) in the current example include:

In general, such default assumptions may either be false or inappropriate. In the present example Fortunately, g2++comp(1C++) allows users to override its default assumptions by attaching attributes to the USER type definition:
   usr.g
           Time    USER
                   .header Time.h
                   .header Timeio.h
                   .null   Time::MIN
           ...

We will address the specific attributes used in the above example later. First, let's look at the general form of a USER type definition:

           GREEK SMALL LETTER TAU USER
                .header H1
                .header H2
                    ...
                .null   N
                .isnull I
                .put    P
                .get    G

The significance of each of the attributes is explained below:


.header H
There may be zero or more header attributes. Each H value is interpreted as the name of a header file. g2++comp(1C++) will generate an #include"H" directive for each attribute, in the same order in which the attributes occur. As mentioned above, the default header filename is GREEK SMALL LETTER TAU .h, which will be used if no header attributes are given. The remaining attributes are allowed to assume the existence of definitions exported by the transitive closure of header files named by header attributes. That is, if H1, H2, ... are files named in header attributes, then the closure consists of H1+H2+... plus any header files included by those files, and so-on, transitively.

.null N
There may be zero or one null attributes. When translated in the context of the header file closure implied by header attributes, N must be a valid C++ expression of type GREEK SMALL LETTER TAU. Its value will be used as the null value for type GREEK SMALL LETTER TAU. Omitting the null attribute implies a contract that a parameterless constructor GREEK SMALL LETTER TAU() exists, and its value will be used as the null value.

.isnull I
There may be zero or one isnull attributes. I is taken as the name of a function that indicates whether or not its argument is null. Including an isnull attribute implies a contract that there exists, somewhere in the header file closure implied by header attributes, a declaration of the form:
       int I(const GREEK SMALL LETTER TAU & t);

This function is expected to return 1 if its argument is null, and 0 otherwise. If the isnull attribute is omitted, g2++comp(1C++) will generate code to explicitly test for equality with the null value defined by the null attribute; this means that omitting the isnull attribute implies a contract that there exists, somewhere in the header file closure implied by header attributes, the declaration of an equality operator for type GREEK SMALL LETTER TAU.


.put P
There may be zero or one put attributes. P is taken as the name of a function that knows how to insert an external representation of type GREEK SMALL LETTER TAU into an output stream. Including a put attribute implies a contract that there exists, somewhere in the header file closure implied by header attributes, a declaration of the form:
       ostream& P(ostream& os,const GREEK SMALL LETTER TAU & t);

P is expected to insert an external representation of t into stream os. To preserve the integrity of the record, the external representation must not contain tabs, newlines, or other nonprintable ASCII characters.

If the put attribute is omitted, g2++comp(1C++) will call GREEK SMALL LETTER TAU::operator<< to do the insertion. This means that omitting the put attribute implies a contract that there exists, somewhere in the header file closure implied by header attributes, the declaration of an inserter for type GREEK SMALL LETTER TAU.


.get G
There may be zero or one get attributes. G is taken as the name of a function that knows how to extract an external representation type GREEK SMALL LETTER TAU from an input stream. Including a get attribute implies a contract that there exists, somewhere in the header file closure implied by header attributes, a declaration of the form:
       istream& G(istream& is, GREEK SMALL LETTER TAU & t);

G is expected to extract an external representation from stream is, construct an object of type GREEK SMALL LETTER TAU, and assign it to t. The function must extract only the characters constituting the external representation and leave the stream positioned so that the first character extracted by a subsequent extraction will be the first character following the external representation of type GREEK SMALL LETTER TAU. If G cannot construct an object of type GREEK SMALL LETTER TAU, it should assign a null value to t and clear the error bits (see ios(3C++)). If the get attribute is omitted, g2++comp(1C++) will call GREEK SMALL LETTER TAU::operator>> to do the extraction. This means that omitting the get attribute implies a contract that there exists, somewhere in the header file closure implied by header attributes, the declaration of an extractor for type GREEK SMALL LETTER TAU.

We cannot overemphasize that each piece of information furnished via an attribute (or implied by omitting an attribute) merely creates a contract between the record definer and the software developers responsible for providing the named or implied facilities. g2++comp(1C++) cannot check or enforce these contracts. For example, it does not check for the existence of files named in header attributes, nor does it typecheck any expressions in null attributes. It is only later, when the application is compiled and linked, that the named or implied facilities must actually exist. This delayed binding allows applications to be developed in parallel with their infrastructure.


Next topic: Null Values
Previous topic: Using G2++ with User-Defined Types

© 2004 The SCO Group, Inc. All rights reserved.
UnixWare 7 Release 7.1.4 - 27 April 2004