mnc@m10ux.UUCP (MHx7002 ) (03/09/87)
One of the important features of Ada that allows the safe implementation of
abstract data types is the "private" type feature. You can declare a new
type in the specification of a module, but indicate that the details of the
type definition may not be seen by users of the module. These users may
only declare variables of that type. To perform any operations on the
variables, they must be passed as arguments to functions of the module
that "owns" the private type. Obviously this is necessary to prevent users
of an abstract data type from writing code that depends on the particular
current implementation of the type, say as an array. Such a dependency
would prevent changing the implementation later.
Wouldn't it be nice if the same feature could be obtained in a C header file
(which is the analog of an Ada specification)? Well the following program
compiles without errors on Berkeley 4.3 and Sys V.2 (VAX versions):
typedef struct PRIVATE_S *PRIVATE_P;
main()
{ PRIVATE_P x; if (x) exit();
}
If this is legal C everywhere, it implies that one can obtain a private type
by declaring it to be a struct pointer in the header file (PRIVATE_P), but
only declaring the struct type (PRIVATE_S) in the module that owns the type.
Comments?
--
Michael Condict {ihnp4|vax135|cuae2}!m10ux!mnc
AT&T Bell Labs (201)582-5911 MH 3B-416
Murray Hill, NJ
bzs@bu-cs.UUCP (03/11/87)
Yes, your program certainly works, amazing what people will find, very interesting. One problem is, try: printf("%d\n",sizeof(x)); in the test program. I get an Unknown size error on the compilation. This leads me to believe that although you could do something with this it's probably just exploiting a missing error check in the compiler caused by the need to "trust" forward references to struct pointers or something like that. A bug I guess. Ooops, that was on a SUN3. My Encore just barfs all over your original example (I'm pretty sure they're using a green hills compiler, not a pcc derivitive.) I think the ice is getting very thin. -Barry Shein, Boston University
congdon@ci-dandelion.UUCP (03/11/87)
In article <172@m10ux.UUCP> mnc@m10ux.UUCP (MHx7002 ) writes: >Wouldn't it be nice if the same feature could be obtained in a C header file >(which is the analog of an Ada specification)? Well the following program >compiles without errors on Berkeley 4.3 and Sys V.2 (VAX versions): > > typedef struct PRIVATE_S *PRIVATE_P; > main() > { PRIVATE_P x; if (x) exit(); > } > >If this is legal C everywhere, it implies that one can obtain a private type >by declaring it to be a struct pointer in the header file (PRIVATE_P), but >only declaring the struct type (PRIVATE_S) in the module that owns the type. >Comments? I'm not sure if this is 'legal' C or not (any comments from the language lawyers?) but lint (with -h switch) will warn about the missing definition for 'struct PRIVATE_S'. The structure tag construct is intended to allow definition of self-referential or forward-referencing struct types (K&R pg. 197). For example: typedef struct Foo { struct Foo *next; /* other stuff ... */ } FOO; But in such cases the struct type is eventually defined so the compiler shouldn't complain. In your example, since the compiler never sees a definition for the struct type it's reasonable for the compiler (or lint) to warn about the missing struct type. Pascal allows usage of a pointer types in type definitions before the base type of the pointer type has been defined for self-referential types as well. In fact, I think that this is the only example of 'usage before definition' in Standard Pascal (where even labels have to be pre-defined!). -- Robert M. Congdon UUCP: {talcott,vaxine,mit-eddie}!ci-dandelion!congdon Cognition, Inc. PHONE: (617) 667-4800 900 Tech Park Drive Billerica, MA 01821
chris@mimsy.UUCP (03/12/87)
While I do not know the precise details of Ada private types, I can say that in general, private types are in fact implemented through the use of a `generic pointer' type. That is, outside of a specific module, the only handle anything has on an object of a private type is a pointer to that object. In 4BSD, the generic pointer type is `caddr_t' (Core ADDRess Type); in ANSI draft C it is `void *' (a name that I find utterly lacking in taste, though it does avoid a new keyword). For example, a private data structure that implments longer integers might look like this: struct longer { long low; long high; }; but the routines that deal with one of these take and return only `caddr_t' types: caddr_t new_longer() { struct longer *l; l = (struct longer *) malloc(sizeof (struct longer)); if (l != NULL) l->low = l->high = 0; return ((caddr_t) l); } void incr(obj) caddr_t obj; { struct longer *l = (struct longer *) obj; if (++l->low == 0) /* overflow */ l->high+++; } This is often employed in an `object oriented' manner by providing a structure containing pointers to the object-specific routines, as well as an instance of the object itself: struct representation { caddr_t r_obj; /* the object */ void (*r_incr)(); /* a function that counts it up */ void (*r_print)(); /* a function that prints it */ }; In this case, only the routine that creates a specific instance of an object need know the names of the functions that implement that object. Everywhere else in the code, only the operations provided by the `representation' are available: add_1_and_print(r) register struct representation *r; { (*r->incr)(r->obj); (*r->print)(r->obj); } Of course, doing this is considerably simpler if the compiler helps out, which is why we have languages like C++ in the first place. Otherwise we could all write the C code that the C++ compiler produces. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) UUCP: seismo!mimsy!chris ARPA/CSNet: chris@mimsy.umd.edu
guy@gorodish.UUCP (03/14/87)
>In 4BSD, the generic pointer type is `caddr_t' (Core ADDRess Type); Well, "caddr_t" isn't specific to 4BSD; other versions of UNIX have it. However, it's not really a "new" type; it's just a "typedef" name for "char *". >in ANSI draft C it is `void *' (a name that I find utterly lacking in taste, >though it does avoid a new keyword). An argument can be made that the name "void *" emphasises that these pointers cannot be dereferenced, since dereferencing a "void *" would yield a "void". If this was, in fact, a reason why "void *" was chosed to be the name of the "generic pointer" type, this should perhaps appear in the Rationale.
faustus@ucbcad.berkeley.edu (Wayne A. Christopher) (03/17/87)
In article <15039@sun.uucp>, guy%gorodish@Sun.COM (Guy Harris) writes: > Well, "caddr_t" isn't specific to 4BSD; other versions of UNIX have it. > However, it's not really a "new" type; it's just a "typedef" name for > "char *". The problem with "caddr_t" is that it doesn't look like a pointer... Although that may be a good thing since it will make you not want to dereference it without casting it... Wayne
bobd@dshovax.UUCP (Bob Dietrich) (03/18/87)
In article <513@ci-dandelion.UUCP> congdon@ci-dandelion.UUCP (Robert M. Congdon) writes: > >Pascal allows usage of a pointer types in type definitions before the >base type of the pointer type has been defined for self-referential >types as well. In fact, I think that this is the only example of >'usage before definition' in Standard Pascal (where even labels have to >be pre-defined!). > >-- >Robert M. Congdon UUCP: {talcott,vaxine,mit-eddie}!ci-dandelion!congdon >Cognition, Inc. PHONE: (617) 667-4800 >900 Tech Park Drive >Billerica, MA 01821 Pascal also allows another case (effectively): program parameters appear in the program heading before their definition as variables. In addition, Extended Pascal adds the identifiers that are exported as constituents of a module interface. Bob Dietrich Intel Corporation, Hillsboro, Oregon (503) 681-2092 usenet: tektronix!reed!omssw2!dshovax!bobd