comp.lang.ada
 help / color / mirror / Atom feed
From: Maciej Sobczak <no.spam@no.spam.com>
Subject: Controlled types and exception safety
Date: Wed, 30 Nov 2005 14:57:07 +0100
Date: 2005-11-30T14:57:07+01:00	[thread overview]
Message-ID: <dmkb3j$h4q$1@sunnews.cern.ch> (raw)

Hi,

I try to understad how the Controlled types work and I spotted one 
"small issue" that makes it difficult to write exception-safe code.

The "exception-safe" means that code behaves "correctly" in the presence 
of exceptions, for some chosen definition of "correctly".
In C++ we define the following levels of exception-safety:
- level 0 (no guarantee) - in the presence of exception, anything can 
happen, memory may become corrupted, data structures may become 
completely mangled, etc.
- level 1 (basic guarantee) - in the presence of exception, no resources 
are leaked and objects are in a coherent, but not necessarily 
predictable state.
- level 2 (strong guarantee) - in the presence of exception, the program 
state (to the relevant extent) remains unchanged. This is similar to the 
commit-or-rollback semantics known from databases.
- level 3 (nothrow guarantee) - the code simply guarantees that there 
are no exceptions.

Why is this classification useful? Let's say that I have an abstract 
data type that implements some data structure - a stack, for example. I 
can classify the stack's operations by assigning them any of the above 
four levels, so that I know what can be expected when an exception is 
thrown for any reason (like inability to allocate more memory, or 
alike). For example, if the Push method of the stack gives me the strong 
guarantee (level 2 above), then I *know* that by calling this method 
either the new element will be appended to the stack, or the stack will 
remain unchanged, so that even if the exception is thrown, I don't have 
to worry about the stack's internal consistency.
This is useful.

This is useful also in assignment operations. Since stack can be a 
dynamic data structure, assigning one stack object to another may 
involve destroying one existing data structure *and* creating a new one 
(a copy) in its place. Similarly, the quality implementation should 
provide the strong guarantee, so that I *know* that either the stack was 
properly copied, or there was a problem during assignment and an 
exception was thrown, but nothing changed in any of the objects involved.

Let's say that I want to write a stack in Ada. Making it a Controlled 
type seems to be a good idea, so that we have hooks for initialization, 
adjusting and finalization. Let's say that I have two stack objects, X 
and Y:

X, Y : Stack;

These objects were populated with some data, so that each of them 
manages its own internal dynamic data structure.
Now, I do this:

X := Y;

and the following happens (this is what I understand, please correct me 
if I'm wrong):

1. X is finalized. This allows me to clean up (free) its internal data.
2. Y is *shallow-copied* to X, so that in effect X and Y share their state.
3. X is adjusted. This allows me to duplicate its internal structure so 
that it becomes independent from Y.

later:
4. Both X and Y are finalized. This allows me to clean up (free) their 
resources.

For everything to work correctly it's important that two separate stack 
objects *never* share their internal dynamic data structure, otherwise 
bad things can happen. It would be also fine not to leak memory.

Now, the interesting part: let's say that during adjustment (3.) some 
error happened (like low memory condition or whatever) that resulted in 
raising an exception (note: this exception might be actually raisen not 
by the stack code, but by the assignment operation of the stack 
elements, even somewhere in the middle of this process).
Bad things will happen in subsequent finalization of those objects, 
unless I handle it by cleaning up everything that I already managed to 
duplicate (but still, this leaves me with the empty stack).


I think that the inherent problem comes from the fact that the 
finalization of X was forced *before* its adjustment.
The canonical C++ way is to *first* make a copy of new value (because 
this is when errors might occur, so that even if they occur, there was 
no change in the destination object) and *then* inject the duplicate 
into the destination object, getting rid of its old state (and this is 
assumed to be nothrow).

The "Ada way" looks like selling the house *before* looking for the new one.

What do you do to avoid surprises?


-- 
Maciej Sobczak : http://www.msobczak.com/
Programming    : http://www.msobczak.com/prog/



             reply	other threads:[~2005-11-30 13:57 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-11-30 13:57 Maciej Sobczak [this message]
2005-11-30 15:06 ` Controlled types and exception safety Dmitry A. Kazakov
2005-11-30 16:19   ` Maciej Sobczak
2005-12-01  0:05     ` Stephen Leake
2005-12-01  9:21     ` Dmitry A. Kazakov
2005-12-01 10:46       ` Maciej Sobczak
2005-12-01 15:08         ` Dmitry A. Kazakov
2005-12-02  4:17           ` Randy Brukardt
2005-12-02  9:29             ` Maciej Sobczak
2005-12-02 18:12               ` tmoran
2005-12-02 19:15                 ` Robert A Duff
2005-12-02 21:42                   ` tmoran
2005-12-06  9:00                     ` Maciej Sobczak
2005-12-06  9:50                       ` Dmitry A. Kazakov
2005-12-06 18:34                         ` Jeffrey R. Carter
2005-12-06 19:34                           ` Randy Brukardt
2005-12-06 21:20                             ` Dmitry A. Kazakov
2005-12-07  1:57                             ` Jeffrey R. Carter
2005-12-08  0:50                               ` Randy Brukardt
2005-12-08 19:37                                 ` Jeffrey R. Carter
2005-12-09  2:36                                   ` Randy Brukardt
2005-12-09  6:33                                     ` Jeffrey R. Carter
2005-12-09 20:35                                       ` Randy Brukardt
2005-12-10  7:53                                         ` Jeffrey R. Carter
2005-12-06 20:43                           ` Dmitry A. Kazakov
2005-12-07  2:00                             ` Jeffrey R. Carter
2005-12-07 10:01                               ` Dmitry A. Kazakov
2005-12-02 23:21             ` Robert A Duff
2005-11-30 17:46 ` Jean-Pierre Rosen
2005-11-30 21:02 ` Jeffrey R. Carter
2005-11-30 22:06   ` Björn Persson
2005-11-30 23:52     ` Randy Brukardt
2005-12-01  5:26     ` Jeffrey R. Carter
2005-12-02 23:51       ` Robert A Duff
2005-12-06 11:41   ` Peter C. Chapin
2005-12-06 12:50     ` Jean-Pierre Rosen
2005-12-06 13:06     ` Dmitry A. Kazakov
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox