Clean up after exception thrown in constructor

  • Follow


Hello

I have a class hierarchy where the constructor of a child class ("Ford") 
can throw an exception, while the constructor of the parent class 
("Car") has some side-effects.
If construction fails due to the Exception on the child class being 
thrown, the side-effect of the parent constructor cannot be cleaned up.

What would be a better approach to this problem, so that if construction 
fails for whatever reason, the system is left in a pristine state?

Thanks for your advice
Phil

Example SSCCE:
package exceptionInCtor;

import java.util.ArrayList;
import java.util.List;

public class Car {
   private static List<String> nameList = new ArrayList<String>();
   private String name;

   public Car(String name){
     nameList.add(name); // name is added to list as side-effect
     this.name = name;
   }

   public void remove(){ // called when car is no longer used
     nameList.remove(name);
   }

   public static class Ford extends Car{
     public Ford(String name, int wheels){
       super(name);
       if(wheels > 4){
         throw new IllegalArgumentException("Too many wheels");
       }
     }
   }


   public static void main(String[] args) {
     Car c = null;
     try{
       c = new Ford("myFord", 5);
     } catch (Exception e) {
       // cannot call c.remove() here!
       e.printStackTrace();
     }

     System.out.println(c); // prints null
     System.out.println(nameList); // prints [myFord], should be empty
   }
}

0
Reply sicsicsic (164) 4/15/2008 1:38:38 PM

This is an OpenPGP/MIME signed message (RFC 2440 and 3156)
--------------enigA7899F9A7548A70E301EAE1B
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable

Philipp schreef:
> Hello
>=20
> I have a class hierarchy where the constructor of a child class ("Ford"=
)=20
> can throw an exception, while the constructor of the parent class=20
> ("Car") has some side-effects.
> If construction fails due to the Exception on the child class being=20
> thrown, the side-effect of the parent constructor cannot be cleaned up.=

>=20
> What would be a better approach to this problem, so that if constructio=
n=20
> fails for whatever reason, the system is left in a pristine state?
>=20
> Thanks for your advice
> Phil
>=20
> Example SSCCE:
> package exceptionInCtor;
>=20
> import java.util.ArrayList;
> import java.util.List;
>=20
> public class Car {
>   private static List<String> nameList =3D new ArrayList<String>();
>   private String name;
>=20
>   public Car(String name){
>     nameList.add(name); // name is added to list as side-effect
>     this.name =3D name;
>   }
>=20
>   public void remove(){ // called when car is no longer used
>     nameList.remove(name);
>   }
>=20
>   public static class Ford extends Car{
>     public Ford(String name, int wheels){
>       super(name);
>       if(wheels > 4){
>         throw new IllegalArgumentException("Too many wheels");
>       }
>     }
>   }
>=20
>=20
>   public static void main(String[] args) {
>     Car c =3D null;
>     try{
>       c =3D new Ford("myFord", 5);
>     } catch (Exception e) {
>       // cannot call c.remove() here!
>       e.printStackTrace();
>     }
>=20
>     System.out.println(c); // prints null
>     System.out.println(nameList); // prints [myFord], should be empty
>   }
> }

Since nameList is static, you could provide a static remove(String name) =

method, and call that from the catch block.

Better though for constructors not to have side-effects.  You could use=20
the Factory pattern and have the factory keep the name list.

H.
--=20
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html


--------------enigA7899F9A7548A70E301EAE1B
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.4-svn0 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iD8DBQFIBLFUe+7xMGD3itQRArbdAJ9nH3d53jEcobOpbpn+uZLpK4yVggCfToV/
q23LkotqIJx9d2CZebvTw+8=
=6zk+
-----END PGP SIGNATURE-----

--------------enigA7899F9A7548A70E301EAE1B--
0
Reply gtw37bn02 (214) 4/15/2008 1:44:49 PM


Philipp <sicsicsic@freesurf.ch> writes:
>I have a class hierarchy where the constructor of a child class ("Ford") 
>can throw an exception, while the constructor of the parent class 
>("Car") has some side-effects.
>If construction fails due to the Exception on the child class being 
>thrown, the side-effect of the parent constructor cannot be cleaned up.
>
>What would be a better approach to this problem, so that if construction 
>fails for whatever reason, the system is left in a pristine state?

  First, save all results of calls that might fail (throw)
  into temporaries.

  Then, perform the side effects with operations that cannot
  fail (throw), for example, copy temporaries to permanent
  variables.

  This is called �exception-safe programming�.

      �Widget& Widget::operator=( const Widget& other )
      {
        Widget temp( other ); // do all the work off to the side
        Swap( temp );    // then "commit" the work using
        return *this;    //  nonthrowing operations only
      }�

