Java-Gaming.org Hi !
Featured games (81)
games approved by the League of Dukes
Games in Showcase (513)
Games in Android Showcase (119)
games submitted by our members
Games in WIP (576)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Opinion about constructors that throw exceptions  (Read 1861 times)
0 Members and 1 Guest are viewing this topic.
Offline tono

Junior Newbie





« Posted 2005-11-20 11:32:04 »

I have a question about constructors that throw exceptions. This maybe about general programming, but my example is about game and I certainly know that games differ from 'office' applications in many ways. I have a class that handles tiled maps in my game. My thinking is, that you can create this class by providing the actual layout in it's constructor - obviously they are so tightly coupled. Now, if the map is invalid (like in my case, a door is in non-useful location) should the constructor throw an exception, or should I make that the class is created first, and then the actual layout is fed in in separate method which throws the exception?
So in general, if I were to make a library, are people comfortable with constructors that throw exceptions. I am not new to programming, but creating games and libraries are new to me.
Offline cylab

JGO Ninja


Medals: 52



« Reply #1 - Posted 2005-11-20 15:51:21 »

I tend to use no constructors (besides the default one) at all. Just create an object, set all properties and call some initialization method. This might be a bit clumpsy especially if you forget to call the init-method in a code path Wink, but it also has a lot of benefits, especially when it comes to serialization or bean wireing with frameworks like spring.

Constructors that throw exceptions are dangerous In my experience. I would avoid this. If you want to encapsulate the construction process, just use the abstract factory pattern for this.

Said that, I have to admit, that most of my programming knowledge is based on J2EE middleware programming, so there might be different aspects in game programming.

Mathias - I Know What [you] Did Last Summer!
Offline swpalmer

JGO Coder


Exp: 12 years


Where's the Kaboom?


« Reply #2 - Posted 2005-11-20 16:09:51 »

Constructors that throw exceptions are dangerous In my experience. I would avoid this. If you want to encapsulate the construction process, just use the abstract factory pattern for this.

Obviouly if it is posible to pass bogus data to your constructor then you have little choice but to throw an exception if you fail to initialize the object as expected.  When it comes down to it, depending on the exact usage, there won't be any difference in throwing the exception from the constructor, or throwing it from a factory method or init method.

Another method is to put some sort of 'init' flag in the object and fail other methods if the object isn't ready yet.  I don't liek that method as much.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #3 - Posted 2005-11-20 16:21:34 »

Constructors should put the object into a known, valid and workable state. If your constructor finds that this isn't possible then it should throw an exception. I for one am fed up of seeing code like:

1  
2  
3  
4  
Foo theFoo = new Foo();
theFoo.setBar(bar);
theFoo.setBaz(baz);
theFoo.init();


It's nonsense, error prone and needlessly bloats your interface. Most of the time you can never repeat this (ie. do a second init after some use) and you don't often want to do this anyway.

There are a couple of exceptions though, usually when you want to seperate memory allocation and actual init code (like for a pooled object). But until you actually know you need this it'd probably be better to start with the cleaner and more robust method.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline Ask_Hjorth_Larsen

Junior Duke




Java games rock!


« Reply #4 - Posted 2005-11-20 16:32:30 »

I, too, prefer as much work as possible to be done from the constructor. It forces the programmer to remember ALL parameters necessary to use the object, thus preventing lots of errors, and throwing Exceptions from constructors is fine with me. If it isn't thrown when it should be, the session is probably doomed anyway.
Offline Jeff

JGO Coder




Got any cats?


« Reply #5 - Posted 2005-11-22 04:45:18 »

Yes, Orangy says it exactly perfectly Cool

+1 on his comments, and I do throw exceptions from constructors from time to time.  In fact there is a constructor already defined for this purpose in the JDK (InstantiationException).

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline thaaks
« Reply #6 - Posted 2005-11-22 19:14:29 »

Exceptions are what their name implies: exceptional.
There is a very simple way to assure proper object creation: static methods!
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
public class MyClass {
  private int myFoo;

  // private constructor to avoid calling it
  private MyClass(int foo) {
    myFoo = foo;
  }

  public static MyClass newMyClass(int someFoo) {
    if (someFoo < 0)
      return null;  // no need to raise an exception
    MyClass myObj = new MyClass(someFoo);
    return myObj;  // only return valid objects or null in case of some problem
  }
}

And later calling:
1  
2  
3  
4  
5  
...
MyClass anObj = MyClass.newMyClass(someValue);
if (anObj != null) {
   ...
}

Works fine for me. I can do any required validations in my static methods and decide anytime if I return null or a valid object.
I would throw exceptions only if I run into some "low level" problems like network errors, missing database connection and such.

Hope that helps,
Tommy

Offline Jeff

JGO Coder




Got any cats?


« Reply #7 - Posted 2005-11-22 22:33:09 »

This is fine when a factory makes sense.

But IMHO its often needless complexity.

And again IMHO a new failing *is* an exceptional condition.

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline cylab

JGO Ninja


Medals: 52



« Reply #8 - Posted 2005-11-23 00:00:50 »

I feel the need to clarify my comment Wink

The main problem with constructors throwing exceptions and constructors with parameters in gereral is inheritance. Consider the following example

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
  // Class A wants to register all instances with a global registry for lookup
  class A
  {
    public A()
    {
      // The user should not know about this registration process,
      // all black magic, so do it in the constructor
      Registry.getInstance().register(this);
    }
  }

  // Class B is an A with a twist
  class B extends A
  {
    public B()
    {
      // The super() call has to be the first in the constructor
      super();
      // Oops, now we have a bogus instance registered :(
      throw new RuntimeException("something went wrong");
    }
  }


One can argue, that B could call something to deregister the broken instance, but how do you know, what else has to be done. Using the init()-scheme, this problem can simply be solved by calling the super.init() method at last:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
  // A version 2
  class A2
  {
    public A2()
    {
    }

    public void init()
    {
      Registry.getInstance().register(this);
    }
  }

  // Class B is an A with a twist
  class B2 extends A2
  {
    public B()
    {
      // No Problem using the super call
      super();
    }

    public void init()
    {
      // Just throw an exception and forget..
      throw new RuntimeException("something went wrong");
      // The super call can be moved to the end of the method, so no problem here
      super.init();
    }
  }


The problem becomes more visible if constructor parameters are involved. This time, the Exception is thrown in the base class constructor:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
  // A Mesh
  class Mesh
  {
    public Mesh(int rows, int columns, float[] vertexData)
    {
      if(vertexData==null)
        throw new IllegalArgumentException("Vertex data may not be null!");
      // initialize VBO-Stuff
    }
  }

  // A heightfield is nothing more than a Mesh
  class HeightField extends Mesh
  {
    public HeightField(BufferedImage image)
    {
      // I can't provide the initial data (super() has to be the first), so lets set bogus params and set the mesh up later...
      super(0,0,null);  // hmm, this can't be done, since the constructor throws an exception :(
      // Note: You can't even put a super()-call inside a try{} block
    }
  }


Since the constructor of Mesh throws an exception, it is not possible to encapsulate the logic for creating a Mesh out of an height map inside a derived class. You have to precalculate the vertexData in your main application and just create a Mesh instance with it. Effectively cancel out OO design. Using an init()-Method, this would look like:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
  // Another Mesh
  class Mesh2
  {
    public Mesh2()
    {
    }

    public void setRows(int rows) {...}
    public void setColumns(int columns) {...}
    public void setVertexData(float[] vertexData) {...}

    public void init()
    {
      if(this.vertexData==null)
        throw new IllegalArgumentException("Vertex data may not be null!"); // this is fine here
      // initialize VBO-Stuff
    }
  }

  // A heightfield with all loading logic encapsulated
  class HeightField2 extends Mesh2
  {
    public HeightField2()
    {
    }

    public void setHeightMap(BufferedImage heightMap)
    {
      setRows(heightMap.getHeight());
      setColumns(heightMap.getWidth());
      setVertexData(generateVertexData(heightMap));
    }
    private float[] generateVertexData(BufferedImage image){...}
  }


To use the above code you write:

1  
2  
3  
4  
5  
6  
7  
8  
9  
  Mesh2 aMesh= new Mesh2();
  aMesh.setRows(16);
  aMesh.setColumns(32);
  aMesh.setVertexData(someData);
  aMesh.init();

  HeightField2 aHeightField= new HeightField2();
  aHeightField.setHeightMap(ImageIO.read(Main.class.getResourceAsStream("heightMap.png")));
  aHeightField.init();


which is IMHO not tooooo clumpsy Wink On the contrary, I think the above code is more readable, since you see the property names and values at a glance.

Quote
When it comes down to it, depending on the exact usage, there won't be any difference in throwing the exception from the constructor, or throwing it from a factory method or init method.

Since the factory method can produce any implementation or subclass of the desired object without beeing overloaded, the problems that can araise by throwing exceptions in in the constructor call chain can not occour using an abstract factory pattern. It may look like the same from the users point of view, but it is different from the implementation perspective.

Excuse the long post, by I had to defend myself Wink

PS: All this is rather special and may not apply to game developer needs, so it might be valid to use twenty constructor parameters and throw exceptions as you like. It all depends on the concrete problem to solve.

Mathias - I Know What [you] Did Last Summer!
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #9 - Posted 2005-11-23 00:28:55 »

Exceptions are what their name implies: exceptional.
There is a very simple way to assure proper object creation: static methods!
As Jeff said, sometimes factories don't make sense.

Equally, now you're back in C land with your error handling code jammed in the middle of your normal code. This interleaving obscures the code which occurs when there are no problems, and makes it more difficult to make sure all error cases are properly handled. Exactly the kind of thing that exceptions are designed to avoid. Roll Eyes

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline kevglass

JGO Kernel


Medals: 186
Projects: 24
Exp: 18 years


Coder, Trainee Pixel Artist, Game Reviewer


« Reply #10 - Posted 2005-11-23 01:03:41 »

Constructors throwing exceptions comes down to taste and opinon. Make you choice and stick to it. As long as its documentated and useful no one is going to complain.

Kev

Offline swpalmer

JGO Coder


Exp: 12 years


Where's the Kaboom?


« Reply #11 - Posted 2005-11-23 04:16:43 »

Equally, now you're back in C land with your error handling code jammed in the middle of your normal code. This interleaving obscures the code which occurs when there are no problems, and makes it more difficult to make sure all error cases are properly handled. Exactly the kind of thing that exceptions are designed to avoid. Roll Eyes

(Just ot be devil's advocate...)

"Except" that they generally don't avoid those things.. in practice.

Now with exceptions you have ugly try/catch blocks all over the place or you need to propagate your throws declaration all the way up your call stack, unless you are using unchecked exceptions.  Those things tend to get interleaved with the real code in order to handle the various error cases when they matter. 

I actually think exceptions are the right way to do it,  but we need some good articles on how to use them effectively to keep the code clean.  Here I think the 'finally' block is the big life-saver that C++ lacks.

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Longarmx (46 views)
2014-10-17 03:59:02

Norakomi (37 views)
2014-10-16 15:22:06

Norakomi (29 views)
2014-10-16 15:20:20

lcass (32 views)
2014-10-15 16:18:58

TehJavaDev (62 views)
2014-10-14 00:39:48

TehJavaDev (62 views)
2014-10-14 00:35:47

TehJavaDev (52 views)
2014-10-14 00:32:37

BurntPizza (70 views)
2014-10-11 23:24:42

BurntPizza (40 views)
2014-10-11 23:10:45

BurntPizza (82 views)
2014-10-11 22:30:10
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!