comp.lang.ada
 help / color / mirror / Atom feed
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
       .      @       .



  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