From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,772ae8afc5db35f2 X-Google-Attributes: gid103376,public From: Matthew Heaney Subject: Re: Can't export object of private type Date: 1999/03/09 Message-ID: X-Deja-AN: 452932782 Sender: matt@mheaney.ni.net References: <7bmgfb$2d3$1@plug.news.pipex.net> NNTP-Posting-Date: Tue, 09 Mar 1999 03:10:27 PDT Newsgroups: comp.lang.ada Date: 1999-03-09T00:00:00+00:00 List-Id: nospam@thanks.com.au (Don Harrison) writes: > Nick Roberts wrote: > > :|:Also, you need to remove the function Solo_T from package T (it does > :nothing > > Yes, you're right. As the code stands, it isn't necessary. What I > really want is an abstract primitive operation, not so much for > polymorphism, but so that derivations are forced to supply an access > function to their (private) variable "Self". This is a form of > contract which derivations must meet. You can't enforce this using the type system. This is like declaring a type, and then trying to have an operation that forces clients to declare instances of the type. Huh??? There is a very practical reason why you'll need an accessor function: no one will be able to use your singleton if you don't provide one! > :|:and move the declaration of Self from the private part > :|:of package T.Child (where it doesn't need to be, and will cause an > :|:unnecessary dependency) to the package's body. > > Got you. There are two opposing needs here: > > a) On the other, it's convenient for all private declarations > to be in the one place (rather than being split between private > part of spec and body).... I would declare the instance in the body. The reason is that there might be other abstractions that are needed by the instance. If you declare the instance in the spec, then you'll have to move those with's into the spec too, which can cause unnecessary recompilations. > Just wondering.. Would private child packages have been a better > alternative to nested packages? [I have a pathological aversion to nested > packages.] If you have a choice between a child and a nested package, then use a child. The reason, of course, is to push module dependencies into the child. By moving the dependency to a child, you only have to recompile the subtree, if that module changes. This motivated by package design in my "Abstract Factory Revisited" article in the ACM patterns archive. Maze_Type has a dependency on Maze_Room, because one of its operations takes a room as a return value: type Maze_Type (<>) is limited private; function Get_Room (Number : in Positive; Of_Maze : access Maze_Type) return Room_Handle; In the original version, I had this: package Mazes is type Maze_Type (<>) is limited private; ... type Maze_Room is new Maze_Item with private; function Get_Room (Number : ... With this organization of types, then the entire subsystem (rooted at Mazes) has a dependency on Maze_Type, Maze_Item, and Maze_Room. If any of those types changes (say, because you need to add an operation), then every package in the subsystem must get recompiled. I reasoned that the only type that really needs to go in the root spec is Maze_Item, because that's the root type for all the things you put in a maze game (walls, doors, and rooms all derive from that type). But no one depends Maze_Type except the client. So I moved that type into a child package, which allowed me to move the declaration of the room type into a child package. Like this: package Mazes.Rooms is type Maze_Room is new Maze_Item with private; ... end Mazes.Rooms; with Mazes.Rooms; package Mazes.Games is type Maze_Type (<>) is limited private; function Get_Room (Number : in Positive; Of_Maze : access Maze_Type) return Rooms.Room_Handle; ... end Mazes.Games; Now, with this improved organization, if Maze_Room type changes, then only clients of that one package (like Mazes.Games) need to be recompiled. If Maze_Type changes, then only clients of that package need to be recompiled. The rest of the children of package Mazes are oblivious to changes in Maze_Room or Maze_Type, because they no longer depend on those types. In Ada especially, you always have to be thinking about how to remove module dependencies. Indeed, the child package facility was created _expressly_ to allow you to remove dependencies, by moving the dependency to a subtree. There is an analogy to deep type hierarchies. The higher in the hierarchy you make a change, the more clients have to get recompiled. This problem is so pernicious and so common it has a name: the "fragile base class" problem. In Ada, you have a similar problem for modules. Change the root module in a subsystem, and _every_ module in the subsystem has to get recompiled. You cannot just be thinking of programming in the abstract. You must also be thinking about the actual construction of systems. Frequent recompilations will do you in, and you must take active steps to avoid it. That means careful module design is required. Move module dependencies to a body whenever possible, and push spec dependencies downward in the package hierarchy. In my example above, two types were moved moved from a parent package to two children. This protects other children in that hierarchy from changes in those types. This is one of the reasons I prefer to declare singleton abstractions as state machine packages whenever possible, because the "representation" of that "object" can stay in the body. To use a type means you have to implement the type in the private region of the spec, which means the entities you need to implement that type have to get with'd by the spec. Change one of those other packages, and every package that with's yours will have to be recompiled. This would not be true if those dependencies were moved into the body. This is basically why always say, Don't implement a singleton as a type, unless you have a compelling need to. It just creates module dependencies that wouldn't be there otherwise. 'nuff said, Matt