http://www.gotw.ca/gotw/059.htm

  See also:

http://www.gotw.ca/gotw/061.htm
 
0
Reply ram (2827) 4/15/2008 1:48:52 PM

On Tue, 15 Apr 2008 15:38:38 +0200  Philipp wrote:
> What would be a better approach to this problem, so that if construction 
> fails for whatever reason, the system is left in a pristine state?
> 
> public class Car {
>    private static List<String> nameList = new ArrayList<String>();
Prolly not a good idea, as it is not threadsafe.

>    private String name;
> 
>    public Car(String name){

        this.name = name; 
     }

Create an initialize-method where you add the name to the list (register). 
      public void register() {
               nameList.add( name );
       }          


>    public static class Ford extends Car{
>      public Ford(String name, int wheels){
>        super(name);
>        if(wheels > 4){
>          throw new IllegalArgumentException("Too many wheels");
>        }
	else {
           register();
        }
>      }
>    }

Then you can first check the arguments and postpone the initialization
until you are pretty sure about that the arguments are correct. But of
course you can then forget to call register.. 

Otherwise you can call remove in the if-part
>        if(wheels > 4){
           remove();
>          throw new IllegalArgumentException("Too many wheels");
>        }

Neither way is very elegant. A better way would be a car factory which does
the registration and also is thread safe:

class CarFactory {
     private List<String> carNames;   
 
    public <T extends Car> create( Class<T> clazz ) {
      T result = ... use reflection to create an instance...
      register( result );
    }

    private synchronized void register(Car c) {
           carNames.add(c.getName());
    }
}

Jan
0
Reply kork (75) 4/15/2008 2:00:32 PM

Philipp writes:
>> I have a class hierarchy where the constructor of a child class ("Ford") 
>> can throw an exception, while the constructor of the parent class 
>> ("Car") has some side-effects.
>> If construction fails due to the Exception on the child class being 
>> thrown, the side-effect of the parent constructor cannot be cleaned up.
>>
>> What would be a better approach to this problem, so that if construction 
>> fails for whatever reason, the system is left in a pristine state?

Stefan Ram wrote:
>   First, save all results of calls that might fail (throw)
>   into temporaries.
> 
>   Then, perform the side effects with operations that cannot
>   fail (throw), for example, copy temporaries to permanent
>   variables.
> 
>   This is called »exception-safe programming«.
> 
>       »Widget& Widget::operator=( const Widget& other )
>       {
>         Widget temp( other ); // do all the work off to the side
>         Swap( temp );    // then "commit" the work using
>         return *this;    //  nonthrowing operations only
>       }«

My Java compiler doesn't seem to handle this example very well.

Of course, there is an equivalent idiom in Java, but I'm not sure it handles 
the OP's issue.  The parent class cannot know that the child class's part of 
the constructor will demand an unwind of the setup actions.  The child class 
will need appropriate try-catch semantics:

  public Child()
  {
   try
   {
    somethingThatThrows()
   }
   catch( Exception exc )
   {
     unwindParentClassActions();
     throw exc;
   }
  }

Since the parent constructor cannot unwind the actions, obviously the child 
constructor has to.

One might want to move the child method that could throw an exception out of 
the constructor.  Also the parent class actions that create side effects could 
move out of that constructor.  It's a tough call.  Constructors ideally should 
only do what's necessary for construction of an object in memory.  This makes 
one push side effects out into methods.  However, RAII ("Resource Acquisition 
is Initialization") argues that a resource should attach to the lifetime of 
its respective resource manager, which in turn leads one to put the resource 
acquisition in the constructor.  But then one runs into cases like the current 
matter, where some client of the code messes with the assumptions.

Perhaps the child class shouldn't really inherit from the parent.  Perhaps it 
should compose an instance of the resource manager instead of deriving from it.

-- 
Lew
0
Reply lew (2143) 4/15/2008 2:13:10 PM

> Philipp schreef:
>> I have a class hierarchy where the constructor of a child class
>> ("Ford") can throw an exception, while the constructor of the
>> parent class
>> ("Car") has some side-effects.
>> If construction fails due to the Exception on the child class being
>> thrown, the side-effect of the parent constructor cannot be cleaned up.

Where I learnt Java they told me two things about constructors:
 1.) don't store away the "this" pointer!  The object belongs to
       who created it (with "new"), and only the owner shall 
       decide where to keep it, and who to pass it on.
 2.) Don't throw exceptions from constructors.

ad 1:
   Specifically with non-final classes, this can easily lead
   to access of not-yet-completely initialized objects: Even
   if the Ford-constructor did not throw an exception, other
   threads might see the object (through the list) just before
   Ford's c'tor has completed it's job.
ad 2:
   I remember the rule, but not the exact reasons :-)

Hendrik Maryns <gtw37bn02@sneakemail.com> wrote:
> Better though for constructors not to have side-effects.
Hmm, even stricter.

> You could use the Factory pattern and have the factory
> keep the name list.
That's of course the solution for such demands.
0
Reply avl1 (2656) 4/15/2008 2:40:14 PM

Why would u need to clean up.  U arnt using any system resources, the
garbage collector will do all cleanup for u.  And any cleanup should
be done in the finally or catch block.
0
Reply chasepreuninger (165) 4/15/2008 11:38:24 PM

Philipp wrote:
> I have a class hierarchy where the constructor of a child class ("Ford") 
> can throw an exception, while the constructor of the parent class 
> ("Car") has some side-effects.
> If construction fails due to the Exception on the child class being 
> thrown, the side-effect of the parent constructor cannot be cleaned up.
> 
> What would be a better approach to this problem, so that if construction 
> fails for whatever reason, the system is left in a pristine state?

I would drop doing the stuff in constructors and do it in
ordinary methods. That will give you more freedom
to code exception handling as you want.

Arne
0
Reply arne6 (9485) 4/16/2008 1:24:53 AM

Chase Preuninger wrote:
> Why would u need to clean up.  U arnt using any system resources, the
> garbage collector will do all cleanup for u.  And any cleanup should
> be done in the finally or catch block.

Wow.  Why is it too much work to type the "yo" part of the word "you"?  Just 
spelling it "u" looks singularly jejune.

GC does not do "all cleanup for u [sic]".  It releases memory.  That's all. 
The OP spoke of side effects.  They didn't say these effects were limited to 
memory; in context one would reasonably conclude that they were not.  Ergo, 
cleanup is very definitely a concern.

-- 
Lew
0
Reply lew (2143) 4/16/2008 4:17:45 AM

Arne Vajh�j wrote:
> Philipp wrote:
>> I have a class hierarchy where the constructor of a child class 
>> ("Ford") can throw an exception, while the constructor of the parent 
>> class ("Car") has some side-effects.
>> If construction fails due to the Exception on the child class being 
>> thrown, the side-effect of the parent constructor cannot be cleaned up.
>>
>> What would be a better approach to this problem, so that if 
>> construction fails for whatever reason, the system is left in a 
>> pristine state?
> 
> I would drop doing the stuff in constructors and do it in
> ordinary methods. That will give you more freedom
> to code exception handling as you want.

Thanks to all for your answers. I learned a lot just by reading about 
exception safety which was triggered by this thread.

In fact, I will follow the advice of several and add a register() method 
which can handle the exception properly. Naturally, this puts the burden 
of calling register() and remove() at the right moments on the programmer.

The two main other options, namely creating the instance using a factory 
and using composition rather than inheritance represent a too large code 
change for the expected result. In a future in-depth refactoring I will 
definitely take these solutions into account.

Phil
0
Reply sicsicsic (164) 4/16/2008 6:22:05 AM

Philipp wrote:
> The two main other options, namely creating the instance using a factory 
> and using composition rather than inheritance represent a too large code 
> change for the expected result. In a future in-depth refactoring I will 
> definitely take these solutions into account.

PS: Could someone recommend some reference about why exceptions in 
constructors are bad. In particular, if the constructor has no side 
effects, I can't understand what the problem is in having exceptions.

Phil
0
Reply sicsicsic (164) 4/16/2008 6:30:35 AM

On Tue, 15 Apr 2008 23:30:35 -0700, Philipp <sicsicsic@freesurf.ch> wrote:

> PS: Could someone recommend some reference about why exceptions in  
> constructors are bad. In particular, if the constructor has no side  
> effects, I can't understand what the problem is in having exceptions.

I can't either.  :)

Seriously though, lots of classes in the Java SDK can throw exceptions  
 from the constructor.  I didn't read any of the messages in this thread as  
being anti-exception in a constructor.  Just anti-side-effects.  And of  
course it seems as though you _do_ understand at least some of why  
side-effects in a constructor are bad (frankly, they're not great  
anywhere, but it seems to me they are especially non-optimal in a  
constructor).

I suppose if someone was specifically arguing against constructors  
throwing exceptions, they will respond explaining why.  If that happened  
in this thread, I missed it.

I don't personally think that there's anything fundamentally wrong with  
throwing an exception from a constructor.  After all, every "new" can  
potentially throw at least one exception (out-of-memory).  And throwing an  
exception from a constructor is the only way to report an error (be it an  
invalid parameter, some problem with the current state of the program,  
etc.)

Pete
0
Reply NpOeStPeAdM (1107) 4/16/2008 6:40:21 AM

Philipp <sicsicsic@freesurf.ch> writes:
>PS: Could someone recommend some reference about why exceptions in 
>constructors are bad. In particular, if the constructor has no side 
>effects, I can't understand what the problem is in having exceptions.

  For exception-safe programming, it helps when the constructor
  does not has other side effects than the instance creation.
  Otherwise, one needs to add a finally-clause to undo this.

  I do not deem throwing constructors bad style. I believe that
  exceptions even became popular in object oriented languages,
  to support throwing constructors: A constructor cannot return
  an error code. So exceptions are needed to communicate errors.

0
Reply ram (2827) 4/16/2008 12:12:50 PM

Philipp wrote:
>> PS: Could someone recommend some reference about why exceptions in 
>> constructors are bad. In particular, if the constructor has no side 
>> effects, I can't understand what the problem is in having exceptions.

Peter Duniho wrote:
> I can't either.  :)
> 
> Seriously though, lots of classes in the Java SDK can throw exceptions 
> from the constructor.  I didn't read any of the messages in this thread 
> as being anti-exception in a constructor.  Just anti-side-effects.  And 
> of course it seems as though you _do_ understand at least some of why 
> side-effects in a constructor are bad (frankly, they're not great 
> anywhere, but it seems to me they are especially non-optimal in a 
> constructor).
> ... 
> I don't personally think that there's anything fundamentally wrong with 
> throwing an exception from a constructor.  After all, every "new" can 
> potentially throw at least one exception (out-of-memory).  And throwing 
> an exception from a constructor is the only way to report an error (be 
> it an invalid parameter, some problem with the current state of the 
> program, etc.)

I agree, throwing an exception from a constructor is perfectly legitimate if 
properly documented.  One problematic area is constructors that are invoked 
reflectively, as via a framework or to load a driver.  The framework must 
expect the exceptions that can be thrown; if it assumes none can be and the 
constructor throws one, it would be trouble.

Philipp wrote:
>> In fact, I will follow the advice of several and add a register() method which 
>> can handle the exception properly. Naturally, this puts the burden of calling 
>> register() and remove() at the right moments on the programmer.

You can assist the client code with checks for proper state in the service 
methods.  If register() has not been called yet, then doWork() can throw an 
IllegalStateException.  Calling on an improperly initialized object is a 
programming error, so a runtime exception is appropriate.

Even though runtime exceptions are not declared in the method signature, you 
should still document them with an '@throws' in the Javadoc.

-- 
Lew
0
Reply lew (2143) 4/16/2008 12:16:33 PM

Lew wrote:
> Chase Preuninger wrote:
>> Why would u need to clean up.  U arnt using any system resources, the
>> garbage collector will do all cleanup for u.  And any cleanup should
>> be done in the finally or catch block.

> GC does not do "all cleanup for u [sic]".  It releases memory.  That's 
> all. The OP spoke of side effects.  They didn't say these effects were 
> limited to memory; in context one would reasonably conclude that they 
> were not.  Ergo, cleanup is very definitely a concern.

Also, in this specific example, the garbage collector won't be able to
collect everything.  There is a String that has been added to a static
list of Strings.  The garbage collector can't collect that because it
is still live data.

   - Logan
0
Reply lshaw-usenet (926) 4/19/2008 4:58:09 PM

Philipp wrote:

|> PS: Could someone recommend some reference about why exceptions in 
|> constructors are bad. In particular, if the constructor has no side 
|> effects, I can't understand what the problem is in having exceptions.

One practical reason might be that, in upper layer methods of layered
architectures, you want to catch lower layer exception types thrown
from lower layer methods, and if you can't handle them, throw new
exceptions of upper layer exception types. But you are not allowed
to put the super() call inside a try...catch construct. So, callers
of your upper layer constructor will have to know about and deal with
lower layer exceptions.

-- 

"I'm a doctor, not a mechanic." Dr Leonard McCoy <mccoy@ncc1701.starfleet.fed>
"I'm a mechanic, not a doctor." Volker Borchert  <v_borchert@despammed.com>
0
Reply v_borchert (106) 4/19/2008 6:07:57 PM

Lew wrote:

|> I agree, throwing an exception from a constructor is perfectly legitimate if 
|> properly documented.  One problematic area is constructors that are invoked 
|> reflectively, as via a framework or to load a driver.  The framework must 
|> expect the exceptions that can be thrown; if it assumes none can be and the 
|> constructor throws one, it would be trouble.

Not really, since exceptions thrown from reflexive construction will
generally be wrapped into a (checked) InstantiationException.

-- 

"I'm a doctor, not a mechanic." Dr Leonard McCoy <mccoy@ncc1701.starfleet.fed>
"I'm a mechanic, not a doctor." Volker Borchert  <v_borchert@despammed.com>
0
Reply v_borchert (106) 4/19/2008 6:11:55 PM

Philipp wrote:
> Hello
> 
> I have a class hierarchy where the constructor of a child class ("Ford") 
> can throw an exception, while the constructor of the parent class 
> ("Car") has some side-effects.
> If construction fails due to the Exception on the child class being 
> thrown, the side-effect of the parent constructor cannot be cleaned up.
> 
> What would be a better approach to this problem, so that if construction 
> fails for whatever reason, the system is left in a pristine state?
> 
> Thanks for your advice
> Phil
> 
> Example SSCCE:
> package exceptionInCtor;
> 
> import java.util.ArrayList;
> import java.util.List;
> 
> public class Car {
>   private static List<String> nameList = new ArrayList<String>();
>   private String name;
> 
>   public Car(String name){
>     nameList.add(name); // name is added to list as side-effect
>     this.name = name;
>   }
> 
>   public void remove(){ // called when car is no longer used
>     nameList.remove(name);
>   }
> 
>   public static class Ford extends Car{
>     public Ford(String name, int wheels){
>       super(name);
>       if(wheels > 4){
>         throw new IllegalArgumentException("Too many wheels");
>       }
>     }
>   }
> 
> 
>   public static void main(String[] args) {
>     Car c = null;
>     try{
>       c = new Ford("myFord", 5);
>     } catch (Exception e) {
>       // cannot call c.remove() here!
>       e.printStackTrace();
>     }
> 
>     System.out.println(c); // prints null
>     System.out.println(nameList); // prints [myFord], should be empty
>   }
> }
> 

The answer is... Constructors should not cause side effects! Ever! For 
just this reason.

The better approach is to use either a two-stage approach, or a factory 
approach that encapsulates that two-stage approach

public abstract class Car {
   final String name;
   protected Car(String name) { this.name = name; }
   public void init() {  nameList.add(name); }

}
Car myCar = new Ford("Blah", 4);
myCar.init();

-- 
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
0
Reply newsgroup.spamfilter (920) 4/20/2008 6:12:27 PM

Philipp wrote:
> PS: Could someone recommend some reference about why exceptions in 
> constructors are bad. In particular, if the constructor has no side 
> effects, I can't understand what the problem is in having exceptions.

It is not always bad.

It can and should be used in some cases.

But sometimes it is an indication that functionality beyond
pure construction has been put into the constructor.

Arne
0
Reply arne6 (9485) 4/26/2008 7:23:16 PM

Arne Vajh�j wrote:
> Philipp wrote:
>> PS: Could someone recommend some reference about why exceptions in 
>> constructors are bad. In particular, if the constructor has no side 
>> effects, I can't understand what the problem is in having exceptions.
> 
> It is not always bad.
> 
> It can and should be used in some cases.
> 
> But sometimes it is an indication that functionality beyond
> pure construction has been put into the constructor.
> 
> Arne
Although, it may also indicate some validation problem during 
construction.

A constructor is likely to throw NullPointerExceptions and 
IllegalArgumentExceptions.  They may also do some other validation and 
throw some other exception.

I think that it may have been "bad" in non-gced langauges (such as C++), 
where you could end up with memory leaks if the object wasn't properly 
destructed.

-- 
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
0
Reply newsgroup.spamfilter (920) 4/26/2008 9:06:58 PM

19 Replies
27 Views

(page loaded in 0.322 seconds)


Reply: