* A suggestion for resource management @ 2010-08-21 16:20 Florian Weimer 2010-08-21 19:07 ` Dmitry A. Kazakov ` (2 more replies) 0 siblings, 3 replies; 20+ messages in thread From: Florian Weimer @ 2010-08-21 16:20 UTC (permalink / raw) Here's a proposal for a resource management pragma, tentatively called pragma Scoped. It is similar to the scope(exit) directive in D, the C++ scope guard idom, and (to a lesser degree) Go's rescue statement. The syntax is: pragma Scoped (procedure_call_statment); The legality rules and static semantics are the same as for the old (one-argument) pragma Debug implemented by GNAT, with the additional restriction that Scoped pragmas may only appear in a handled_sequence_of_statements or in a declarative_part. (This additional restriction is necessary because otherwise, the pragma could be executed multiple times, and it is difficult to decide what should happen in this case.) Regarding dynamic semantics: When a Scoped pragma which is part of a handled_sequence_of_statements is executed or when it is elaborated as part of a declarative_part, the procedure_name or procedure_prefix and actual parameters of the procedure_call_statment are evaluated. If the corresponding handled_sequence_of_statements completes subsequently (or if the declarative_part completes abnormally, without ever entering the handled_sequence_of_statements), the procedure call is performed, using the prefix and parameters as evaluated previously. After that, objects are finalized as necessary. (Finalization of parameters is a reason why there are no specific pragmas for normal and abnormal completion---the arguments would have to be finalized, despite the pragma suggesting that nothing happens in that case.) The procedure calls happen in the reverse order of the execution of the pragmas, and before objects are finalized which were elaborated prior to execution of the pragma. If the procedure call itself completes abnormally, Program_Error is raised. (Program_Error is not raised if the earlier parameter evaluation completes abnormally.) The example at the end of section B.4 could use the Scoped pragma in this way: procedure Test_External_Formats is ... COBOL_File : File_Type; ... begin Open (COBOL_File, Name => "Some_File"); pragma Scoped (Close (COBOL_File)); loop ... exception when End_Error => ... end Test_External_Formats; ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-21 16:20 A suggestion for resource management Florian Weimer @ 2010-08-21 19:07 ` Dmitry A. Kazakov 2010-08-21 19:47 ` Florian Weimer 2010-08-21 20:34 ` Niklas Holsti 2010-08-22 13:09 ` stefan-lucks 2 siblings, 1 reply; 20+ messages in thread From: Dmitry A. Kazakov @ 2010-08-21 19:07 UTC (permalink / raw) On Sat, 21 Aug 2010 18:20:29 +0200, Florian Weimer wrote: > procedure Test_External_Formats is > ... > COBOL_File : File_Type; > ... > > begin > Open (COBOL_File, Name => "Some_File"); > pragma Scoped (Close (COBOL_File)); > > loop > ... > exception > when End_Error => ... > end Test_External_Formats; What is wrong with having a destructor for File_Type? If the language is to be extended why not to fix that first? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-21 19:07 ` Dmitry A. Kazakov @ 2010-08-21 19:47 ` Florian Weimer 2010-08-21 20:53 ` Dmitry A. Kazakov 0 siblings, 1 reply; 20+ messages in thread From: Florian Weimer @ 2010-08-21 19:47 UTC (permalink / raw) * Dmitry A. Kazakov: > On Sat, 21 Aug 2010 18:20:29 +0200, Florian Weimer wrote: > >> procedure Test_External_Formats is >> ... >> COBOL_File : File_Type; >> ... >> >> begin >> Open (COBOL_File, Name => "Some_File"); >> pragma Scoped (Close (COBOL_File)); >> >> loop >> ... >> exception >> when End_Error => ... >> end Test_External_Formats; > > What is wrong with having a destructor for File_Type? If the language is to > be extended why not to fix that first? You can't always change libraries in that way. Adding destructors has both syntactic and run-time overhead. The run-time overhead can be minimized by a sufficiently advanced compiler (perhaps relying on whole-program optimization to detect the lack of task aborts). I'm more concerned with the syntactic overhead. There are some cases where the destructor solution doesn't really apply. For instance, the cleanup operation might need two parameters, one denoting the object, and a second one decribing where to put it. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-21 19:47 ` Florian Weimer @ 2010-08-21 20:53 ` Dmitry A. Kazakov 2010-08-21 21:09 ` Florian Weimer 0 siblings, 1 reply; 20+ messages in thread From: Dmitry A. Kazakov @ 2010-08-21 20:53 UTC (permalink / raw) On Sat, 21 Aug 2010 21:47:05 +0200, Florian Weimer wrote: > * Dmitry A. Kazakov: > >> On Sat, 21 Aug 2010 18:20:29 +0200, Florian Weimer wrote: >> >>> procedure Test_External_Formats is >>> ... >>> COBOL_File : File_Type; >>> ... >>> >>> begin >>> Open (COBOL_File, Name => "Some_File"); >>> pragma Scoped (Close (COBOL_File)); >>> >>> loop >>> ... >>> exception >>> when End_Error => ... >>> end Test_External_Formats; >> >> What is wrong with having a destructor for File_Type? If the language is to >> be extended why not to fix that first? > > You can't always change libraries in that way. Adding destructors has > both syntactic and run-time overhead. I don't see why. Without class-wide objects there is no overhead, everything is statically known. Neither there is any syntactic overhead. File_Type is extended just once and then used everywhere. In fact it is your solution that has distributed overhead (and error-prone too), because the pragma has to be used everywhere a file is opened. BTW, file handle File_Type should not be opened, it should be constructed. There should be no invalid File_Type, at least the library should not encourage them as the Ada library does and in your example follows. > The run-time overhead can be > minimized by a sufficiently advanced compiler (perhaps relying on > whole-program optimization to detect the lack of task aborts). I'm > more concerned with the syntactic overhead. > > There are some cases where the destructor solution doesn't really > apply. For instance, the cleanup operation might need two parameters, > one denoting the object, and a second one decribing where to put it. I would use mix-in in such rare cases. However, I try to avoid clean-ups. It is a bad pattern. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-21 20:53 ` Dmitry A. Kazakov @ 2010-08-21 21:09 ` Florian Weimer 2010-08-22 6:40 ` Dmitry A. Kazakov 2010-08-23 23:22 ` Randy Brukardt 0 siblings, 2 replies; 20+ messages in thread From: Florian Weimer @ 2010-08-21 21:09 UTC (permalink / raw) * Dmitry A. Kazakov: >> You can't always change libraries in that way. Adding destructors has >> both syntactic and run-time overhead. > > I don't see why. Without class-wide objects there is no overhead, > everything is statically known. You need escape analysis or inter-procedural scalar replacement to eliminate the tag. But it certainly can be done, and the additional word will not hurt in all but the most extreme cases. (There's a GNAT-specific inefficiency, but it is reportedly being tackled.) > BTW, file handle File_Type should not be opened, it should be > constructed. There should be no invalid File_Type, There are cases where you need the explicit Close operation, so you still end up with an invalid state. How would you handle an exception raised by construction, without extending the handler to cover undue regions of code? >> There are some cases where the destructor solution doesn't really >> apply. For instance, the cleanup operation might need two parameters, >> one denoting the object, and a second one decribing where to put it. > > I would use mix-in in such rare cases. However, I try to avoid clean-ups. > It is a bad pattern. And you suggest to use Finalize procedures instead? Hmm. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-21 21:09 ` Florian Weimer @ 2010-08-22 6:40 ` Dmitry A. Kazakov 2010-08-23 23:22 ` Randy Brukardt 1 sibling, 0 replies; 20+ messages in thread From: Dmitry A. Kazakov @ 2010-08-22 6:40 UTC (permalink / raw) On Sat, 21 Aug 2010 23:09:38 +0200, Florian Weimer wrote: > * Dmitry A. Kazakov: > >> BTW, file handle File_Type should not be opened, it should be >> constructed. There should be no invalid File_Type, > > There are cases where you need the explicit Close operation, so you > still end up with an invalid state. It is difficult to construct such cases. One I can remember is the socket closed from outside to break blocking recv. > How would you handle an exception raised by construction, without > extending the handler to cover undue regions of code? Roll back everything elaborated above and propagate. >>> There are some cases where the destructor solution doesn't really >>> apply. For instance, the cleanup operation might need two parameters, >>> one denoting the object, and a second one decribing where to put it. >> >> I would use mix-in in such rare cases. However, I try to avoid clean-ups. >> It is a bad pattern. > > And you suggest to use Finalize procedures instead? Hmm. Yes, it requires a bit more up front work, but it always pays off. It is much simpler to maintain. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-21 21:09 ` Florian Weimer 2010-08-22 6:40 ` Dmitry A. Kazakov @ 2010-08-23 23:22 ` Randy Brukardt 1 sibling, 0 replies; 20+ messages in thread From: Randy Brukardt @ 2010-08-23 23:22 UTC (permalink / raw) "Florian Weimer" <fw@deneb.enyo.de> wrote in message news:8739u73c6l.fsf@mid.deneb.enyo.de... ... > You need escape analysis or inter-procedural scalar replacement to > eliminate the tag. But it certainly can be done, and the additional > word will not hurt in all but the most extreme cases. Why would you bother? The tag itself isn't very large and exists once per type. The tag component is usually a word or two per object; it isn't going to matter unless there are 10s of thousands of objects. (And if there *are* 10s of thousands of objects, the overhead of finalizing the objects, no matter what you call it [such as calling Close in this example], is going to be a much greater problem. Tiny, common objects can't require cleanup, period.) Randy. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-21 16:20 A suggestion for resource management Florian Weimer 2010-08-21 19:07 ` Dmitry A. Kazakov @ 2010-08-21 20:34 ` Niklas Holsti 2010-08-21 21:01 ` Florian Weimer 2010-08-22 13:09 ` stefan-lucks 2 siblings, 1 reply; 20+ messages in thread From: Niklas Holsti @ 2010-08-21 20:34 UTC (permalink / raw) Florian Weimer wrote: > Here's a proposal for a resource management pragma, tentatively called > pragma Scoped. It is similar to the scope(exit) directive in D, the > C++ scope guard idom, and (to a lesser degree) Go's rescue statement. > > The syntax is: > > pragma Scoped (procedure_call_statment); I strongly dislike the idea of using "pragma" to introduce such non-obvious flow of control. Flow of control should be clearly represented in the syntactic structure, with textual order matching execution order. The current exception-handling syntax is good in that respect. > Regarding dynamic semantics: When a Scoped pragma which is part of a > handled_sequence_of_statements is executed or when it is elaborated as > part of a declarative_part, the procedure_name or procedure_prefix and > actual parameters of the procedure_call_statment are evaluated. ... and, if I understand your suggestion, the evaluated parameters are saved somewhere, in case they are needed for the later call. I think this can cause large run-time overheads, as well as confusion and errors. How "deeply" are the parameters saved? The semantics will depend on whether a type is passed by value or by access, right? Also, saved parameters of access type may become unusable (hanging pointers) if the statement_sequence deallocates the accessed object. The state of the relevant objects may also change in some other non-obvious but significant ways that invalidate the saved parameter values. You did not discuss if "pragma Scoped" could be executed conditionally, as in: Do_Something ( ... Success => Ok); if Ok then pragma Scoped (Undo_Something (...)); end if; Is this included in your suggestion? > The example at the end of section B.4 could use the Scoped pragma in > this way: > > procedure Test_External_Formats is > ... > COBOL_File : File_Type; > ... > > begin > Open (COBOL_File, Name => "Some_File"); > pragma Scoped (Close (COBOL_File)); > > loop > ... > exception > when End_Error => ... > end Test_External_Formats; If I understand your suggestion correctly, more or less the same behaviour can be achieved in current Ada by a statement block: procedure Test_External_Formats is ... COBOL_File : File_Type; ... begin Open (COBOL_File, Name => "Some_File"); begin loop ... end loop; exception when End_Error => ... end; Close (COBOL_File); end Test_External_Formats; I find that form clear and brief enough, although I admit that nesting depth may become awkwardly large (the remedy is to split the procedure). I'm not sure if your suggestion is that the "pragma" procedure call (here, Close (COBOL_File)) should be performed also if an exception is propagated from the exception handler of the handled_sequence_of_statements. My version above does not perform Close in that case. If Close should be performed in that case, I would very much prefer new syntax for a "finally" structure placed at the end of the handled_sequence_of_statements, after the exception handler if any, over the "pragma" suggestion. In summary, the present language already has tools for this need, either finalization (as Dmitry suggested) or the nested block shown above. Cases where the present tools are not ideal could be covered by a new "finally" construct. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-21 20:34 ` Niklas Holsti @ 2010-08-21 21:01 ` Florian Weimer 2010-08-22 10:53 ` Niklas Holsti 2010-08-22 11:32 ` Georg Bauhaus 0 siblings, 2 replies; 20+ messages in thread From: Florian Weimer @ 2010-08-21 21:01 UTC (permalink / raw) * Niklas Holsti: > Florian Weimer wrote: >> Here's a proposal for a resource management pragma, tentatively called >> pragma Scoped. It is similar to the scope(exit) directive in D, the >> C++ scope guard idom, and (to a lesser degree) Go's rescue statement. >> >> The syntax is: >> >> pragma Scoped (procedure_call_statment); > > I strongly dislike the idea of using "pragma" to introduce such > non-obvious flow of control. In a sense, it's just repeating what Unchecked_Deallaction does behind the scenes. > Flow of control should be clearly represented in the syntactic > structure, with textual order matching execution order. The current > exception-handling syntax is good in that respect. I understand that goal. However, this approach separates the initialization from the clean-up code, and the clean-up code might need repeating in several places. This cannot be good. >> Regarding dynamic semantics: When a Scoped pragma which is part of a >> handled_sequence_of_statements is executed or when it is elaborated as >> part of a declarative_part, the procedure_name or procedure_prefix and >> actual parameters of the procedure_call_statment are evaluated. > > ... and, if I understand your suggestion, the evaluated parameters are > saved somewhere, in case they are needed for the later call. I think > this can cause large run-time overheads, as well as confusion and > errors. How "deeply" are the parameters saved? renaming-declaration-deeply, so it really depends on the types involved. This happens with any procedure call, so the overhead cannot be huge. > The semantics will depend on whether a type is passed by value or by > access, right? Not really. The idea is to avoid strange action-at-a-distance if the actual arguments change their value between execution of the pragma and the embedded procedure call. > Also, saved parameters of access type may become unusable (hanging > pointers) if the statement_sequence deallocates the accessed object. Ordinary procedure calls suffer from this problem, too. As far as I can see, this can only happen with Unchecked_Deallaction, so it is acceptable. > You did not discuss if "pragma Scoped" could be executed > conditionally, as in: > > Do_Something ( ... Success => Ok); > if Ok then > pragma Scoped (Undo_Something (...)); > end if; > > Is this included in your suggestion? The branches of an if statement aren't a handled_sequence_of_statements, so it's not allowed. >> The example at the end of section B.4 could use the Scoped pragma in >> this way: >> >> procedure Test_External_Formats is >> ... >> COBOL_File : File_Type; >> ... >> >> begin >> Open (COBOL_File, Name => "Some_File"); >> pragma Scoped (Close (COBOL_File)); >> >> loop >> ... >> exception >> when End_Error => ... >> end Test_External_Formats; > > If I understand your suggestion correctly, more or less the same > behaviour can be achieved in current Ada by a statement block: > > procedure Test_External_Formats is > ... > COBOL_File : File_Type; > ... > begin > Open (COBOL_File, Name => "Some_File"); > begin > loop > ... > end loop; > exception > when End_Error => ... > end; > Close (COBOL_File); You also need this here: exeption when others => Close (COBOL_File); raise; plus another level of nesting because you shouldn't call Close when Open results in an exception, and when Close itself raises an exception. > end Test_External_Formats; > > I find that form clear and brief enough, although I admit that > nesting depth may become awkwardly large (the remedy is to split the > procedure). No one will write such code unless forced to do so by some static analysis tool. It's rather messy. It's actually pretty difficult to see if all clean-ups occur as needed. If the subprogram needs two objects which require clean-up, it will not fit on a single screen anymore. Splitting it up into two outer subprograms which perform initialization and cleanup for each object and another one which does the bulk of the work will not add much value to the reader, either. > I'm not sure if your suggestion is that the "pragma" procedure call > (here, Close (COBOL_File)) should be performed also if an exception is > propagated from the exception handler of the > handled_sequence_of_statements. My version above does not perform > Close in that case. If Close should be performed in that case, I would > very much prefer new syntax for a "finally" structure placed at the > end of the handled_sequence_of_statements, after the exception handler > if any, over the "pragma" suggestion. "finally" was state-of-the-art in 1995. I'm not sure if it still can be considered good language design. Most languages which strive for exception safety are gradually moving to different constructs (even Java). "finally" is much less syntactically heavyweight than nested exception handling blocks, but programmers still do not use it consistently. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-21 21:01 ` Florian Weimer @ 2010-08-22 10:53 ` Niklas Holsti 2010-08-22 15:29 ` Florian Weimer 2010-08-22 16:12 ` Florian Weimer 2010-08-22 11:32 ` Georg Bauhaus 1 sibling, 2 replies; 20+ messages in thread From: Niklas Holsti @ 2010-08-22 10:53 UTC (permalink / raw) Florian Weimer wrote: > * Niklas Holsti: > >> Florian Weimer wrote: >>> Here's a proposal for a resource management pragma, tentatively called >>> pragma Scoped. It is similar to the scope(exit) directive in D, the >>> C++ scope guard idom, and (to a lesser degree) Go's rescue statement. >>> >>> The syntax is: >>> >>> pragma Scoped (procedure_call_statment); >> I strongly dislike the idea of using "pragma" to introduce such >> non-obvious flow of control. > > 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? >> Flow of control should be clearly represented in the syntactic >> structure, with textual order matching execution order. The current >> exception-handling syntax is good in that respect. > > I understand that goal. However, this approach separates the > initialization from the clean-up code, I understand your point, but these are conflicting goals, as long as text remains one-dimensional, so it is a judgement call. > and the clean-up code might > need repeating in several places. This cannot be good. I take it you mean that one and the same occurrence of an "Open" call may require more than one occurrence of a "clean-up" call of "Close". But in some cases the converse happens, too: One and the same call of "Close" may clean up after different (alternative) "Open"s. That's life... To focus the discussion, your proposal contains the following four distinct parts, as I see it: 1. The introduction of a new executable construct (in your proposal, a pragma Scoped) that, *when* and *if* executed, dynamically "schedules" something else (the procedure call) to be executed at a later point in the execution (just before the "end" of the handled_sequence_of_statements). Advantages: The dynamic semantics gives LIFO nesting of initialization and finalization actions, without a corresponding nested syntax, even if exceptions occur (that is, transparently with respect to exceptions). Disadvantages: Flow of control differs strongly from text order. If your application or coding style puts, in the same subprogram, many things that need such clean-up (several levels of dynamic nesting), I understand that the advantages may be valued higher than the disadvantages. 2. The syntax of that new executable construct. You suggest a pragma, and I don't like that. I think pragmas should be "compiler directives" (RM 2.8(1)) and should not contribute materially to the algorithm that the program implements. I accept that there are already some pragmas that are really executable statements, such as pragma Assert, but I see those as special cases that are not part of the program's algorithm. 3. The nature and form of the code that is "scheduled" for later execution. You suggest a procedure call; I don't see why such a feature should not allow any form of statement. 4. The dynamic semantics of the "scheduled" code, in particular whether some parts of it are evaluated and fixed at the time of "scheduling", as you suggest, instead of later when the code is executed. If point (1) is accepted, I would like a non-pragma syntax, preferably using existing keywords. For example: at end do some-statement; (Following normal Ada principles, this should really be closed by an "end at", or even "end at end", but that may be too much...) There could be an optional subprogram or block identifier between the "end" and "do", as in at end of Test_External_Formats do Close (COBOL_File); >>> Regarding dynamic semantics: When a Scoped pragma which is part of a >>> handled_sequence_of_statements is executed or when it is elaborated as >>> part of a declarative_part, the procedure_name or procedure_prefix and >>> actual parameters of the procedure_call_statment are evaluated. >> ... and, if I understand your suggestion, the evaluated parameters are >> saved somewhere, in case they are needed for the later call. I think >> this can cause large run-time overheads, as well as confusion and >> errors. How "deeply" are the parameters saved? > > renaming-declaration-deeply, so it really depends on the types > involved. This happens with any procedure call, so the overhead > cannot be huge. Yes, it happens at every procedure call, but the values are then normally discarded after the procedure call. Here, they would not be discarded until the "end". But I agree that a renaming is not expensive. 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): begin I : Integer := 4; A : array (1 .. 10) of Float := ( some values ); pragma Scoped (Foo (I, A(I))); begin I := 9; end; I think your suggestion is that the pragma is equivalent to: Saved_I : Integer renames I; Saved_AI : Float renames A(I); followed (before the "end") by the call Foo (Saved_I, Saved_AI); The call that is executed before the "end" is then Foo (9, A(4)), where the variable "I" seems to have two different values, 4 and 9. 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? >> The semantics will depend on whether a type is passed by value or by >> access, right? > > Not really. The idea is to avoid strange action-at-a-distance if the > actual arguments change their value between execution of the pragma > and the embedded procedure call. But the example above shows that this produces other (?) strange effects, since renaming "fixes" the value of a variable in some contexts but not in others. >> Also, saved parameters of access type may become unusable (hanging >> pointers) if the statement_sequence deallocates the accessed object. > > Ordinary procedure calls suffer from this problem, too. My point is that the early evaluation of the parameters at the point of the pragma suggests that the procedure call occurs in that state, but actually the state may have changed, and the evaluated and saved parameters only capture some part of the state. This is confusing; when the call occurs, before the "end", the parameters are a mixture of the two states. In the example above, "I" seems to have two values... > As far as I > can see, this can only happen with Unchecked_Deallaction, so it is > acceptable. Why? Do you never use Unchecked_Deallocation? AFAIK it is the only way to recover global memory resources in Ada, so it is a normal part of Ada programming. I think the clearest solution to point (4) is to say that all of the "scheduled" code is evaluated and executed later (before the "end"). If the programmer needs to save some values that may change, this can be done with ordinary declarations or statements, for example Saved_I : constant Integer := I; Saved_AI : constant Float := A(I); >> You did not discuss if "pragma Scoped" could be executed >> conditionally, as in: >> >> Do_Something ( ... Success => Ok); >> if Ok then >> pragma Scoped (Undo_Something (...)); >> end if; >> >> Is this included in your suggestion? > > The branches of an if statement aren't a > handled_sequence_of_statements, so it's not allowed. Ok, I misunderstood your suggestion: 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. >> I would >> very much prefer new syntax for a "finally" structure placed at the >> end of the handled_sequence_of_statements, after the exception handler >> if any, over the "pragma" suggestion. > > "finally" was state-of-the-art in 1995. That is not an argument by itself. > I'm not sure if it still can > be considered good language design. 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? -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-22 10:53 ` Niklas Holsti @ 2010-08-22 15:29 ` Florian Weimer 2010-08-22 16:12 ` Florian Weimer 1 sibling, 0 replies; 20+ messages in thread From: Florian Weimer @ 2010-08-22 15:29 UTC (permalink / raw) * 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. > 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-) > 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. > I think the clearest solution to point (4) is to say that all of the > "scheduled" code is evaluated and executed later (before the "end"). >> The branches of an if statement aren't a >> handled_sequence_of_statements, so it's not allowed. > > Ok, I misunderstood your suggestion: 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. I couldn't decide which one is the right approach, so I made both illegal. >> I'm not sure if it still can >> be considered good language design. 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? Python: <http://docs.python.org/reference/compound_stmts.html#with> <http://www.python.org/dev/peps/pep-0343/> Java: <http://blogs.sun.com/darcy/entry/project_coin_updated_arm_spec> C# (which contained it from the start): <http://msdn.microsoft.com/en-us/library/yh598w02%28VS.80%29.aspx> Go (with some peculiar semantics): <http://golang.org/doc/go_spec.html#Handling_panics> Perl 6 apparently has LEAVE (as a more dynamic variant of END), but I don't know if it is actually used. 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. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-22 10:53 ` Niklas Holsti 2010-08-22 15:29 ` Florian Weimer @ 2010-08-22 16:12 ` Florian Weimer 2010-08-23 12:25 ` Niklas Holsti 1 sibling, 1 reply; 20+ messages in thread From: Florian Weimer @ 2010-08-22 16:12 UTC (permalink / raw) * 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. > 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-) > 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. > I think the clearest solution to point (4) is to say that all of the > "scheduled" code is evaluated and executed later (before the "end"). >> The branches of an if statement aren't a >> handled_sequence_of_statements, so it's not allowed. > > Ok, I misunderstood your suggestion: 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. I couldn't decide which one is the right approach, so I made both illegal. >> I'm not sure if it still can >> be considered good language design. 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? Python: <http://docs.python.org/reference/compound_stmts.html#with> <http://www.python.org/dev/peps/pep-0343/> Java: <http://blogs.sun.com/darcy/entry/project_coin_updated_arm_spec> C# (which contained it from the start): <http://msdn.microsoft.com/en-us/library/yh598w02%28VS.80%29.aspx> Go (with some peculiar semantics): <http://blog.golang.org/2010/08/defer-panic-and-recover.html> <http://golang.org/doc/go_spec.html#Handling_panics> Perl 6 apparently has LEAVE (as a more dynamic variant of END), but I don't know if it is actually used. 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. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-22 16:12 ` Florian Weimer @ 2010-08-23 12:25 ` Niklas Holsti 2010-09-04 19:09 ` Florian Weimer 0 siblings, 1 reply; 20+ messages in thread From: Niklas Holsti @ 2010-08-23 12:25 UTC (permalink / raw) 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 <identifier> do" syntax, the clean-up point can be indicated by the <identifier>, 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: > > <http://docs.python.org/reference/compound_stmts.html#with> > <http://www.python.org/dev/peps/pep-0343/> 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: > > <http://blogs.sun.com/darcy/entry/project_coin_updated_arm_spec> 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): > > <http://msdn.microsoft.com/en-us/library/yh598w02%28VS.80%29.aspx> 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): > > <http://blog.golang.org/2010/08/defer-panic-and-recover.html> > <http://golang.org/doc/go_spec.html#Handling_panics> 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 <statement>". 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 . @ . ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-23 12:25 ` Niklas Holsti @ 2010-09-04 19:09 ` Florian Weimer 2010-09-07 10:14 ` Niklas Holsti 0 siblings, 1 reply; 20+ messages in thread From: Florian Weimer @ 2010-09-04 19:09 UTC (permalink / raw) * Niklas Holsti: > 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. Finalization of components is quite magic, too. > Also, what if X is a private type defined in another package? > Depending on its scalarity would break privacy. That information already leaks during exception handling. In retrospect, the construct suggested by Stefan (with the additional tweak I mentioned) should work well enough, it just introduces a pointless identifier. Curiously, it shares many of the things you criticize about pragma Scoped. This succient notation was not possible in Ada 95, so I'm not too embarrassed that I missed this option. > 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? Yes, I keep confusing the Go terms. > - 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 idea was to implement it in an existing compiler if the semantics are well-received. >> 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. In Java, I often see programmers using FileInputStream or Socket without try-finally blocks, relying on the garbage collector to close file descriptors. Sorry, I can't be more specific than that. I'll try to remember to post a follow-up when I see something similar in an open code base. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-09-04 19:09 ` Florian Weimer @ 2010-09-07 10:14 ` Niklas Holsti 0 siblings, 0 replies; 20+ messages in thread From: Niklas Holsti @ 2010-09-07 10:14 UTC (permalink / raw) Florian Weimer wrote: > In retrospect, the construct suggested by Stefan (with the additional > tweak I mentioned) should work well enough, it just introduces a > pointless identifier. For reference, since those posts appeared some time ago, here is a part of your pragma proposal: > On Sat, 21 Aug 2010, Florian Weimer wrote: > >> The example at the end of section B.4 could use the Scoped pragma in >> this way: >> >> procedure Test_External_Formats is >> ... >> COBOL_File : File_Type; >> ... >> >> begin >> Open (COBOL_File, Name => "Some_File"); >> pragma Scoped (Close (COBOL_File)); >> >> loop >> ... >> exception >> when End_Error => ... >> end Test_External_Formats; >> And here is Stefan's construct: stefan-lucks@see-the.signature wrote: > I don't quite why this needs an extra pragma -- your example is, > apparently, easy to handle by current Ada's capacities: > > procedure New_Test_External_Formats is > ... > COBOL_File : File_Type; > > procedure Close_Cobol_File is > begin > Close(COBOL_FILE); > end Close_Cobol_File; > > Finisher: Finish_Package.Finisher; > -- The type Finish_Package.Finisher is derived from > -- Ada.Finalization.Limited_Controlled. > ... > > begin > Open (COBOL_File, Name => "Some_File"); > -- pragma Scoped (Close (COBOL_File)); > -- we don't need the pragma > Finisher.Set(Close_Cobol_File'Access); > -- we will call Close_Cobol_File > -- when Finisher goes out of scope > loop > ... > exception > when End_Error => ... > end Test_External_Formats; > > The only disadvantage of this approach, in comparison > to your pragma, is the need to define a parameterless > procedure Close_Cobol_File. But defining such parameterless > procedures is a design pattern you get used to anyway, > when working with Ada.Containers. And finally your tweak on Stefan's proposal: Florian Weimer wrote: > Or even this: > > COBOL_File : File_Type; > package Finisher_COBOL_File is > new Finisher (File_Type, COBOL_File, Close); > Curiously, it [Stefan's construct] shares many of the > things you [Niklas] criticize about pragma Scoped. I would like to discuss this. I criticized your "pragma Scoped" suggestion on these points: - Using a pragma to define flow of control. Stefan's construct does not use a pragma, so it escapes this criticism. - Violation of the principle that flow of control should match textual order (the procedure_call_statement in pragma Scoped would be executed later, at end of scope). This criticism can be applied to any use of implicitly invoked finalization, so it does apply to Stefan's construct, but it applies even more to my suggested alternative to pragma Scoped, which was new syntax of the form "at end do <statement>". However, since Ada now supports automatic, implicit finalization (a good thing), this principle cannot always be followed, and (as I admitted earlier) there are other arguments against the principle, too. I don't think we need to discuss it further. - The difficulty of defining and using your suggestions for the early evaluation and saving of the parameter values of the procedure_call_statement in "pragma Scoped". This does not apply to Stefan's construct since it does not save any parameters (because it is limited to a parameterless clean-up procedure). It might apply to your tweak in which the clean-up procedure has one parameter (COBOL_File in the example) that (depending on its generic formal mode) is perhaps evaluated and saved in the instantiation of the generic package Finisher. Do you propose mode "in" or mode "in out" for this parameter of package Finisher? - The fact that "pragma Scoped" was limited to scheduling a single procedure_call_statement at end of scope, rather than any kind of statement or statement sequence. Stefan's construct, and your tweak, have this limitation too, and even limit the kind of parameters that the call can have. In summary, as I see it, all these suggestions try to create a kind of "ad hoc" finalization code that could also have been done by wrapping the resource (COBOL_File) in a controlled type. The question is, do we need such an "ad hoc" finalization feature? Stefan showed that it can be done in the existing language by using a kind of general finalizable object or package that can play host to an arbitrary clean-up procedure. To me, this seems to introduce almost as much clutter as the nested block and exception-handling syntax that you considered cumbersome. Stefan says that such parameterless "helper" procedures are common when using Ada.Containers, but I believe that there are current proposals for new Ada syntax to avoid such procedures and instead write their statements "in line", for example in loops that iterate over containers, or statements that find and update a specific element in a container. >> - 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 idea was to implement it in an existing compiler if the semantics > are well-received. If you were to implement this pragma in an existing compiler as an extension -- which is of course your right -- and if the pragma were then extensively used, it would tend to constrain later standardization and force the standard to use or at least support such a pragma, to which my reaction is still negative. Is it really much simpler to implement "pragma Scoped" than to implement "at end do <statement>"? After all, both are syntactic sugar for Stefan's construct. >>> 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. > > In Java, I often see programmers using FileInputStream or Socket > without try-finally blocks, relying on the garbage collector to close > file descriptors. And of course garbage collection can be indefinitely delayed. Good example, thanks. I don't know Java well (on my list...) but IIUC Java does not provide end-of-scope finalization, as Ada does for controlled objects, so Stefan's construct is not available and try-finally is the only option left in Java. Perhaps it would be easier to use controlled objects than try-finally. I do understand the advantages of writing resource-deallocation (clean-up) code close to the resource-allocation code, an argument for "ad hoc" finalization. My main objections are to using a pragma and to any automatic saving of clean-up state. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-21 21:01 ` Florian Weimer 2010-08-22 10:53 ` Niklas Holsti @ 2010-08-22 11:32 ` Georg Bauhaus 2010-08-23 23:37 ` Randy Brukardt 1 sibling, 1 reply; 20+ messages in thread From: Georg Bauhaus @ 2010-08-22 11:32 UTC (permalink / raw) On 8/21/10 11:01 PM, Florian Weimer wrote: > * Niklas Holsti: >> [One may use blocks, this is Ada.] >> >> I find that form clear and brief enough, although I admit that >> nesting depth may become awkwardly large (the remedy is to split the >> procedure). > > No one will write such code unless forced to do so by some static > analysis tool. It's rather messy. (Even though there is some evidence that block nesting and disciplined manual cleanup has been considered messy here and there, backing this claim with data will help. Recent Python development may be a source of evidence, e.g. counting cleanup Bugs in old Python from a big installation such as Google App Engine, versus new Python and whatever programs are available for statistical analysis.) Wouldn't a new type based hook into the object life cycle fit the language better? At least if you use types to encapsulate objects that belong together. Wouldn't have compatibility problems, either, would it? Scope(whatever) ...; looks like a solution typical of {} languages: compare its "flexibility" with the "flexibility" of goto in C and Ada, respectively. I find it too compiler-writer-oriented, and somewhat ad hoc in use. How can it be bridled? Just my 2c. Georg ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-22 11:32 ` Georg Bauhaus @ 2010-08-23 23:37 ` Randy Brukardt 0 siblings, 0 replies; 20+ messages in thread From: Randy Brukardt @ 2010-08-23 23:37 UTC (permalink / raw) "Georg Bauhaus" <rm-host.bauhaus@maps.futureapps.de> wrote in message news:4c710ab7$0$6882$9b4e6d93@newsspool2.arcor-online.net... ... > Scope(whatever) ...; looks like a solution typical of {} languages: > compare its "flexibility" with the "flexibility" of goto in C and Ada, > respectively. I find it too compiler-writer-oriented, and somewhat > ad hoc in use. How can it be bridled? I agree, but I don't think it is "compiler-writer-oriented", because it doesn't fit into the things an Ada compiler is already doing. Which means it would be a massive new mess, unless it was implemented in terms of existing things. I'd probably implement it with an anonymous controlled object having the procedure call (conditionally) called from the Finalize routine. Probably would be a lot more expensive than just doing it right (using controlled types). Moreover, using pragmas for dynamic content is really an abuse of the concept, IMHO. The fact that the concept has been abused in the past doesn't make it OK to abuse it more. Randy. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-21 16:20 A suggestion for resource management Florian Weimer 2010-08-21 19:07 ` Dmitry A. Kazakov 2010-08-21 20:34 ` Niklas Holsti @ 2010-08-22 13:09 ` stefan-lucks 2010-08-22 14:30 ` Florian Weimer 2010-08-22 15:09 ` Florian Weimer 2 siblings, 2 replies; 20+ messages in thread From: stefan-lucks @ 2010-08-22 13:09 UTC (permalink / raw) On Sat, 21 Aug 2010, Florian Weimer wrote: > The example at the end of section B.4 could use the Scoped pragma in > this way: > > procedure Test_External_Formats is > ... > COBOL_File : File_Type; > ... > > begin > Open (COBOL_File, Name => "Some_File"); > pragma Scoped (Close (COBOL_File)); > > loop > ... > exception > when End_Error => ... > end Test_External_Formats; > I don't quite why this needs an extra pragma -- your example is, apparently, easy to handle by current Ada's capacities: procedure New_Test_External_Formats is ... COBOL_File : File_Type; procedure Close_Cobol_File is begin Close(COBOL_FILE); end Close_Cobol_File; Finisher: Finish_Package.Finisher; -- The type Finish_Package.Finisher is derived from -- Ada.Finalization.Limited_Controlled. ... begin Open (COBOL_File, Name => "Some_File"); -- pragma Scoped (Close (COBOL_File)); -- we don't need the pragma Finisher.Set(Close_Cobol_File'Access); -- we will call Close_Cobol_File -- when Finisher goes out of scope loop ... exception when End_Error => ... end Test_External_Formats; The only disadvantage of this approach, in comparison to your pragma, is the need to define a parameterless procedure Close_Cobol_File. But defining such parameterless procedures is a design pattern you get used to anyway, when working with Ada.Containers. -- ------ Stefan Lucks -- Bauhaus-University Weimar -- Germany ------ Stefan dot Lucks at uni minus weimar dot de ------ I love the taste of Cryptanalysis in the morning! ------ ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-22 13:09 ` stefan-lucks @ 2010-08-22 14:30 ` Florian Weimer 2010-08-22 15:09 ` Florian Weimer 1 sibling, 0 replies; 20+ messages in thread From: Florian Weimer @ 2010-08-22 14:30 UTC (permalink / raw) > I don't quite why this needs an extra pragma -- your example is, > apparently, easy to handle by current Ada's capacities: > > procedure New_Test_External_Formats is > ... > COBOL_File : File_Type; > > procedure Close_Cobol_File is > begin > Close(COBOL_FILE); > end Close_Cobol_File; > > Finisher: Finish_Package.Finisher; > -- The type Finish_Package.Finisher is derived from > -- Ada.Finalization.Limited_Controlled. > ... Or even this: COBOL_File : File_Type; package Finisher_COBOL_File is new Finisher (File_Type, COBOL_File, Close); That's actually quite nice, and can be implemented in Ada 2005. Unfortunately, GNAT still generates horrible code for this case, but that can be fixed. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: A suggestion for resource management 2010-08-22 13:09 ` stefan-lucks 2010-08-22 14:30 ` Florian Weimer @ 2010-08-22 15:09 ` Florian Weimer 1 sibling, 0 replies; 20+ messages in thread From: Florian Weimer @ 2010-08-22 15:09 UTC (permalink / raw) > I don't quite why this needs an extra pragma -- your example is, > apparently, easy to handle by current Ada's capacities: > > procedure New_Test_External_Formats is > ... > COBOL_File : File_Type; > > procedure Close_Cobol_File is > begin > Close(COBOL_FILE); > end Close_Cobol_File; > > Finisher: Finish_Package.Finisher; > -- The type Finish_Package.Finisher is derived from > -- Ada.Finalization.Limited_Controlled. > ... Or even this: COBOL_File : File_Type; package Finisher_COBOL_File is new Finisher (File_Type, COBOL_File, Close); That's actually quite nice, and can be implemented in Ada 2005. Unfortunately, GNAT still generates horrible code for this case, but that can be fixed. (One trivial improvement is to use your Finisher type in the implementation of the Finisher package; further improvements need some compiler work.) ^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2010-09-07 10:14 UTC | newest] Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2010-08-21 16:20 A suggestion for resource management Florian Weimer 2010-08-21 19:07 ` Dmitry A. Kazakov 2010-08-21 19:47 ` Florian Weimer 2010-08-21 20:53 ` Dmitry A. Kazakov 2010-08-21 21:09 ` Florian Weimer 2010-08-22 6:40 ` Dmitry A. Kazakov 2010-08-23 23:22 ` Randy Brukardt 2010-08-21 20:34 ` Niklas Holsti 2010-08-21 21:01 ` Florian Weimer 2010-08-22 10:53 ` Niklas Holsti 2010-08-22 15:29 ` Florian Weimer 2010-08-22 16:12 ` Florian Weimer 2010-08-23 12:25 ` Niklas Holsti 2010-09-04 19:09 ` Florian Weimer 2010-09-07 10:14 ` Niklas Holsti 2010-08-22 11:32 ` Georg Bauhaus 2010-08-23 23:37 ` Randy Brukardt 2010-08-22 13:09 ` stefan-lucks 2010-08-22 14:30 ` Florian Weimer 2010-08-22 15:09 ` Florian Weimer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox