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,45abc3b718b20aa3 X-Google-Attributes: gid103376,public From: bobduff@world.std.com (Robert A Duff) Subject: Re: Two ideas for the next Ada standard Date: 1996/08/31 Message-ID: X-Deja-AN: 177631957 references: <5009h5$ir4@netline-fddi.jpl.nasa.gov> <503sbo$j45@goanna.cs.rmit.edu.au> <507akg$t9u@krusty.irvine.com> organization: The World Public Access UNIX, Brookline, MA newsgroups: comp.lang.ada Date: 1996-08-31T00:00:00+00:00 List-Id: In article <507akg$t9u@krusty.irvine.com>, Adam Beneschan wrote: >To me, the mistake is that private parts have to be put in package >specs at all. Ideally, if you declare a type "private" in the package >spec, you should be able to define the complete type in the package >body, which is the normal place to put things that you don't want >visible to other packages that use the package. Quite true. Private parts are primarily an efficiency hack. But this change would be much more sweeping than my idea of allowing the private part to have its own with_clauses. (I think putting the with_clauses inside things makes more sense anyway, independent of your idea.) >The only reason it isn't in the body, as far as I can see, is that it >makes life more difficult for compilers, who would like to know how >big a type is before they compile other packages that use the spec. >This means that things like stack offsets and record component offsets >aren't known at compile time. But it shouldn't be that difficult to >arrange things so that the linker can generate the correct offsets at >link time. It may require a more sophisticated linker or more >sophisticated relocation information in the object file. I think making Ada depend on a more sophisticated linker (and, more importantly, a non-standard object file format) would be a Really Bad Idea! Ada has enough trouble fitting in with the rest of the software world as it is. Ada requires some sort of pre-linker to figure out elaboration order (and complain about circularities), which causes some trouble, but it's not nearly as bad as fooling with relocation information, which is the heart of the linker, and really needs to be standardized across languages. Also, doing more work at link time is bad, because link time is a bottleneck. To modify one body, you have to recompile one thing, but re-link the entire program. At least, that's the way typical implementations work. (I wouldn't mind having an incremental linker! But I can't blame the designers of Ada for assuming the more traditional sort of tools (batch mode compiler, followed by link-it-all).) Another possibility would be to have the compiler generate inefficient code (i.e. assume all private types are dynamic-sized) by default. Then have a pragma along the lines of pragma Inline, which tells the compiler to peek at the body, and generate better code (but making compile-time slower due to extra dependences). Another possibility would be to split a package into three parts -- visible, private, and body. Semantic dependencies would be on the visible part only, but compilation dependencies would be on the visible and private parts. Actually, I think the GNAT folks are planning to implement something like this -- they want to allow a "source representation" that puts the private part in a separate file. This seems like a nice feature, but has some drawbacks: The private part doesn't start with the name of the package, so the private part file is less readable. Also, it depends heavily on GNAT's rule about file names matching package names. Also, exotic source representations can hurt portability. Although the GNAT folks are fond of pointing out that the RM does not define source representation, it seems best if people can stick to something simple and obvious, like one compilation per source file. >I'm running into this problem right now. I'm defining some new >private types, but I cannot define them in the private part, because >this would lead to recursive package dependencies. (The types are in >package X, and package Y's spec WITH's package X, but I'd like to put >some data defined in Y in the definition of the private type. Since I >can't do that without creating recursive dependencies, I've resorted >to the old trick of making the private type an access to a record >structure that's defined in X's body. This works, but opens up a can >of worms related to memory allocation and garbage collection. Yes. At least in Ada 95 you can wrap the access type in a controlled type, thus solving the garbage collection problem. If the feature were built in, instead of being done by hand like this, then it could be more efficient, since the unknown-sized thing could be allocated on the stack, rather than on the heap. Other solutions to this circularity problem have been discussed on this newsgroup. >So my suggestion for the next Ada standard is to allow private types >to be completed in the package body, instead of requiring them to be >completed in the "private" part. (If this would cause serious >difficulties for other language rules, or if there would be major >problems implementing this suggestion in some cases, I'm not aware of >the problem but would appreciate having someone point it out to me.) There are some problems. For one thing, Ada 95 child units don't fit in well with this scheme, since they can't see into bodies. You don't want to force people to choose between two nice features that ought to be orthogonal (I could put this thing in the body, but then I can't extend it in a child package -- grr). Another issue is what to do about access-before-elaboration. When something is declared in two pieces, the language has to worry about what happens when some code references the first piece, when at run time, the second piece has not yet been elaborated. This kind of operation generally makes no sense, so the language must prevent it. For private type vs. full type, the language uses the freezing rules for this purpose, and these rules are checked at compile time. For spec vs body of a subprogram, the language uses run-time checks. The compile-time checks don't work when the thing being split in two is split across compilation units (given the current Ada model, where compilation units can float around in the elab order). Now, run-time checks on every procedure call are somewhat inefficient, but run-time checks on every reference to a type sound much worse. So this seems like reasonable rationale for why private types must be completed in the spec, whereas procedures are completed in the body. On the other hand, one could argue that the run-time checks on procedures are intolerable, and a better solution to that problem is required. Such a solution could presumably deal with types as well. One could argue that the *programmer* should decide this efficiency issue -- why should Jean Ichbiah decide that run-time checks on calls are tolerable, but on types are intolerable, when he hasn't seen *my* program, where there are lots of calls to procedure P, but few references to type T? Two approaches are: (1) use run-time checks, but make sure it's feasible to optimize them away in the vast majority of cases. This kind of optimization is actually rather hard to do in Ada as it stands. (2) Do some analysis at link time (again, link-time work causes trouble, but at least it's a pre-linker pass, rather than meddling with the internals of existing linkers). >(I know that someone [I don't remember who] made the same argument >around 1980 or 1981, pointing out that we'd all benefit from more >sophisticated linkers. I don't remember that. Anyway, that sort of arrogance seemed sensible back in 1980, when Ada folks believed that Ada would take over the world. (The same sort of attitude produced the KAPSE/MAPSE ideas -- we've got a new language, so lets have a new OS as well.) It didn't happen. Nowadays, Ada has to interface to other languages, so saying "Ada needs a different sort of linker" would mean "Let's not use Ada", rather than "Let's have better linkers". Sad, perhaps. Linkers are indeed pretty awful. The typical linker of 1996 contains design decisions that were originally driven by compatibility with linkers of the 1960's, and it's hard to break away from that. >... It's possible that the original Ada proposals >allowed you to complete private types in the package body, but that >this was changed at the request of implementors, leading someone to >argue against the change. But my memory is hazy.) I don't remember any such version, but you could be right. - Bob