From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.5-pre1 (2020-06-20) on ip-172-31-74-118.ec2.internal X-Spam-Level: X-Spam-Status: No, score=-1.9 required=3.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.5-pre1 Date: 29 Jul 93 03:10:36 GMT From: rational.com!geneo@uunet.uu.net (Gene Ouye) Subject: Re: Generic package problem Message-ID: <1993Jul29.031036.23470@rational.com> List-Id: Charles Lindsey (chl@clw.cs.man.ac.uk) wrote: : Please can someone explain hte following. I am using AdaEd. : I have a generic package 'linked_lists' which does what you would expect, and : takes one TYPE parameter known as 'ANYTHING'. : I have another package which publishes an abstract data type 'line'. I also : wanted clients of this package to be able to use linked lists of lines. So I : wrote: : WITH linked_lists; : PACKAGE lines IS : TYPE line is PRIVATE; : PACKAGE line_lists IS NEW linked_lists(line); : PRIVATE : etc. : and the compiler complained, after the package instantiation line, : *** ERROR: Invalid use of private type in instantiation of ANYTHING (RM 12.3) : Now I can well understand why a compiler might find difficulty in handling : this, and hence why it might be forbidden, but I have read TFRM (esp. 12.3 : thereof), and I cannot see exactly where this is forbidden (it is certainly : OK by the visibility rules). Please can someone enlighten me? Take a look at LRM 7.4.1, paragraphs 4 and 6. 7.4.1(4) (excerpted): Within the specification of a package that declares a private type and before the end of the corresponding full type declaration, a restriction applies to the use of the name that denotes the private type... The only allowed occurrences of such a name are in a deferred constant declaration, a type or subtype declaration, a subprogram specification, or an entry declaration;... 7.4.1(6) (excerpted) (this paragraph is part of the Notes for 7.4.1): ...before the full declaration, the name of the private type cannot be used in a generic instantiation... : Of course, by moving the package instantiation after the real declaration of : 'line' in the PRIVATE part it accepted it. But what should I do if I really : want the package line_lists to be visible to the clients of 'lines', but : also within the PRIVATE part of lines (some of the record fields in the : PRIVATE part are of type line_lists.linked_list)? Do I have to instantiate : it twice, and if so will the types exported by the two instantiations really : be compatible? If you instantiate it twice, the types exported from the instantiations will not be compatible (if you're using the word the way I think you are). That is, the two instantiations are different packages and any types or objects they export will also be different. You could always force a conversion between the two types via Unchecked_Conversion, but this will get ugly and will force you to add a lot of with's that will clutter up your architecture. I can't see what else you have in your packages, and I'm not sure how you intend them to be used, but I wonder if you have properly separated the behaviors of Line from the behaviors of a collection of Lines. I don't mean this as a criticism of your design, it's just the first question I would ask myself in this situation. If you really do need visibility to the Line_Lists instantiation in the private (or non-visible) part of the Lines package, could it be rearranged so that you only need visibility in the body of Lines? If so, then Line_Lists could be a library level instantiation that could be with'ed by the body of Lines. Personally, I think what follows is really ugly, but it will do the trick if it's what you need. There is an assumption here that AdaEd will allow the spec/body with'ing games that I play here with the generic instantiation (I don't have access to AdaEd so I can't try it out). -- I assume Linked_Lists looks something like this: generic type Anything is private; -- this is the type of an element in the lists package Linked_Lists is type Linked_List is private; -- need operations on linked lists, such as: procedure Add (Item : in Anything; To_List : in out Linked_List); -- there should also be constructors, destructors, etc. private type Linked_List is access Anything; end Linked_Lists; -- of course, it has a body, too. package body Linked_Lists is procedure Add (Item : in Anything; To_List : in out Linked_List) is begin null; -- this should be code to add another item to the list end Add; end Linked_Lists; -- Note: the Linked_List dependency is no longer here. package Lines is type Line is private; -- need operations that do things to a line private type Some_Strange_Incomplete_Type; type Some_Strange_Access_Type is access Some_Strange_Incomplete_Type; type Line is record Text : String (1 .. 80); Some_Other_Field : Some_Strange_Access_Type; end record; end Lines; -- Now we instantiate the generic as a library unit with the Line type -- declared in the Lines package. with Linked_Lists; with Lines; package Line_Lists is new Linked_Lists (Anything => Lines.Line); -- Finally, we complete the body of the Lines package with the instantiation. with Line_Lists; package body Lines is type Some_Strange_Incomplete_Type is access Line_Lists.Linked_List; -- now you implement your package body and do whatever you need -- with the Linked_List and the Line. end Lines; ======================================================================== Like I said, I think this particular example is really ugly, but I know of instances when it has to be done (I don't think this is one of those instances). I suspect that your abstraction of Line is broken if it needs access to a list of Lines. If you want to discuss this further, feel free to send me e-mail. Gene Ouye (geneo@rational.com) Rational, Bethesda, MD, USA (301) 897-4014