From: Niklas Holsti <niklas.holsti@tidorum.invalid>
Subject: Re: A suggestion for resource management
Date: Sun, 22 Aug 2010 13:53:52 +0300
Date: 2010-08-22T13:53:52+03:00 [thread overview]
Message-ID: <8dcdu1F4v9U1@mid.individual.net> (raw)
In-Reply-To: <87eidr3cje.fsf@mid.deneb.enyo.de>
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
. @ .
next prev parent reply other threads:[~2010-08-22 10:53 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
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
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox