Nothing Half Baked

Problems

How do you avoid wasting resources creating and destroying objects that are never usable?

Context

You are creating a class, or family of related classes.

Forces

Your classes are dependent upon some external factor beyond their control in order to function correctly.

Object creation and destruction are two of the most expensive single operations in your system. (This is true in Java and in most C++ implementations)

Examples

File I/O. Want to read file, create file object, file doesn't exist, file object is bad and can't be used.

Socket I/O. Want to connect to server, create socket object, remote host is down/network error/whatever, socket object is bad and can't be used.

Date and/or time class. Want to create from user input, user typed data in invalid format, object is bad and can't be used.


From here, I see two divergent patterns:

1. Create a blank object, then prepare it for use in an initialization step. If the initialization fails, just try again using the same object.

2. Use private constructors and have the object created by a static member function. The static member function exerts the minimum effort required to positively determine if the operation will succeed. Only then is the object constructed.

I'm guessing that forces will decide which path is taken.

Comments anyone?


For the file and socket cases, surely the costs of instantiation are very much lower than anything to do with manipulation that kind of OS resource? So an instance here or there doesn't make much difference and you might want to hold information about the failure in the invalid instance.

For the data/time case, the time object is down in the Model level whereas validating user input is up in the View. You want to separate the two anyway to allow for different Locales and user preferences, so the instance creation should be handled via something in the presentation code - possibly with some supporting infrastructure in the Date/Time class. -- SteveFreeman


Um, object creation/destruction is expensive compared with i/o? Well, one thing you can do is pool your objects for re-use. MicrosoftTransactionServer does that.


The point about the cost of I/O relative to the cost of construction/destruction is very well taken. In situations where the existence of an object may give seeming legitimacy to a process which has failed miserably and no recovery is possible, what approach can be taken to make it absolutely clear to the user or to the other parts of the software that this is so?

I guess I just don't like the "Create an object, maybe it's valid, maybe it isn't." paradigm. Especially for things like file objects. I see this in terms of the fundamental principles of object-oriented programming. If instances of a software class represent instances of some real world object, then how can I have a software instance where a corresponding real world instance does not or cannot exist? Sorry, but it just seems backwards to me.

So, what do you do with, say, a socket object that worked for a while but died in the middle? A socket that dies on opening could be regarded as just a limit case. There may still be things you want to keep a handle on so you can retry or report the error properly. Similarly, what's a file system link ('shortcut' in MS-speak)? It tells you something about the user's intentions, even if the thing it's pointing to is broken and maybe the target will come back later. Finally, object types don't only represent "real world" instances (assuming a file is a real world thing), they can represent concepts, intentions, policies, etc., etc. -- SF

An idea (which includes concepts, intentions and policies) is just as real, even if it doesn't have physical form. Please note that I'm not trying to say that this approach is the only valid approach, or even that it is the best approach. What I will say though, is that I think it is an equally valid approach and that, depending upon the exact circumstances of the problem, might yield a better implementation. It is a conceptual tool which we should keep in our toolbox until needed.

Now we're converging... Actually, I think that this technique is very useful, particularly if your instances come from a factory, but I think the OS examples don't work so well. The Date example is more interesting because bad input is reasonably likely and the allocation costs are dominant. -- SF


It sounds like you really want a way to return failure from an object construction, without setting error flags in the object itself. It is the normal "how to handle errors" question, with the slight twist that the error is best detected in the object's constructor, but if the error occurs we don't want to have created the object.

Having a factory object which quietly hides/deletes the object and then returns NIL (or has some out-of-line error state) would be reasonable. The classic solution, almost made for this situation, is to throw an exception from the constructor. (This would be using exceptions for their alternate return semantics, which may not be appropriate if the error is quite likely to occur.) -- DaveHarris


EditText of this page (last edited November 24, 2005) or FindPage with title or text search