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-Thread: 103376,7fcf9180e7ba7ab1 X-Google-NewGroupId: yes X-Google-Attributes: gida07f3367d7,domainid0,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news1.google.com!news3.google.com!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: Niklas Holsti Newsgroups: comp.lang.ada Subject: Re: A suggestion for resource management Date: Mon, 23 Aug 2010 15:25:00 +0300 Organization: Tidorum Ltd Message-ID: <8df7ksFu5fU1@mid.individual.net> References: <8762z4gcoi.fsf@mid.deneb.enyo.de> <8darikF1b0U1@mid.individual.net> <87eidr3cje.fsf@mid.deneb.enyo.de> <8dcdu1F4v9U1@mid.individual.net> <878w3yhbi2.fsf@mid.deneb.enyo.de> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Trace: individual.net bMMvY+KYWA87JGXgx9kFagGi50CB7QYHkKbSwYZfFCe4JHyde4 Cancel-Lock: sha1:rcCMX1ECzW0YcZe4t0RSOb2Vf9E= User-Agent: Mozilla-Thunderbird 2.0.0.24 (X11/20100328) In-Reply-To: <878w3yhbi2.fsf@mid.deneb.enyo.de> Xref: g2news1.google.com comp.lang.ada:13666 Date: 2010-08-23T15:25:00+03:00 List-Id: Florian Weimer wrote: > * Niklas Holsti: > >>> In a sense, it's just repeating what Unchecked_Deallaction does behind >>> the scenes. >> I don't understand your comment at all. An instance of >> Unchecked_Deallocation is explicitly executed where it is called, not >> at some later point in time, and no pragma is involved. Or do you mean >> Finalize for controlled types? > > Exactly, Unchecked_Deallocation arranges for calls to a somewhat > non-obvious set of Finalize subprogramms. Yes, but these Finalize calls occur within the execution of an explicit call of Unchecked_Deallocation, not "delayed" at some later point in the program. If I call Foo (X), it is normal for Foo to do something with/to X, including calling primitive operations of X. When Unchecked_Deallocation (X) calls Finalize (X), it is thus within (my expectation of) normal control flow. The scheduling of a clean-up action for later execution is more like the *implicit* calls of Finalize that occur when a controlled object goes out of scope. >> However, if the evaluate-and-save is *only* equivalent to renaming, >> you can get weird effects where a scalar variable seems to have >> different values at different places in the parameter list. For >> example, consider (using the pragma syntax): > > Oh, so scalars need to be copied after all. 8-) That does not solve the basic problem, because then, in "pragma Scoped (Foo (X))", the value (old or new) of X that is (eventually) used in the call would depend on whether X is scalar or not, which would be very error-prone under maintenance. Also, what if X is a private type defined in another package? Depending on its scalarity would break privacy. I still think that all evaluation of the clean-up code should be delayed until the clean-up is actually needed. If something needs to be saved at the point of the pragma Scoped, the programmer should explicitly save it. This could be assisted by an extension of the "at end" syntax to include an optional set of declarations of objects that are elaborated at once, but available later (and only) in the clean-up code, for example in this way: procedure Bar (...) ... X : X_Type := Old_Value; at end of Bar -- Not (yet) Ada! with Saved_X : constant X_Type := X; -- Takes a copy of X as it is now (Old_Value). -- The name Saved_X is visible only here -- and in the "do" part. do Foo (Saved_X); -- The name Saved_X is no longer visible. begin ... X := New_Value; ... end Bar; -- Here Foo is called with Saved_X (= Old_Value). -- If X_Type needs finalization, Saved_X is finalized -- immediately after this call of Foo. >> Moreover, what happens if an actual parameter is a function call? >> Should the function be called at the point of the "pragma Scoped", or >> later? > > At the point of the pragma. Thus, if the function returns a large composite object, that would have to be saved. Another reason to delay all evaluation until the actual use of the clean-up code. Do you have an example that motivates why the parameters should be evaluated early, as you suggest? >> ... you would only allow pragma >> Scoped on the "top" level in a handled_sequence_of_statements. >> >> But why make this limitation? It seems to me not unlikely that some >> application may conditionally Open a COBOL_File, and then a similarly >> conditional Close should occur at the end. One could even let "pragma >> Scoped" be used in loops and execute the clean-up code just before the >> present iteration of the loop ends. > > There is an ambiguity whether the cleanup will occur at the end of the > sequence_of_statements, or at the end of some outer scope. As a case > in point, in the "if" case, you suggest to prefer outer scope, but for > the loop case, you want local cleanup. The choice in the loop case is rather evident, isn't it? The program should not be allowed to make two Open calls without an intervening Close call, just as you implied in your original posting. In the "if" case, a choice would have to be made. Choosing the end of the enclosing subprogram (or loop) is the more flexible choice, since the programmer can force the other alternative by nesting a begin-end block in the "if". With the "at end of do" syntax, the clean-up point can be indicated by the , which could name a subprogram, a loop, or a block. > I couldn't decide which one is > the right approach, so I made both illegal. A conservative choice, but I could live with it. >>> Most languages which strive for >>> exception safety are gradually moving to different constructs (even >>> Java). >> That could be an argument. Can you present these "different >> constructs" here as examples that we could compare to "finally" and to >> your proposal? Many thanks, your links are interesting references. Below, I comment on the properties of each, relative to the questions we are discussing, and which are: (1): Do we need a new feature to schedule clean-up actions? (2): The syntax of the feature. (3): The form of the clean-up action. (4): Possible early evaluation and saving of clean-up parameters. > Python: > > > Need (1): Replaces a fairly complex nesting of try-except-finally, so may well be useful and needed. Syntax (2): Uses a specific syntax to define the objects ("context managers") that initialize and finalize resources, and to delimit the sequence of "subordinate" statements after which the clean-up should occur. Thus more "structured" than Florian's proposal for Ada, whether by "pragma Scoped" or by "at end do", neither of which delimits the subordinate statements (they are all the remaining statements in the handled_sequence_of_statements). Form of clean-up (3): Call of the "exit" method for the context manager object(s), with parameters that indicate normal or exceptional completion of the subordinate statements. Thus only a single form is allowed, and the present proposals for Ada are more flexible. Saving parameters (4): Only the identity of the "exit" method for the context manager is saved. The "exit" method has no programmer-defined parameters, so the question of saving parameter values does not arise. However, the construct also creates the context manager object, so values can be saved there, if the programmer desires. This is similar to my suggestion (no automatic early evaluation and saving). > Java: > > Need (1): Replaces a nesting of try-catches-finally, in the same way as for Python. Syntax (2): Extends the Java "try" statement to include a "resource specification" part. Similar to the Python syntax, and thus similarly different from the proposed Ada syntax. Complicated by the existence of "suppressed exceptions" in Java (a new concept for me). Form of clean-up (3): Call of the parameterless "close" method for the resource object(s), thus more restricted even than the Python case. Saving parameters (4): None for the parameterless "close", but, as in the Python case, the resource object is created as part of the construct and can thus save state, if the programmer desires. > C# (which contained it from the start): > > Very similar to the Java case, but seems a bit simpler; the translation is a "try-finally" statement with no "catches" and no nesting. The "resource objects" are immutable in the subordinate statements, perhaps to ensure that state is saved for the clean-up (point 4). > Go (with some peculiar semantics): > > > Need (1): The feature is motivated in the same way as a "finally" construct, or automatic finalization of objects, which seem absent from Go (caution: this is the first time I look at Go). Syntax (2): A "defer" statement which is very similar to the proposed "pragma Scoped" or "at end do". A clean-up action is dynamically scheduled to be executed at the end of the containing subprogram, and the syntax does not delimit or contain the subordinate statements. The "defer" statement does not identify the relevant resource objects or context managers, to use terms from other languages. Form of clean-up (3): A function or method call. The function can be given "in-line" in the defer statement (a "function literal"). Flexibility thus similar to the proposed "at end do ". Saving parameters (4): The parameters to the deferred function or method call are evaluated and saved. IIUC this is a real copy, not a renaming, and differs from a deep copy only if the parameter value is a pointer or has pointer components. No motivation is given for this level of "saving". Florian's proposal is thus most similar to the Go "defer" statement, and rather different from the constructs in Python, Java, and C#. By the way, Florian, in your original posting you said: Florian Weimer wrote: > Here's a proposal for a resource management pragma. It is similar > to the scope(exit) directive in D, the C++ scope guard idom, and > (to a lesser degree) Go's rescue statement. It seems to me that the Go "rescue" statement is Go's form of an exception handler/catcher, and not at all like pragma Scoped. I assume you meant the "defer" statement, Florian, is that right? I found the D construct "scope(exit)" explained here: http://www.digitalmars.com/d/2.0/statement.html#ScopeGuardStatement My analysis of the D feature: Need (1): Not explained. There are three variants of the feature, respectively for executing a clean-up always, on normal termination, or on exceptional termination. If several variants are used in the same scope, the corresponding try-catch-finally structure could be quite complex. Syntax (2): Similar to "defer" in Go and to the proposed "pragma Scoped" or "at end do". Does not use a pragma. The subordinate statements are not enclosed, and the resource objects are not identified. Form of clean-up (3): Any kind of statement (but one that must not propagate an exception), thus similar to "at end do". Saving parameters (4): None, as far as I can see. > Perl 6 apparently has LEAVE (as a more dynamic variant of END), but I > don't know if it is actually used. I did not look at this one. Sorry, but my loathing of Perl was too strong :-) My summary of the comparison: Need (1): Ok, there seems to be a need, or a least a trend, for this kind of thing, so we should at least consider it for Ada too. Syntax (2): - Florian's proposal is unique in suggesting a "pragma" syntax. All the other languages use syntax that is made part of the core language and is not just a "compiler directive". - The other languages are split between a structured (nested) syntax and a more execution-oriented syntax. In the former, the subordinate statements are enclosed in the syntactic structure like the (extended) Java "try" statement. In the latter, for example the Go "defer" and the D "scope(exit)", the subordinate statements are all the remaining statements in the enclosing subprogram or scope. Florian's proposal for Ada falls in the latter camp. Form of clean-up (3): Some languages limit this to a single call of a subprogram, sometimes a specific subprogram or method (close, exit), perhaps even parameterless. Florian's proposal of a call to a programmer-chosen subprogram, with possible programmer-chosen parameters, is more flexible. But some other languages allow any statement as clean-up code. Saving parameters (4): Only the Go language and Florian's proposal have this feature. I think it needs much more motivation to be supported, and I continue to think that it will be hard to define in a clear way for Ada, especially if arbitrary statements are allowed as clean-up code. One point that is not addressed in Florian's proposal is making the clean-up code aware of the exceptional or normal termination of the subordinate statements. This is possible in Python and D. Should it be possible in Ada? > For evidence that try-finally doesn't work, it's instructive to run a > suitable static analyzer on a code base for the first time. Even if > the developers are competent, you'll find rule violations, several of > them caused by a desire to reduce syntactic overhead. Concrete examples would be interesting. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .