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=-0.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Thread: 103376,147f221051e5a63d X-Google-Attributes: gid103376,domainid0,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news1.google.com!news4.google.com!news.germany.com!newsfeed.utanet.at!newsfeed01.chello.at!newsfeed.arcor.de!newsspool2.arcor-online.net!news.arcor.de.POSTED!not-for-mail From: "Dmitry A. Kazakov" Subject: Re: memory management in Ada: tedious without GC? Newsgroups: comp.lang.ada User-Agent: 40tude_Dialog/2.0.15.1 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Reply-To: mailbox@dmitry-kazakov.de Organization: cbb software GmbH References: <4ddef8bf-b5b1-4d7e-b75b-386cd6c8402c@l17g2000pri.googlegroups.com> <9f2c2db4-d6c1-4cdf-884c-5cbc26ac7701@d1g2000hsg.googlegroups.com> <1qxcw3pphdlek.1jgsfwb7atdmo.dlg@40tude.net> <10j4zhb9ge8ea.156spz1dkc4vb$.dlg@40tude.net> Date: Sat, 24 May 2008 21:04:42 +0200 Message-ID: NNTP-Posting-Date: 24 May 2008 21:04:43 CEST NNTP-Posting-Host: b109b04b.newsspool1.arcor-online.net X-Trace: DXC=PP6LV?R:bRaj5k5aEF7ISmic==]BZ:afn4Fo<]lROoRa<`=YMgDjhgbWOemhf?UNZn[6LHn;2LCVn[9^_W\3[e X-Complaints-To: usenet-abuse@arcor.de Xref: g2news1.google.com comp.lang.ada:331 Date: 2008-05-24T21:04:43+02:00 List-Id: On Sat, 24 May 2008 12:14:56 -0400, Robert A Duff wrote: > "Dmitry A. Kazakov" writes: > >> On Fri, 23 May 2008 19:15:45 -0400, Robert A Duff wrote: >> >>> "Dmitry A. Kazakov" writes: >>> >>>> 1. You don't know exactly the order in which the Finalize of the controlled >>>> component gets called. So if you access the container object over an >>>> access discriminant, that might be already invalid. >>> >>> You know something about the order. Initialize is bottom-up, >>> Finalize is top-down. And when there are access discrims, the >>> order among subling-components is specified by the RM. >>> >>> I would prefer a fully defined order, based on the declaration order. >> >> Hmm, that would be even more broken, I think. The language should not >> require more than necessary to implement the programmer's intent. > > How does the compiler know the programmer's intent? Maybe order is > important, maybe not. Yes, this why it is safe to assume that the program may not rely on it. >>...The order >> of record components or discriminants has no semantic meaning (except when >> representation clauses involved). > > It sometimes has meaning -- that's why we have positional-notation > record aggregates. Just a lexical convention to me. >>... as well as >> initialization of. > > There, I disagree. I see zero advantage to allowing arbitrary order for > the calls to Initialize and Finalize. And one huge disadvantage -- if > you depend on the order, either on purpose or by accident, you might get > a bug introduced years later, when you switch compilers (or even > compiler versions). It will be very hard to detect and to fix that > bug! Yes, this is the same dilemma as with re-ordering operands in expressions. I understand your argument, but I think that the solution is wrong. I'd prefer a better control over the side effects in order to make such (erroneous) programs illegal. It is especially important for modern pipelined, multi-core architectures. Why not to perform initialization of components concurrently? > Consider two finalization actions -- one flushes a buffer to disk, > and the other closes the file handle. It is a wrong design to handle this from components and from different actions of finalization. Buffer cannot be flushed without knowing the file handle. Thus with right design the buffer component will have no access to the file handle. Hence flushing could only be put into the finalization of the composite object, which would automatically enforce proper order. >>... Consider a statically constrained discriminant as an >> example. If the compiler could remove it, we would have the problem of >> measurement units solved! > > Yes. I've always wanted to do that optimization. > > The strange thing is that most compilers do exactly that for array > bounds, but not for discriminants. Array bounds are really > discriminants, deep down! ;-) Yes, and don't forget type tags. They are discriminants too! >>>> 4. The pattern is exposed to multiple inheritance diamond diagram problem, >>>> when such components are added independently. >>> >>> I don't understand your point here. Could you give an example of the >>> problem? >> >> type A is limited tagged record ...; >> type B is new A with record >> -- a controlled component here to handle finalization of A >> >> generic >> type Some_A is new A with private; >> package P is >> type C is new Some_A with record >> -- a controlled component here to handle finalization of A >> >> Now, if P is instantiated with B, finalization of A will be handled twice. >> >> The problem is that finalization in C++ terms is a "virtual" member, while >> record components are "non-virtual". Implementation of one through another >> is IMO fundamentally broken. > > OK, I understand the above example (although I don't see a diamond). A / \ B C (generic) \ / C (instance) > My answer is, "So don't do that". ;-) I thought Ada is a safe language (:-)) Seriously, I think that the Rosen trick should be made illegal for controlled components. It is unsafe. > Why would you put the finalization for A in B? Put it in A where it > belongs. Exactly, but I cannot if A is not controlled! > The main reason to add finalization to B is if B adds > new components that need to be cleaned up. If so, then wrap > those components in a controlled type. This is not the only case. There is a different case when B adds new functionality rather than components. This might require some book keeping actions upon initialization and finalization. These actions cannot be expressed in the terms of individual components, but in primitive operations of A/B. This is the notorious dispatching from constructor/destructor. I call it "class-wide" initialization/finalization. The Rosen trick on a controlled component emulates such class-wide initialization/finalization. But defining an order of component initialization does not save it. Because if you derived from that type, new components would be initialized after the inherited controlled one. So dispatching from its initialization to an overridden operation would become a disaster. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de