comp.lang.ada
 help / color / mirror / Atom feed
* Re: Safety of the Booch Ada 95 Components
  1999-12-10  0:00 Safety of the Booch Ada 95 Components Harry Erwin
  1999-12-10  0:00 ` Simon Wright
@ 1999-12-10  0:00 ` Matthew Heaney
  1999-12-10  0:00   ` Hyman Rosen
  1999-12-10  0:00   ` Harry Erwin
  1999-12-13  0:00 ` Tucker Taft
  2 siblings, 2 replies; 29+ messages in thread
From: Matthew Heaney @ 1999-12-10  0:00 UTC (permalink / raw)


In article <1e2lds4.7trgj21rgj9i0N%herwin@gmu.edu> , herwin@gmu.edu 
(Harry Erwin) wrote:

> Now I've been looking at the Booch components for Ada 95, and have
> noticed that the Copy function typically starts by clearing the To
> container.

I haven't studied the Booch components specifically, but here's how Copy
operations should be implemented in general.

Assuming the data structure is implemented as a by-reference type (the
type is tagged and/or limited), you can invoke RM95 13.3 (16) to legally
compare the addresses of the subprogram parameters:

  procedure Copy
    (From : in     Source_Type;
     To   : in out Target_Type) is
  begin
    if From'Address = To'Address then
      return;  -- do nothing, because From is same object as To
    end if;

    Clear (To);  -- safe, because we now know To isn't From

    <do rest of copy>
  end Copy;

If the Booch Components don't first check whether aliasing has occurred,
prior to clearing the target object, then perhaps something is wrong.


> That immediately implies that they are not exception-safe,
> but I'm concerned that they may not be safe under self-assignment as
> well.

I don't understand your comment about not being "exception-safe."
Perhaps you could elaborate on that point.


>  Is there something about the Ada 95 standard that guarantees that
> there will be no aliasing of container args?

No, it's up to you the programmer to determine whether aliasing has
occurred.

The idiom for determining whether aliasing has occurred is to compare
object addresses, per RM95 13.3 (16).


--
Help keep evolution in the science classroom and religion out: become a
member of the National Center for Science Education.

<http://www.natcenscied.org/>





^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-10  0:00   ` Hyman Rosen
@ 1999-12-10  0:00     ` Matthew Heaney
  1999-12-11  0:00       ` Harry Erwin
  1999-12-13  0:00       ` Hyman Rosen
  1999-12-10  0:00     ` Harry Erwin
  1 sibling, 2 replies; 29+ messages in thread
From: Matthew Heaney @ 1999-12-10  0:00 UTC (permalink / raw)


In article <t790326901.fsf@calumny.jyacc.com> , Hyman Rosen 
<hymie@prolifics.com>  wrote:

> In C++, class objects are copied through a class method called the
> copy-constructor, to allow for resource control.

Data structures (in Ada95) are written as generics that accept the
container item as a nonlimited generic formal private type:

generic
  type Item_Type is private;
package Stacks is ...;

The "copy constructor" in Ada95 is just the assignment operator that
comes with Item_Type.  Typically, the client of the assignment operator
(here, the implementation of the Copy operation for stack types) assumes
that assignment doesn't raise an exception.

We make this assumption per the "design-by-contract" model.  If you give
me an assignment operator that doesn't work, and it raises an exception
(say), then yes, that would leave the target object in an inconsistent
state.

If you don't like that, then don't give me a broken assignment operator.

> If an exception is thrown during copy-construction of one of the elements,
> it's possible that the target data structure may be left in an invalid state.

I suppose if you don't trust your client's assignment operator, then you
could make a copy of the target object, clear the target, and then do
the copy.  If there's an error during assignment, then you use the copy
of the target to restore the target back to its original state, and then
reraise the exception.

(But then again, I don't know how you would even implement this.  How do
you make a copy of the target, if you can't trust the copy constructor
for items?)

But this is an awfully heavy way to implement a Copy operation for a
data structure.  The canonical implementation of a Copy operation should
choose the more efficient implementation, which assumes that assignment
works (again, per DBC).

If you don't like the canonical Copy, then just extend the abstraction
with a child operation implemented using the pessimistic algorithm
(which I'm not convinced is even implementable).

--
Why stop at evolution and cosmology, though? Let's make sure that the
schoolkids of Kansas get a really first-rate education by loosening up
the teaching standards for other so-called scientific ideas that are,
after all, just theories. The atomic theory, for example. The theory of
relativity. Heck, the Copernican theory--do we really know that the
universe doesn't revolve around the earth?

John Rennie, Scientific American, Oct 1999




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-10  0:00 Safety of the Booch Ada 95 Components Harry Erwin
@ 1999-12-10  0:00 ` Simon Wright
  1999-12-12  0:00   ` Simon Wright
  1999-12-12  0:00   ` Harry Erwin
  1999-12-10  0:00 ` Matthew Heaney
  1999-12-13  0:00 ` Tucker Taft
  2 siblings, 2 replies; 29+ messages in thread
From: Simon Wright @ 1999-12-10  0:00 UTC (permalink / raw)


herwin@gmu.edu (Harry Erwin) writes:

> In C++, the equate operation for a container class C<T> is preferably
> defined as follows (Sutter, Exceptional C++, Addison-Wesley, 2000):
> 
> template <typename T>
> C<T>& operator=(const C<T>& c)
> {
>     if(&c == this) return *this; // not required; done for efficiency
>     C temp(c); // uses the copy constructor, may throw
>     swap(temp, *this); // swaps the guts of this container with
>                        // temp. May not throw.
>     return *this; // May not throw.
> } // the destructor for temp releases the memory originally in this
>   // container, and destructors may not throw
> 
> This is strongly exception-safe and exception-neutral, since only the
> copy constructor can throw, and that occurs before the guts are swapped.
> Hence the container remains useable, and no objects are lost from it.
> Now I've been looking at the Booch components for Ada 95, and have
> noticed that the Copy function typically starts by clearing the To
> container. That immediately implies that they are not exception-safe,
> but I'm concerned that they may not be safe under self-assignment as
> well. Is there something about the Ada 95 standard that guarantees that
> there will be no aliasing of container args?

(1) the Copy subprogram -- in this case

  procedure Copy (From : Queue'Class; To : in out Queue'Class);

is used for copying queues using the same element type but different
storage allocation strategies (Bounded, Unbounded). It's the
equivalent of the C++

  virtual BC_TQueue<Item>& operator=(const BC_TQueue<Item>&);

in the abstract class template<class Item> class BC_TQueue.

(2) I'm not quite sure what should occur if an exception happened in
the middle of copying a queue; it would be reasonable to expect the
data structure to be uncorrupted, but you couldn't expect any
particular subset of the elements in the queue to have been copied.

Nevertheless, I need to look at this one ..

(3) The deep copy you expect on normal assignment of one Queue to
another (Second := First;) is managed by having them be Controlled:

  type Container is abstract new Ada.Finalization.Controlled with private;
  type Queue is abstract new Container with private;
  type Bounded_Queue is new Queue with private;

and (ALRM 7.6(17)):

  For an assignment_statement, after the name and expression have been
  evaluated, and any conversion (including constraint checking) has
  been done, an anonymous object is created, and the value is assigned
  into it; that is, the assignment operation is applied. (Assignment
  includes value adjustment.) The target of the assignment_statement
  is then finalized. The value of the anonymous object is then
  assigned into the target of the assignment_statement. Finally, the
  anonymous object is finalized. As explained below, the
  implementation may eliminate the intermediate anonymous object, so
  this description subsumes the one given in 5.2, ``Assignment
  Statements''.

GNAT 3.11p not only eliminates the intermediate anonymous object, it
special-cases the "A := A;" case; well, in the quick check I've just
run:

...
  Queue_B_P1, Queue_B_P2 : Queue_Finalization_Test.Queue;

begin

  Append (Queue_B_P2, '1');
  Append (Queue_B_P2, '2');
  Append (Queue_B_P2, '3');
  Append (Queue_B_P2, '4');

  Put_Line ("Queue_B_P2:");
  Print (Queue_B_P2);
  
  Queue_B_P1 := Queue_B_P2;
  Put_Line ("Queue_B_P1:");
  Print (Queue_B_P1);
  
  Queue_B_P1 := Queue_B_P1;
  Put_Line ("Queue_B_P1:");
  Print (Queue_B_P1);
...

outputs

initializing a Queue
initializing a Queue
Queue_B_P2:
Item: 1
Item: 2
Item: 3
Item: 4
finalizing a Queue
adjusting a Queue
Queue_B_P1:
Item: 1
Item: 2
Item: 3
Item: 4
Queue_B_P1:
Item: 1
Item: 2
Item: 3
Item: 4
finalizing a Queue
finalizing a Queue




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Safety of the Booch Ada 95 Components
@ 1999-12-10  0:00 Harry Erwin
  1999-12-10  0:00 ` Simon Wright
                   ` (2 more replies)
  0 siblings, 3 replies; 29+ messages in thread
From: Harry Erwin @ 1999-12-10  0:00 UTC (permalink / raw)


In C++, the equate operation for a container class C<T> is preferably
defined as follows (Sutter, Exceptional C++, Addison-Wesley, 2000):

template <typename T>
C<T>& operator=(const C<T>& c)
{
    if(&c == this) return *this; // not required; done for efficiency
    C temp(c); // uses the copy constructor, may throw
    swap(temp, *this); // swaps the guts of this container with
                       // temp. May not throw.
    return *this; // May not throw.
} // the destructor for temp releases the memory originally in this
  // container, and destructors may not throw

This is strongly exception-safe and exception-neutral, since only the
copy constructor can throw, and that occurs before the guts are swapped.
Hence the container remains useable, and no objects are lost from it.
Now I've been looking at the Booch components for Ada 95, and have
noticed that the Copy function typically starts by clearing the To
container. That immediately implies that they are not exception-safe,
but I'm concerned that they may not be safe under self-assignment as
well. Is there something about the Ada 95 standard that guarantees that
there will be no aliasing of container args?

-- 
Harry Erwin, PhD, <http://mason.gmu.edu/~herwin>




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-10  0:00 ` Matthew Heaney
@ 1999-12-10  0:00   ` Hyman Rosen
  1999-12-10  0:00     ` Matthew Heaney
  1999-12-10  0:00     ` Harry Erwin
  1999-12-10  0:00   ` Harry Erwin
  1 sibling, 2 replies; 29+ messages in thread
From: Hyman Rosen @ 1999-12-10  0:00 UTC (permalink / raw)


"Matthew Heaney" <matthew_heaney@acm.org> writes:
> I don't understand your comment about not being "exception-safe."
> Perhaps you could elaborate on that point.

In C++, class objects are copied through a class method called the
copy-constructor, to allow for resource control. If an exception is
thrown during copy-construction of one of the elements, it's possible
that the target data structure may be left in an invalid state.




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-10  0:00 ` Matthew Heaney
  1999-12-10  0:00   ` Hyman Rosen
@ 1999-12-10  0:00   ` Harry Erwin
  1999-12-12  0:00     ` Simon Wright
  1 sibling, 1 reply; 29+ messages in thread
From: Harry Erwin @ 1999-12-10  0:00 UTC (permalink / raw)


Matthew Heaney <matthew_heaney@acm.org> wrote:

> In article <1e2lds4.7trgj21rgj9i0N%herwin@gmu.edu> , herwin@gmu.edu 
> (Harry Erwin) wrote:
> 
> > Now I've been looking at the Booch components for Ada 95, and have
> > noticed that the Copy function typically starts by clearing the To
> > container.
> 
> I haven't studied the Booch components specifically, but here's how Copy
> operations should be implemented in general.
> 
> Assuming the data structure is implemented as a by-reference type (the
> type is tagged and/or limited), you can invoke RM95 13.3 (16) to legally
> compare the addresses of the subprogram parameters:
> 
>   procedure Copy
>     (From : in     Source_Type;
>      To   : in out Target_Type) is
>   begin
>     if From'Address = To'Address then
>       return;  -- do nothing, because From is same object as To
>     end if;

That's missing from the code I've been looking at.

> 
>     Clear (To);  -- safe, because we now know To isn't From
> 
>     <do rest of copy>
>   end Copy;
> 
> If the Booch Components don't first check whether aliasing has occurred,
> prior to clearing the target object, then perhaps something is wrong.
> 
> 
> > That immediately implies that they are not exception-safe,
> > but I'm concerned that they may not be safe under self-assignment as
> > well.
> 
> I don't understand your comment about not being "exception-safe."
> Perhaps you could elaborate on that point.

Strong exception-safety == supports commit/rollback semantics.
Apparently in the Booch components, if the copy goes bad, the To
container has been cleared and is partially written. Basic exception
safety (== the container is still useable) is probably supported.

> 
> 
> >  Is there something about the Ada 95 standard that guarantees that
> > there will be no aliasing of container args?
> 
> No, it's up to you the programmer to determine whether aliasing has
> occurred.

That may not be possible.

> 
> The idiom for determining whether aliasing has occurred is to compare
> object addresses, per RM95 13.3 (16).

Got it.  Thanks!

> 
> 
> --
> Help keep evolution in the science classroom and religion out: become a
> member of the National Center for Science Education.
> 
> <http://www.natcenscied.org/>


-- 
Harry Erwin, PhD, <http://mason.gmu.edu/~herwin>




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-10  0:00   ` Hyman Rosen
  1999-12-10  0:00     ` Matthew Heaney
@ 1999-12-10  0:00     ` Harry Erwin
  1 sibling, 0 replies; 29+ messages in thread
From: Harry Erwin @ 1999-12-10  0:00 UTC (permalink / raw)


Hyman Rosen <hymie@prolifics.com> wrote:

> "Matthew Heaney" <matthew_heaney@acm.org> writes:
> > I don't understand your comment about not being "exception-safe."
> > Perhaps you could elaborate on that point.
> 
> In C++, class objects are copied through a class method called the
> copy-constructor, to allow for resource control. If an exception is
> thrown during copy-construction of one of the elements, it's possible
> that the target data structure may be left in an invalid state.

And it usually takes some care to avoid that happening. Strong exception
safety goes even further, requiring commit/rollback semantics.

-- 
Harry Erwin, PhD, <http://mason.gmu.edu/~herwin>




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-10  0:00     ` Matthew Heaney
@ 1999-12-11  0:00       ` Harry Erwin
  1999-12-12  0:00         ` Robert Dewar
  1999-12-13  0:00       ` Hyman Rosen
  1 sibling, 1 reply; 29+ messages in thread
From: Harry Erwin @ 1999-12-11  0:00 UTC (permalink / raw)


Matthew Heaney <matthew_heaney@acm.org> wrote:

> In article <t790326901.fsf@calumny.jyacc.com> , Hyman Rosen 
> <hymie@prolifics.com>  wrote:
> 
> > In C++, class objects are copied through a class method called the
> > copy-constructor, to allow for resource control.
> 
> Data structures (in Ada95) are written as generics that accept the
> container item as a nonlimited generic formal private type:
> 
> generic
>   type Item_Type is private;
> package Stacks is ...;
> 
> The "copy constructor" in Ada95 is just the assignment operator that
> comes with Item_Type.  Typically, the client of the assignment operator
> (here, the implementation of the Copy operation for stack types) assumes
> that assignment doesn't raise an exception.
> 
> We make this assumption per the "design-by-contract" model.  If you give
> me an assignment operator that doesn't work, and it raises an exception
> (say), then yes, that would leave the target object in an inconsistent
> state.

Such exceptions in C++ are thrown if resources necessary for creating
the object are not available. These are most commonly memory, but
construction is the idiom used _in_general_ for resource management.
Also, in C++, termination semantics are default for exception handling.

> 
> If you don't like that, then don't give me a broken assignment operator.

A deep copy of a pointer data structure may require more memory than is
available. Similarly for a dynamic data structure. In C++, the
constructor throws a bad_alloc exception, and the class instance is
cleaned up. Not broken at all.

> 
> > If an exception is thrown during copy-construction of one of the
> > elements, it's possible that the target data structure may be left in an
> > invalid state.
> 
> I suppose if you don't trust your client's assignment operator, then you
> could make a copy of the target object, clear the target, and then do
> the copy.  If there's an error during assignment, then you use the copy
> of the target to restore the target back to its original state, and then
> reraise the exception.

template <typename T>
C<T>& operator= (const C(T)& c)
{
    if(this==&c) return *this; // for efficiency, not required
    C<T> temp(c); // may throw
    swap(temp,this); // swaps the guts, does not throw
    return *this; // does not throw
} // temp is deleted when it goes out of scope. does not throw

(per Sutter, 2000)

This idiom supports commit/rollback semantics.

> 
> (But then again, I don't know how you would even implement this.  How do
> you make a copy of the target, if you can't trust the copy constructor
> for items?)
> 
> But this is an awfully heavy way to implement a Copy operation for a
> data structure.  The canonical implementation of a Copy operation should
> choose the more efficient implementation, which assumes that assignment
> works (again, per DBC).
> 
> If you don't like the canonical Copy, then just extend the abstraction
> with a child operation implemented using the pessimistic algorithm
> (which I'm not convinced is even implementable).
> 
> --

-- 
Harry Erwin, PhD, <http://mason.gmu.edu/~herwin>




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-11  0:00       ` Harry Erwin
@ 1999-12-12  0:00         ` Robert Dewar
  1999-12-12  0:00           ` Harry Erwin
  1999-12-13  0:00           ` Kent Paul Dolan
  0 siblings, 2 replies; 29+ messages in thread
From: Robert Dewar @ 1999-12-12  0:00 UTC (permalink / raw)


In article <1e2ns7h.cx85ir1azwo9iN%herwin@gmu.edu>,
  herwin@gmu.edu (Harry Erwin) wrote:
> A deep copy of a pointer data structure may require more
> memory than is available.


A naive copy may have that characteristic, but it is always
possible on modern machines to do such a copy with no additional
storage. It just takes a bit of cleverness. Remember that every
pointer has at least two spare bits.


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-10  0:00 ` Simon Wright
@ 1999-12-12  0:00   ` Simon Wright
  1999-12-12  0:00     ` Matthew Heaney
  1999-12-12  0:00   ` Harry Erwin
  1 sibling, 1 reply; 29+ messages in thread
From: Simon Wright @ 1999-12-12  0:00 UTC (permalink / raw)


Simon Wright <simon@pogner.demon.co.uk> writes:

> herwin@gmu.edu (Harry Erwin) writes:
> 
> > In C++, the equate operation for a container class C<T> is preferably
> > defined as follows (Sutter, Exceptional C++, Addison-Wesley, 2000):
> > 
> > template <typename T>
> > C<T>& operator=(const C<T>& c)
> > {
> >     if(&c == this) return *this; // not required; done for efficiency
> >     C temp(c); // uses the copy constructor, may throw
> >     swap(temp, *this); // swaps the guts of this container with
> >                        // temp. May not throw.
> >     return *this; // May not throw.
> > } // the destructor for temp releases the memory originally in this
> >   // container, and destructors may not throw
> > 
> > This is strongly exception-safe and exception-neutral, since only the
> > copy constructor can throw, and that occurs before the guts are swapped.
> > Hence the container remains useable, and no objects are lost from it.
> > Now I've been looking at the Booch components for Ada 95, and have
> > noticed that the Copy function typically starts by clearing the To
> > container. That immediately implies that they are not exception-safe,
> > but I'm concerned that they may not be safe under self-assignment as
> > well. Is there something about the Ada 95 standard that guarantees that
> > there will be no aliasing of container args?
[...]
> (2) I'm not quite sure what should occur if an exception happened in
> the middle of copying a queue; it would be reasonable to expect the
> data structure to be uncorrupted, but you couldn't expect any
> particular subset of the elements in the queue to have been copied.
> 
> Nevertheless, I need to look at this one ..

.. and it seems fine to me, at least for queues. The structure is
still valid, though it's not possible to say what the contained values
are.

Harry sent me private mail to the effect that there do indeed seem to
be problems here with the BCs. Well, I don't agree; at least, not that
Harry's suggested semantics are any better in practice.

The postcondition of HA = HB; seems to be (primed names indicate
input values)

  HB == HB' and (HA == HB'
                 or an exception is raised and HA == HA')

In the last case, Harry is going to have to do something about HA,
because whatever else it means it does _not_ hold the value it should!
Perhaps it contains _last_ month's balance of his bank account,
perhaps it's the _old_ state of the helicopter's fuel supply ..

The BCs equivalent for assignment is (no warranties, remember)

  BB == BB' and (BA == BB'
                 or an exception is raised)

The above analysis with regard to exceptions holds also for the Copy
operation (between queues of the same element type but possibly with
different allocation strategies).

There is, however, a defect (OK, guys? :-) in the Copy operation,
since it fails under self-assignment. Oops. Logged.




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-10  0:00   ` Harry Erwin
@ 1999-12-12  0:00     ` Simon Wright
  1999-12-12  0:00       ` Harry Erwin
  0 siblings, 1 reply; 29+ messages in thread
From: Simon Wright @ 1999-12-12  0:00 UTC (permalink / raw)


herwin@gmu.edu (Harry Erwin) writes:

> Matthew Heaney <matthew_heaney@acm.org> wrote:
> 
> >   procedure Copy
> >     (From : in     Source_Type;
> >      To   : in out Target_Type) is
> >   begin
> >     if From'Address = To'Address then
> >       return;  -- do nothing, because From is same object as To
> >     end if;
> 
> That's missing from the code I've been looking at.

Yes, a clear defect, logged.

> Strong exception-safety == supports commit/rollback semantics.

Is that a standard definition?

> Apparently in the Booch components, if the copy goes bad, the To
> container has been cleared and is partially written. Basic exception
> safety (== the container is still useable) is probably supported.

Yes, this is the case for the Copy operation (which is *not* the
standard assignment operation!).

In a previous reply, I quoted the ALRM [7.6(17)] on controlled
assignment. I must say I don't fully understand from that what is
expected. At first (& nth) sight I don't see how one could achieve
your idea of strong exception safety.

I wonder what happens in C++ STL-based programming if operator new
fails in the middle of things?




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-12  0:00   ` Simon Wright
@ 1999-12-12  0:00     ` Matthew Heaney
  0 siblings, 0 replies; 29+ messages in thread
From: Matthew Heaney @ 1999-12-12  0:00 UTC (permalink / raw)


In article <x7vu2lowfr2.fsf@pogner.demon.co.uk> , Simon Wright 
<simon@pogner.demon.co.uk>  wrote:

> The BCs equivalent for assignment is (no warranties, remember)
>
>   BB == BB' and (BA == BB'
>                  or an exception is raised)

That's exactly it.

Yes, this lacks "rollback semantics," but I'm perfectly happy with this
postcondition, as it's likely to be far more efficient than its stronger
alternative:

   HB == HB' and (HA == HB'
                  or an exception is raised and HA == HA')

I'd be willing to bet that most systems programmers would NOT be
satisfied with this postcondition, if they knew how inefficient it is
compared to the other.

Perhaps there is a middle position.  We could guarantee that if
assignment fails, then the target data structure is cleared, instead of
being left in some unknown state:

  HB == HB' and (HA == HB'
                 or an exception is raised and HA.Length == 0)


--
The political forces that try to eliminate evolution from science
classrooms impose a narrow, sectarian doctrine on our educational
systems. This imposition represents an affront not only to the
constitutional separation of church and state but also to the moral and
intellectual integrity embedded in that constitution.

<http://www.nabt.org/evolutionks.html>




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-12  0:00     ` Simon Wright
@ 1999-12-12  0:00       ` Harry Erwin
  1999-12-13  0:00         ` Simon Wright
  0 siblings, 1 reply; 29+ messages in thread
From: Harry Erwin @ 1999-12-12  0:00 UTC (permalink / raw)


Simon Wright <simon@pogner.demon.co.uk> wrote:

> herwin@gmu.edu (Harry Erwin) writes:
> 
> > Matthew Heaney <matthew_heaney@acm.org> wrote:
> > 
> > >   procedure Copy
> > >     (From : in     Source_Type;
> > >      To   : in out Target_Type) is
> > >   begin
> > >     if From'Address = To'Address then
> > >       return;  -- do nothing, because From is same object as To
> > >     end if;
> > 
> > That's missing from the code I've been looking at.
> 
> Yes, a clear defect, logged.

That's the feedback I needed.  Thanks.

> 
> > Strong exception-safety == supports commit/rollback semantics.
> 
> Is that a standard definition?

Herb Sutter, Exceptional C++, Addison-Wesley, 2000, page 38.

"2. Strong guarantee: If an operation terminates because of an
exception, program state will remain unchanged. This always implies
commit-or-rollback semantics, including that no references or iterators
into the container be invalidated if an operation fails. . . ."

Also see <http://www.metabyte.com/~fbp/stl/eh_contract.html>

> 
> > Apparently in the Booch components, if the copy goes bad, the To
> > container has been cleared and is partially written. Basic exception
> > safety (== the container is still useable) is probably supported.
> 
> Yes, this is the case for the Copy operation (which is *not* the
> standard assignment operation!).

What is the standard assignment operation, then?  I'm new to Ada 95.  In
C++ 99, we rarely trust the compiler-defined default versions of copy
constructors and assignment operations, because they do bit-by-bit
copies. 

> 
> In a previous reply, I quoted the ALRM [7.6(17)] on controlled
> assignment. I must say I don't fully understand from that what is
> expected. At first (& nth) sight I don't see how one could achieve
> your idea of strong exception safety.
> 
> I wonder what happens in C++ STL-based programming if operator new
> fails in the middle of things?

The constructor is rolled back, with destructors applied in reverse
order to all the data members that were successfully constructed, and
then the memory is returned to the free store.  Finally, the bad_alloc
exception is thrown. Eventually a catch block for bad_alloc is
encountered as the function calls are unwound on the stack, and the
processing is done there. Or, eventually, the main function is unwound,
and the program is terminated.

-- 
Harry Erwin, PhD, <http://mason.gmu.edu/~herwin>




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-10  0:00 ` Simon Wright
  1999-12-12  0:00   ` Simon Wright
@ 1999-12-12  0:00   ` Harry Erwin
  1999-12-13  0:00     ` Simon Wright
  1 sibling, 1 reply; 29+ messages in thread
From: Harry Erwin @ 1999-12-12  0:00 UTC (permalink / raw)


Simon Wright <simon@pogner.demon.co.uk> wrote:

> herwin@gmu.edu (Harry Erwin) writes:
> 
> > In C++, the equate operation for a container class C<T> is preferably
> > defined as follows (Sutter, Exceptional C++, Addison-Wesley, 2000):
> > 
> > template <typename T>
> > C<T>& operator=(const C<T>& c)
> > {
> >     if(&c == this) return *this; // not required; done for efficiency
> >     C temp(c); // uses the copy constructor, may throw
> >     swap(temp, *this); // swaps the guts of this container with
> >                        // temp. May not throw.
> >     return *this; // May not throw.
> > } // the destructor for temp releases the memory originally in this
> >   // container, and destructors may not throw
> > 
> > This is strongly exception-safe and exception-neutral, since only the
> > copy constructor can throw, and that occurs before the guts are swapped.
> > Hence the container remains useable, and no objects are lost from it.
> > Now I've been looking at the Booch components for Ada 95, and have
> > noticed that the Copy function typically starts by clearing the To
> > container. That immediately implies that they are not exception-safe,
> > but I'm concerned that they may not be safe under self-assignment as
> > well. Is there something about the Ada 95 standard that guarantees that
> > there will be no aliasing of container args?
> 
> (1) the Copy subprogram -- in this case
> 
>   procedure Copy (From : Queue'Class; To : in out Queue'Class);
> 
> is used for copying queues using the same element type but different
> storage allocation strategies (Bounded, Unbounded). It's the
> equivalent of the C++
> 
>   virtual BC_TQueue<Item>& operator=(const BC_TQueue<Item>&);

In C++ 99, we'd use:

C1<T> source;   //      assume initialized
C2<T> destination(source.begin(), source.end());  // strongly safe

This uses the copy constructor with two iterator arguments. 

Or we'd use:

destination.insert(position, source.begin(), source.edu());

which, like your Copy, is not strongly safe.

> 
> in the abstract class template<class Item> class BC_TQueue.
> 
> (2) I'm not quite sure what should occur if an exception happened in
> the middle of copying a queue; it would be reasonable to expect the
> data structure to be uncorrupted, but you couldn't expect any
> particular subset of the elements in the queue to have been copied.
> 
> Nevertheless, I need to look at this one ..
> 
> (3) The deep copy you expect on normal assignment of one Queue to
> another (Second := First;) is managed by having them be Controlled:
> 
>   type Container is abstract new Ada.Finalization.Controlled with private;
>   type Queue is abstract new Container with private;
>   type Bounded_Queue is new Queue with private;
> 
> and (ALRM 7.6(17)):
> 
>   For an assignment_statement, after the name and expression have been
>   evaluated, and any conversion (including constraint checking) has
>   been done, an anonymous object is created, and the value is assigned
>   into it; that is, the assignment operation is applied. (Assignment
>   includes value adjustment.) The target of the assignment_statement
>   is then finalized. The value of the anonymous object is then
>   assigned into the target of the assignment_statement. Finally, the
>   anonymous object is finalized. As explained below, the
>   implementation may eliminate the intermediate anonymous object, so
>   this description subsumes the one given in 5.2, ``Assignment
>   Statements''.

Thanks.  I'll nose around into this.  It looks like the Ada language
hides a lot of the detail that a C++ 99 student has to learn to be anal
about.

> 
> GNAT 3.11p not only eliminates the intermediate anonymous object, it
> special-cases the "A := A;" case; well, in the quick check I've just
> run:
> 
> ...
>   Queue_B_P1, Queue_B_P2 : Queue_Finalization_Test.Queue;
> 
> begin
> 
>   Append (Queue_B_P2, '1');
>   Append (Queue_B_P2, '2');
>   Append (Queue_B_P2, '3');
>   Append (Queue_B_P2, '4');
> 
>   Put_Line ("Queue_B_P2:");
>   Print (Queue_B_P2);
>   
>   Queue_B_P1 := Queue_B_P2;
>   Put_Line ("Queue_B_P1:");
>   Print (Queue_B_P1);
>   
>   Queue_B_P1 := Queue_B_P1;
>   Put_Line ("Queue_B_P1:");
>   Print (Queue_B_P1);
> ...
> 
> outputs
> 
> initializing a Queue
> initializing a Queue
> Queue_B_P2:
> Item: 1
> Item: 2
> Item: 3
> Item: 4
> finalizing a Queue
> adjusting a Queue
> Queue_B_P1:
> Item: 1
> Item: 2
> Item: 3
> Item: 4
> Queue_B_P1:
> Item: 1
> Item: 2
> Item: 3
> Item: 4
> finalizing a Queue
> finalizing a Queue

Good, so self-assignment works.

-- 
Harry Erwin, PhD, <http://mason.gmu.edu/~herwin>




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-12  0:00         ` Robert Dewar
@ 1999-12-12  0:00           ` Harry Erwin
  1999-12-13  0:00           ` Kent Paul Dolan
  1 sibling, 0 replies; 29+ messages in thread
From: Harry Erwin @ 1999-12-12  0:00 UTC (permalink / raw)


Robert Dewar <robert_dewar@my-deja.com> wrote:

> In article <1e2ns7h.cx85ir1azwo9iN%herwin@gmu.edu>,
>   herwin@gmu.edu (Harry Erwin) wrote:
> > A deep copy of a pointer data structure may require more
> > memory than is available.
> 
> 
> A naive copy may have that characteristic, but it is always
> possible on modern machines to do such a copy with no additional
> storage. It just takes a bit of cleverness. Remember that every
> pointer has at least two spare bits.
> 

If what you're suggesting is sharing the underlying data, it's risky in
C++ since we have to manage the free store explicitly, rather than
relying on garbage collection. It is done that way for STL strings, but
there are some known problems, especially in a multithreaded
environment.

In any case, this discussion has been very educational. I now know where
in the documentation to go look for answers.

With thanks,
-- 
Harry Erwin, PhD, <http://mason.gmu.edu/~herwin>




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-13  0:00           ` Kent Paul Dolan
  1999-12-13  0:00             ` Robert I. Eachus
@ 1999-12-13  0:00             ` Ted Dennison
  1999-12-13  0:00             ` Simon Wright
  2 siblings, 0 replies; 29+ messages in thread
From: Ted Dennison @ 1999-12-13  0:00 UTC (permalink / raw)


In article <Yk354.42$tb.10677@news.wenet.net>,
  xanthian@well.com (Kent Paul Dolan) wrote:
> AmigaBASIC, whose developers assumed that the 24 bits in use of 32 bit
> pointers they saw when the machine in an early OS rev would be the law
> forever, ignored the developer manuals warnings to the contrary, used
> the other 8 bits for string lengths or some such, in a petty search

Yikes, why did you have to remind me of that? I had a pretty neat
basketball game on my 1000, but on the 2000 the ball turned into a
square brown blotch. I could still play it, but my wife called it
"basketbrick". :-)

--
T.E.D.


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-10  0:00 Safety of the Booch Ada 95 Components Harry Erwin
  1999-12-10  0:00 ` Simon Wright
  1999-12-10  0:00 ` Matthew Heaney
@ 1999-12-13  0:00 ` Tucker Taft
  2 siblings, 0 replies; 29+ messages in thread
From: Tucker Taft @ 1999-12-13  0:00 UTC (permalink / raw)


Harry Erwin wrote:
> ... I'm concerned that they may not be safe under self-assignment as
> well. Is there something about the Ada 95 standard that guarantees that
> there will be no aliasing of container args?

No.  On the other hand, self-assignment is always safe in Ada,
even if the type is controlled, because the "official" semantic model
is that there is an anonymous intermediary object created for
an assignment statement (see RM95 7.6(17)).  If a compiler "optimizes"
this away, it must not create problems with self-assignment.

The simplest way to avoid creating self-assignment problems is to take
advantage of RM95 7.6(19) which says self-assignment may be implemented as a 
no-op.  This permission, plus the ability to do slice-assignment either
left-to-right or right-to-left, means that there is never a need
for an intermediary object in an assignment (and our front end never 
creates one).  

From other responses, it sounds like GNAT uses this approach as well.
But whatever (non-buggy ;-) approach the compiler uses, self-assignment is always safe in Ada.

> Harry Erwin, PhD, <http://mason.gmu.edu/~herwin>

-- 
-Tucker Taft   stt@averstar.com   http://www.averstar.com/~stt/
Technical Director, Distributed IT Solutions  (www.averstar.com/tools)
AverStar (formerly Intermetrics, Inc.)   Burlington, MA  USA




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-12  0:00   ` Harry Erwin
@ 1999-12-13  0:00     ` Simon Wright
  0 siblings, 0 replies; 29+ messages in thread
From: Simon Wright @ 1999-12-13  0:00 UTC (permalink / raw)


herwin@gmu.edu (Harry Erwin) writes:

>                                       It looks like the Ada language
> hides a lot of the detail that a C++ 99 student has to learn to be anal
> about.

Not sure that "hides" is the right word there! If you mean "defines in
the standard", OK .. or "defines in such a way you don't need to
worry"!

> Good, so self-assignment works.

Turns out that one of the free compilers has a serious bug^H^H^Hdefect
here (or else it's me .. usually it's me ..)




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-13  0:00           ` Kent Paul Dolan
  1999-12-13  0:00             ` Robert I. Eachus
  1999-12-13  0:00             ` Ted Dennison
@ 1999-12-13  0:00             ` Simon Wright
  2 siblings, 0 replies; 29+ messages in thread
From: Simon Wright @ 1999-12-13  0:00 UTC (permalink / raw)


xanthian@well.com (Kent Paul Dolan) writes:

> Robert Dewar  <robert_dewar@my-deja.com> wrote:
> >  herwin@gmu.edu (Harry Erwin) wrote:
> >> A deep copy of a pointer data structure may require more
> >> memory than is available.
> 
> >A naive copy may have that characteristic, but it is always
> >possible on modern machines to do such a copy with no additional
> >storage. It just takes a bit of cleverness. Remember that every
> >pointer has at least two spare bits.
> 
> This one sets alarm bells ringing like crazy.  I was a user of
> AmigaBASIC, whose developers assumed that the 24 bits in use of 32 bit
> pointers they saw when the machine in an early OS rev would be the law
> forever, ignored the developer manuals warnings to the contrary, used
> the other 8 bits for string lengths or some such, in a petty search for
> "efficiency" at the expense of clean coding, and had their software die
> a horrible death when the OS was upgraded within a couple of years to
> use all 32 bits of a pointer.

I suspect Robert was thinking of the low-order 2 bits (on the
assumption that malloc() always returns something longword-aligned. I
rather thought it was often 16-byte-aligned??).




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-12  0:00       ` Harry Erwin
@ 1999-12-13  0:00         ` Simon Wright
  0 siblings, 0 replies; 29+ messages in thread
From: Simon Wright @ 1999-12-13  0:00 UTC (permalink / raw)


herwin@gmu.edu (Harry Erwin) writes:

> Simon Wright <simon@pogner.demon.co.uk> wrote:
[...]
> > > Apparently in the Booch components, if the copy goes bad, the To
> > > container has been cleared and is partially written. Basic exception
> > > safety (== the container is still useable) is probably supported.
> > 
> > Yes, this is the case for the Copy operation (which is *not* the
> > standard assignment operation!).
> 
> What is the standard assignment operation, then?  I'm new to Ada 95.  In
> C++ 99, we rarely trust the compiler-defined default versions of copy
> constructors and assignment operations, because they do bit-by-bit
> copies. 

The standard Ada assignment operation is :=

However, it's not an operation that you have control over in the way
that C++ gives you with operator=.

What you do have is Controlled types (types that inherit from
Ada.Finalization.Controlled).

From ALRM,

7.6 User-Defined Assignment and Finalization

(1) Three kinds of actions are fundamental to the manipulation of
     objects: initialization, finalization, and assignment. Every
     object is initialized, either explicitly or by default, after
     being created (for example, by an object_declaration or
     allocator).  Every object is finalized before being destroyed
     (for example, by leaving a subprogram_body containing an
     object_declaration, or by a call to an instance of
     Unchecked_Deallocation). An assignment operation is used as part
     of assignment_statements, explicit initialization, parameter
     passing, and other operations.

(2) Default definitions for these three fundamental operations are
     provided by the language, but a controlled type gives the user
     additional control over parts of these operations. In particular,
     the user can define, for a controlled type, an Initialize
     procedure which is invoked immediately after the normal default
     initialization of a controlled object, a Finalize procedure which
     is invoked immediately before finalization of any of the
     components of a controlled object, and an Adjust procedure which
     is invoked as the last step of an assignment to a (nonlimited)
     controlled object.

[...]

(17) For an assignment_statement, after the name and expression have
     been evaluated, and any conversion (including constraint
     checking) has been done, an anonymous object is created, and the
     value is assigned into it; that is, the assignment operation is
     applied. (Assignment includes value adjustment.) The target of
     the assignment_statement is then finalized. The value of the
     anonymous object is then assigned into the target of the
     assignment_statement. Finally, the anonymous object is
     finalized. As explained below, the implementation may eliminate
     the intermediate anonymous object, so this description subsumes
     the one given in 5.2, ``Assignment Statements''.

I don't think there's a web version of the ALRM at
www.adapower.com. There is one at www.adahome.com (no longer
maintained, it seems, but still with goodies like this).




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-12  0:00         ` Robert Dewar
  1999-12-12  0:00           ` Harry Erwin
@ 1999-12-13  0:00           ` Kent Paul Dolan
  1999-12-13  0:00             ` Robert I. Eachus
                               ` (2 more replies)
  1 sibling, 3 replies; 29+ messages in thread
From: Kent Paul Dolan @ 1999-12-13  0:00 UTC (permalink / raw)


Robert Dewar  <robert_dewar@my-deja.com> wrote:
>  herwin@gmu.edu (Harry Erwin) wrote:
>> A deep copy of a pointer data structure may require more
>> memory than is available.

>A naive copy may have that characteristic, but it is always
>possible on modern machines to do such a copy with no additional
>storage. It just takes a bit of cleverness. Remember that every
>pointer has at least two spare bits.

This one sets alarm bells ringing like crazy.  I was a user of
AmigaBASIC, whose developers assumed that the 24 bits in use of 32 bit
pointers they saw when the machine in an early OS rev would be the law
forever, ignored the developer manuals warnings to the contrary, used
the other 8 bits for string lengths or some such, in a petty search for
"efficiency" at the expense of clean coding, and had their software die
a horrible death when the OS was upgraded within a couple of years to
use all 32 bits of a pointer.

I can already trick out a Mac G4 box with a gig of physical memory for
an obscene price, (but lower than the tag on a pretty old used car, and
less than the cost of a megabyte of memory retail in 1981), and not one
revision down the line support for a second gig will be in place, one
of your spare pointer bits has disappeared and gone, and your code is
broken.  Did you remember to instrument the breaks to be easily
located, and pre-design a workaround for conditional compilation or
conditional linking into place?

Some "efficiencies" aren't worth the risk, and the damage to pointer
semantics of using some bits for "non-pointer purposes" would be nearly
incalculable.

Oh, and did you lock your structures against traversal by other threads
while the (possibly time consuming) deep copy was ongoing, or are the
munged pointers going to be visible outside the deep copy process?

[I'd say "I am but an egg" here, w.r.t. my compiler writing near
non-experience, but some "eggs" hatched out moa birds, after all.]
--
Kent Paul Dolan.
<xanthian@well.com> <xanthian@aztec.asu.edu> <xanthian@whistle.com>
Using modern technology to commit errors at previously unachievable rates.




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-10  0:00     ` Matthew Heaney
  1999-12-11  0:00       ` Harry Erwin
@ 1999-12-13  0:00       ` Hyman Rosen
  1999-12-13  0:00         ` Robert I. Eachus
  1999-12-14  0:00         ` Matthew Heaney
  1 sibling, 2 replies; 29+ messages in thread
From: Hyman Rosen @ 1999-12-13  0:00 UTC (permalink / raw)


"Matthew Heaney" <matthew_heaney@acm.org> writes:
> We make this assumption per the "design-by-contract" model.  If you give
> me an assignment operator that doesn't work, and it raises an exception
> (say), then yes, that would leave the target object in an inconsistent
> state.
> 
> If you don't like that, then don't give me a broken assignment operator.

Why is an assignment operator that raises an exception broken?




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-13  0:00           ` Kent Paul Dolan
@ 1999-12-13  0:00             ` Robert I. Eachus
  1999-12-13  0:00             ` Ted Dennison
  1999-12-13  0:00             ` Simon Wright
  2 siblings, 0 replies; 29+ messages in thread
From: Robert I. Eachus @ 1999-12-13  0:00 UTC (permalink / raw)


Kent Paul Dolan wrote:
  
> This one sets alarm bells ringing like crazy.  I was a user of
> AmigaBASIC, whose developers assumed that the 24 bits in use of 32 bit
> pointers they saw when the machine in an early OS rev would be the law
> forever, ignored the developer manuals warnings to the contrary, used
> the other 8 bits for string lengths or some such, in a petty search for
> "efficiency" at the expense of clean coding, and had their software die
> a horrible death when the OS was upgraded within a couple of years to
> use all 32 bits of a pointer.

  1) The Amiga coding standards from day one emphasized "32-bit" clean,
since
there were already plans for a 68020 based machine.  (In fact, the first
68020 demo I saw, under non-disclosure, was running AmigaDOS 1.1.)

  2) Actually the problem was that it stored pointers in 3 bytes, not 4,
I 
think I still have the patch to fix it floating around.  (It was an
extremely small patch.)

  3) The developer of AmigaBASIC was Microsoft, and they refused to make
the
fix even when asked by Commodore.

  4) That was why AmigaBASIC was dropped in the next version of
AmigaDOS.
    
> Some "efficiencies" aren't worth the risk, and the damage to pointer
> semantics of using some bits for "non-pointer purposes" would be nearly
> incalculable.

    I think that Robert Dewar was referring to the low-order two bits,
which
were, of course, unavailable in Microsoft's AmigaBASIC.
 
> Oh, and did you lock your structures against traversal by other threads
> while the (possibly time consuming) deep copy was ongoing, or are the
> munged pointers going to be visible outside the deep copy process?

    You had better do lcoking in any case.  But since the flipped bits
can be in your new data structure only, you don't have to worry about
some other assignment geting at them.

-- 

                                        Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-13  0:00       ` Hyman Rosen
@ 1999-12-13  0:00         ` Robert I. Eachus
  1999-12-14  0:00           ` Simon Wright
  1999-12-14  0:00         ` Matthew Heaney
  1 sibling, 1 reply; 29+ messages in thread
From: Robert I. Eachus @ 1999-12-13  0:00 UTC (permalink / raw)




Hyman Rosen wrote:
 
> Why is an assignment operator that raises an exception broken?

   It isn't.  But in Ada, an assignment that raises an exception does so
before actually "copying the bits."  So that objects that were
consistant are not broken except by an explicit abort from some other
task while outside an abort-deferred region.  However, one explicit
abort-deferred operation is: "an assignment operation to an object with
a controlled part." RM9.8(11)  There other such operations included so
that a user of an object of a controlled type can expect that the value
is never corrupted.

   So any user of an Ada package which did corrupt objects in this
manner would be consider it to be broken.
 
-- 

                                        Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-13  0:00         ` Robert I. Eachus
@ 1999-12-14  0:00           ` Simon Wright
  1999-12-15  0:00             ` Harry Erwin
  1999-12-15  0:00             ` Mats Weber
  0 siblings, 2 replies; 29+ messages in thread
From: Simon Wright @ 1999-12-14  0:00 UTC (permalink / raw)


"Robert I. Eachus" <eachus@mitre.org> writes:

> Hyman Rosen wrote:
>  
> > Why is an assignment operator that raises an exception broken?
> 
>    It isn't.  But in Ada, an assignment that raises an exception does so
> before actually "copying the bits."

I don't believe this is true. See LRM 7.6(2).

>                                      So that objects that were
> consistant are not broken except by an explicit abort from some other
> task while outside an abort-deferred region.  However, one explicit
> abort-deferred operation is: "an assignment operation to an object with
> a controlled part." RM9.8(11)  There other such operations included so
> that a user of an object of a controlled type can expect that the value
> is never corrupted.
> 
>    So any user of an Ada package which did corrupt objects in this
> manner would be consider it to be broken.

Since (LRM 7.6(2)) Adjust is called as the _last_ step of an
assignment, I don't see how the provider of an Ada package can do as
you ask.

I'm going to do a deep copy.

I have an object containing a pointer to the value that has been
assigned, so I need to make the deep copy and then put a pointer to
the copy in the current object.

If that fails, presumably because of memory exhaustion, I can

(1) make sure that the assignee has a valid but partial copy

(2) make sure that the assignee has a null pointer

(3) leave the assignee pointing to the value that has been assigned,
    so that the copy isn't deep after all

(4) not bother

In *none* of these cases is the assignee "valid". Whether that equates
to being "corrupt" is a question I prefer to leave to the reader ..




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-13  0:00       ` Hyman Rosen
  1999-12-13  0:00         ` Robert I. Eachus
@ 1999-12-14  0:00         ` Matthew Heaney
  1 sibling, 0 replies; 29+ messages in thread
From: Matthew Heaney @ 1999-12-14  0:00 UTC (permalink / raw)


In article <t7g0x64nw6.fsf@calumny.jyacc.com> , Hyman Rosen 
<hymie@prolifics.com>  wrote:

>> If you don't like that, then don't give me a broken assignment operator.
>
> Why is an assignment operator that raises an exception broken?

Perhaps the case is better stated in terms of the postcondition of the
copy.  If item assignment raises an exception during a copy of a data
structure (which contains zero or more items), then

1) You can implement Copy without handling item assignment errors.  This
is the most efficient way to implement copy, but it will leave the
target data structure in an unknown state.

2) You can implement Copy so that if item assignment raises an
exception, then the target data structure is cleared or only a partial
copy.  This is slightly less efficient than (1) -- unless your compiler
implements zero-cost exception handlers -- but it has the virtue of
guaranteeing the target state.

3) You can implement Copy so that if assignment raises an exception,
then the target data structure is rolled back to its original state
prior to the call.  This is much less efficient than (1), but has the
virtue of leaving target state unchanged.

So take your pick.  As with all system design problems, there is no such
thing as a free lunch, and you're going to have to live with some
compromise.

--
It is impossible to feel great confidence in a negative theory which has
always rested its main support on the weak points of its opponent.

Joseph Needham, "A Mechanistic Criticism of Vitalism"




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-14  0:00           ` Simon Wright
  1999-12-15  0:00             ` Harry Erwin
@ 1999-12-15  0:00             ` Mats Weber
  1999-12-17  0:00               ` Simon Wright
  1 sibling, 1 reply; 29+ messages in thread
From: Mats Weber @ 1999-12-15  0:00 UTC (permalink / raw)


Simon Wright wrote:

> I'm going to do a deep copy.
> 
> I have an object containing a pointer to the value that has been
> assigned, so I need to make the deep copy and then put a pointer to
> the copy in the current object.
> 
> If that fails, presumably because of memory exhaustion, I can
> 
> (1) make sure that the assignee has a valid but partial copy
> 
> (2) make sure that the assignee has a null pointer
> 
> (3) leave the assignee pointing to the value that has been assigned,
>     so that the copy isn't deep after all
> 
> (4) not bother

(5) raise or propagate and exception. I think this is the only right
thing to do. Being tagged, controlled types are passed by reference, so
you can also make sure the target of the assignement has a null pointer.

> In *none* of these cases is the assignee "valid". Whether that equates
> to being "corrupt" is a question I prefer to leave to the reader ..

How could it possibly be valid if memory is exhausted, in any
programming language ?




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-14  0:00           ` Simon Wright
@ 1999-12-15  0:00             ` Harry Erwin
  1999-12-15  0:00             ` Mats Weber
  1 sibling, 0 replies; 29+ messages in thread
From: Harry Erwin @ 1999-12-15  0:00 UTC (permalink / raw)


Simon Wright <simon@pogner.demon.co.uk> wrote:

> "Robert I. Eachus" <eachus@mitre.org> writes:
> 
> > Hyman Rosen wrote:
> >  
> > > Why is an assignment operator that raises an exception broken?
> > 
> >    It isn't.  But in Ada, an assignment that raises an exception does so
> > before actually "copying the bits."
> 
> I don't believe this is true. See LRM 7.6(2).
> 
> >                                      So that objects that were
> > consistant are not broken except by an explicit abort from some other
> > task while outside an abort-deferred region.  However, one explicit
> > abort-deferred operation is: "an assignment operation to an object with
> > a controlled part." RM9.8(11)  There other such operations included so
> > that a user of an object of a controlled type can expect that the value
> > is never corrupted.
> > 
> >    So any user of an Ada package which did corrupt objects in this
> > manner would be consider it to be broken.
> 
> Since (LRM 7.6(2)) Adjust is called as the _last_ step of an
> assignment, I don't see how the provider of an Ada package can do as
> you ask.
> 
> I'm going to do a deep copy.
> 
> I have an object containing a pointer to the value that has been
> assigned, so I need to make the deep copy and then put a pointer to
> the copy in the current object.
> 
> If that fails, presumably because of memory exhaustion, I can
> 
> (1) make sure that the assignee has a valid but partial copy
> 
> (2) make sure that the assignee has a null pointer
> 
> (3) leave the assignee pointing to the value that has been assigned,
>     so that the copy isn't deep after all
> 
> (4) not bother
> 
> In *none* of these cases is the assignee "valid". Whether that equates
> to being "corrupt" is a question I prefer to leave to the reader ..

For comparison, the C++ 98 solution is that the deep copy will throw a
bad_alloc exception, and return the memory to the free store. If the
deep copy was being done as an initialization step during a constructor,
the constructor is unwound, and the bad_alloc exception propagates up.
If the deep copy was being done in a different context, the calling
routine needs to catch the bad_alloc exception, or it will propagate up.
STL containers will be left usable (and for most operations, unchanged
and with their iterators still valid).  The pointer being assigned to,
if it is still in scope after the bad_alloc is caught, will have its
original value. If that was corrupt, it will still be corrupt. I teach
my students to habitually tie off all pointers so that they either point
to valid memory or have the sentinel value of 0, so that delete and
delete[] will work correctly.

-- 
Harry Erwin, PhD, <http://mason.gmu.edu/~herwin>




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Safety of the Booch Ada 95 Components
  1999-12-15  0:00             ` Mats Weber
@ 1999-12-17  0:00               ` Simon Wright
  0 siblings, 0 replies; 29+ messages in thread
From: Simon Wright @ 1999-12-17  0:00 UTC (permalink / raw)


Mats Weber <matsw@mail.com> writes:

> Simon Wright wrote:
> 
> > I'm going to do a deep copy.
> > 
> > I have an object containing a pointer to the value that has been
> > assigned, so I need to make the deep copy and then put a pointer to
> > the copy in the current object.
> > 
> > If that fails, presumably because of memory exhaustion, I can
[...]
> (5) raise or propagate and exception. I think this is the only right
> thing to do. Being tagged, controlled types are passed by reference, so
> you can also make sure the target of the assignement has a null pointer.

I forgot to say that I was going to do that anyway! thanks for the
note ..




^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~1999-12-17  0:00 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-12-10  0:00 Safety of the Booch Ada 95 Components Harry Erwin
1999-12-10  0:00 ` Simon Wright
1999-12-12  0:00   ` Simon Wright
1999-12-12  0:00     ` Matthew Heaney
1999-12-12  0:00   ` Harry Erwin
1999-12-13  0:00     ` Simon Wright
1999-12-10  0:00 ` Matthew Heaney
1999-12-10  0:00   ` Hyman Rosen
1999-12-10  0:00     ` Matthew Heaney
1999-12-11  0:00       ` Harry Erwin
1999-12-12  0:00         ` Robert Dewar
1999-12-12  0:00           ` Harry Erwin
1999-12-13  0:00           ` Kent Paul Dolan
1999-12-13  0:00             ` Robert I. Eachus
1999-12-13  0:00             ` Ted Dennison
1999-12-13  0:00             ` Simon Wright
1999-12-13  0:00       ` Hyman Rosen
1999-12-13  0:00         ` Robert I. Eachus
1999-12-14  0:00           ` Simon Wright
1999-12-15  0:00             ` Harry Erwin
1999-12-15  0:00             ` Mats Weber
1999-12-17  0:00               ` Simon Wright
1999-12-14  0:00         ` Matthew Heaney
1999-12-10  0:00     ` Harry Erwin
1999-12-10  0:00   ` Harry Erwin
1999-12-12  0:00     ` Simon Wright
1999-12-12  0:00       ` Harry Erwin
1999-12-13  0:00         ` Simon Wright
1999-12-13  0:00 ` Tucker Taft

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