Re: Why I don't believe in static typing

From: Steven E. Harris (seharris_at_raytheon.com)
Date: 11/19/03


Date: Wed, 19 Nov 2003 12:49:40 -0800

Joachim Durchholz <joachim.durchholz@web.de> writes:

> You are also unsafe if the destructor has side effects such as
> modifying global data, since it's an effect that isn't represented
> syntactically (which means that the effect will most likely be
> overlooked during code review - a nasty source of potential errors).

Sometimes using a destructor in the RAII idiom is the only way to
achieve safety without code duplication, whether or not it has effect
on "global" data or any data with wider scope. Consider that
destruction may be triggered by exception-induced stack
unwinding. RAII makes "do/undo" actions both safe and concise.

Consider this simple example, from production code:

,----[ overlay.hh ]
| #ifndef OVERLAY_HH
| #define OVERLAY_HH
|
| #include "noncopyable.hh"
|
|
| template <typename T>
| class overlay : noncopyable
| {
| public:
| typedef T value_type;
|
| overlay(value_type& val,
| const value_type& overlaid_value)
| : val_( val ),
| original_value_( val_ )
| { val_ = overlaid_value; }
|
| ~overlay()
| { val_ = original_value_; }
|
| private:
| value_type& val_;
| const value_type original_value_;
| };
|
|
| #endif // OVERLAY_HH
`----

An "overlay" is temporary, scoped assignment to some other mutable
variable that will be undone upon the overlay's destruction, similar
to Perl's "local" declaration or layered assignment to special
variables in CL.

Assuming that the value_type's assignment operator can't throw an
exception, using an overlay is safe and is safer than writing four
separate, explicit assignment statements (one to store the original
value, one to change the value, another to restore the original value
under normal exit, and yet another to restore the value in case of a
caught exception, presumably before rethrowing).

The cleanup is not represented syntactically, but the symmetric
promise is: I may change this variable here, and I will change it back
before going away.

{
   int i = 0;

   try
   {
      const overlay<int> o( i, 1 );
      // We're not leaving until i is 0 again.

      std::cout << i << '\n';

      throw std::runtime_error( "bang!" );
   }
   catch ( ... )
   { std::cout << i << '\n'; }
}

-- 
Steven E. Harris        :: seharris@raytheon.com
Raytheon                :: http://www.raytheon.com


Relevant Pages

  • Re: C# Language Proposal for out Parameters
    ... >> If the assignment isn't made because an exception has been thrown, ... inout semantics, not to mention reducing overall clarity of the code. ... The fundamental problem is that GetNewValue would ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Controlled types and exception safety
    ... >> propagate an exception. ... >> For an Adjust invoked as part of an assignment operation, ... But a user-defined constructor is ... a user-defined constructor has just turned on the ...
    (comp.lang.ada)
  • Re: Pop Quiz: Raising an exception inside a function in relation to the return values.
    ... (If the exception were raised if (Random<0.50), ... Simply pretend the raise is a return and you ll see the difference. ... No second assignment ever happens. ... try-except statements switch back ...
    (alt.comp.lang.borland-delphi)
  • Re: Default values of functions
    ... query: TGCQuery; ... exception, the return value would be that value. ... So I agree that the return value of this function could be undefined if the assignment is ignored by the compiler. ... If the calling code called the function inside a "try" section, then execution, upon leaving the called function, will go to the "finally" section of the caller, if there is one, or to the "except" section of the caller, if there is one with the appropriate exception type. ...
    (comp.lang.pascal.delphi.misc)