Groups | Blog | Home
all groups > c# > july 2006 >

c# : throwing exception from constructor



Sek
7/31/2006 11:09:01 PM
Is it appropriate to throw exception from a constructor?

Thats the only way i could think of to denote the failure of
constructor, wherein i am invoking couple of other classes to
initialise the object.

TIA
Sek
chanmm
8/1/2006 12:00:00 AM
Contructor supposed to handle simple tasks like initialization. If up to the
stage you need to throw exception from contructor I think I would suggest
you to review the code.

chanmm

[quoted text, click to view]

simida
8/1/2006 12:26:25 AM
As far as i know, It's not a appropriate way to throw exception from a
constructor.
If you can make sure that when exception occured, you should dispose
all resoures, such as, File handler, memory, etc.



Sek =E5=86=99=E9=81=93=EF=BC=9A

[quoted text, click to view]
Jon Skeet [C# MVP]
8/1/2006 12:27:35 AM
[quoted text, click to view]

Yup, that's fine. Several framework types do it. For examples, see
Guid(string), the FileStream constructors, and String(char[], int,
int).

Jon
Jon Skeet [C# MVP]
8/1/2006 12:34:59 AM
[quoted text, click to view]

It's widely done, and there's no reason not to do it in .NET. In
unmanaged C++ there are reasons why it's a bad idea, but they don't
apply to .NET.

[quoted text, click to view]

File handles etc, yes - but memory will automatically be cleaned up by
the garbage collector.

Jon
Jon Skeet [C# MVP]
8/1/2006 4:02:38 AM
[quoted text, click to view]

Initialization can quite often suggest throwing exceptions,
particularly based on the parameters. What would you suggest FileStream
should do if it's been asked to open a file for reading and the file
doesn't exist?

Jon
Leon Lambert
8/1/2006 6:17:50 AM
As many have stated it is ok to throw an exception in the constructor.
Having said that i would recommend against it. Over the years i have
found it helped me a lot better to just have constructors put the object
into a safe state. I do work that might throw exceptions in a different
method like Setup. I forget all the pains i had in the past that
eventually brought my to doing things this way because I just do it as a
matter of course now.

Leon Lambert

[quoted text, click to view]
Brian C. Barnes
8/1/2006 6:24:02 AM
I agree with what Lambert wrote. I have always tried to insure that
constructors simply put things into an "initialized" state. If you have to do
something more involved, and especially anything that might throw an
exception or have other failures, I always put them into a "Create" or "Open"
type of function. Yes, this can lead to other errors (i.e. forgetting to call
the appropriate Create function), but I just like it better because of all
the "magic" constructors that happen behind your back (copy constructors,
etc.).

[quoted text, click to view]
Jon Skeet [C# MVP]
8/1/2006 7:18:10 AM
[quoted text, click to view]

So how would you implement FileStream? If you don't do anything in the
constructor, it's just saving the exception for later on - where's the
advantage of that? Yes, the object would be in a "safe" state - but
it's useless until it's opened the file, and that's the point at which
you should throw an exception if the file can't be found, IMO.

Jon
Jon Skeet [C# MVP]
8/1/2006 7:21:38 AM
[quoted text, click to view]

C# doesn't *have* "magic" constructors though. I really don't see the
advantage of forcing the client to make two calls when one would do.
The *only* point I could see is that if you're implementing
IDisposable, you need to make sure that your constructor cleans up
after itself if it throws an exception after acquiring a resource. If
you do that in the Create method, you can assume that the client will
call Dispose appropriately.

However, using a Create/Initialize/etc method means that your object
isn't really *usable* when the constructor has returned, which is the
state I like to be in.

It's quite possible that throwing exceptions from constructors is a bad
idea in other environments, but I think it's fine in C#.

Jon
Carl Daniel [VC++ MVP]
8/1/2006 8:04:56 AM
[quoted text, click to view]

Excuse me? Indicating failure from a constructor is one of the primarly
reason that exceptions were added to the C++ language over a decade ago. It
is the proper way to signal failure from a constructor. Used together with
the RAII idiom (resource acquisition is initialization - as manifested in
smart pointers and tools like ScopeGuard), exceptions thrown from within a
constructor are safe and easy to use correctly. The alternative, multi-part
construction (via an "init" function), is an error-prone model than permits
partially constructed objects to exist - something that the .NET designers
felt so strongly about that they ensured that all objects are fully
constructed before the first statement of the constructor runs.

-cd

Carl Daniel [VC++ MVP]
8/1/2006 8:07:21 AM
[quoted text, click to view]

I'd really like to hear those "difficulties". It's quite normal to throw
exceptions from C++ constructors - it's the one of the main reasons that
exceptions were added to C++.

-cd

Jon Skeet [C# MVP]
8/1/2006 8:15:27 AM
[quoted text, click to view]

I think I must have heard exaggerated claims of the problems involved.
I believe (after a quick search) that after an exception is thrown in a
C++ constructor that the destructor is not called, so resources need to
be cleaned up in that situation. I guess some people have taken that as
a reason not to throw exceptions at all in C++...

Jon
Brian Gideon
8/1/2006 9:54:30 AM
Sek,

There are some good comments here already. The Framework Design
Guidelines book says that it is acceptable to throw exceptions when
appropriate. But, it also recommends keeping constructor operations
simple. Often the only thing a constructor needs to do is capture the
parameters. As a result many constructors should only need to throw on
invalid parameters.

I *usually* avoid long running or complex operations in constructors
anyway because it's not clear to the caller that they're happening. If
it makes more sense to construct an object in conjunction with a
complex operation then I'll use a static factory method where I have
the liberty of giving it a clear name using appropriate verbage. If
you go with this approach (and I'm not suggesting that you do) then
you'd naturally be limiting the circumstances where exceptions are
thrown by constructors.

Brian


[quoted text, click to view]
Brian C. Barnes
8/1/2006 10:57:02 AM
But the whole point of .NET is that it is language egnostic - and the
libraries we write in C# may get used by C++/CLI projects, or other languages
that perhaps can't deal with exceptions in constructors as cleanly as C# can.
Since the author really doesn't know what language environment is being used,
I would tend to stick with the more pessimistic approach of doing as little
as possible in the constructor.

[quoted text, click to view]
Brian Gideon
8/1/2006 12:51:16 PM
[quoted text, click to view]

The FileStream constructor is another example of a poor design choice.
IMHO, opening a file is not a simple operation. There should be an
Open method (either instance or static) that performs this work. Even
after reading the documentation it's still not perfectly clear that the
constructor actually opens the file. But the deed has been done and
throwing exceptions is the only appropriate choice.

Brian
Brian Gideon
8/1/2006 1:45:31 PM

[quoted text, click to view]

Well, it's definitely debatable. I can't honestly say that I even
completely agree with my own statement nor do I always follow the
"simple operation" rule for constructors myself. I just think there is
a better alternative in this case.

[quoted text, click to view]

And you'd get just that with a static factory method; a method with a
verb name clearly describing what it is going to do.
Jeff Louie
8/1/2006 2:06:26 PM
Sek.. You can throw an exception in the constructor.. or use a static
class factory
and return null on failure.. or set a flag isValid to false.

Beware that the finalizer will be called in C# even on exceptional
construction!

http://www.geocities.com/Jeff_Louie/oop30.htm

C++ and PHP coders will be surprised to learn that in C# even if an
exception is
thrown in the user defined constructor, the user defined destructor will
still be
called.

Regards,
Jeff
[quoted text, click to view]

Thats the only way i could think of to denote the failure of
constructor, wherein i am invoking couple of other classes to
initialise the object.<<

Barry Kelly
8/1/2006 3:40:52 PM
[quoted text, click to view]

Interesting; the need to flag errors from constructors was one of the
motivations for introducing exceptions into C++, since return value
can't be used.

There's nothing wrong with throwing an exception from a constructor.

-- Barry

--
Barry Kelly
8/1/2006 3:41:45 PM
[quoted text, click to view]

A constructor should leave an object in a valid state. If the
constructor arguments do not give the right information to leave the
object in a valid state with all its invariants holding, then the
constructor should definitely throw an exception.

-- Barry

--
Barry Kelly
8/1/2006 3:47:21 PM
[quoted text, click to view]

I remember it being difficult to throw exceptions correctly in C++
constructors, but C# is not C++, and does not have many of its flaws.

There was never a problem in throwing exceptions in constructors Delphi
either, for a simple reason - Delphi initialized the object's fields to
all-zeros before running the constructor. In Delphi, when a constructor
threw an exception, the destructor was invoked. Because all the fields
were initialized to zero, it was trivial for the destructor to correctly
and safely destroy the partially-constructed object. The same is a lot
harder in C++ when one is doing heap allocation etc. in the constructor.

For similar reasons, in C# there's nothing wrong with throwing in the
constructor, and nor are there any complications or difficulties in the
mode of C++.

-- Barry

--
Barry Kelly
8/1/2006 3:48:12 PM
[quoted text, click to view]

What magic constructors in C#? I suspect you're projecting C++'s
language flaws on other object-oriented languages :)

-- Barry

--
Brian Gideon
8/1/2006 3:57:42 PM
[quoted text, click to view]

File.Open doesn't have an ambiguous meaning. It's perfectly clear from
the name that a file will be opened if no exceptions are thrown. The
problem is that it's on a separate class, which is fine, but how would
one know to look at the File class if they're currently interested in
the FileStream class. It makes more sense to add it to the FileStream
class as well. Consider the following lines of code.

FileStream stream = new FileStream("foo.txt");
FileStream stream = FileStream.Open("foo.txt");

Without knowing anything about a FileStream what can we say about these
lines of code? The only thing we can say for certain about the first
line is that stream can be used to read/write data in the foo.txt file.
We can say more about the second. Not only can it read/write to
foo.txt, but it is *ready* to do so since the method clearly indicates
that the stream is open when it's returned.

But, that's not why I think it was a poor design choice. I think it's
a poor design choice because a constructor that throws an IOException
has a complex operation embedded in it. That contradicts the following
guideline.

"Do minimal work in the constructor. Constructors should not do much
work other than to capture the constructor parameters. The cost of any
other processing should be delayed until required." --Framework Design
Guidelines by Cwalina & Abrams.

[quoted text, click to view]

I don't see where there's extra complexity. In fact, from the callers
perspective the interface would be more self describing and thus
simpler to use!

You wouldn't necessarily have to move logic around to accomodate the
factory method. Just make the constructor private and have the factory
call that if you like.

Using the static factory method approach it would still be impossible
to reopen a closed stream since there wouldn't be an instance method
there to do it.

[quoted text, click to view]

Yep. That's how most of the objects that acquire resources in the
System.Net and System.Data namespaces work. Though, in those examples
they're usually instance methods.

[quoted text, click to view]

I'd say no especially if the documentation on the stream indicated that
a caller can assume it's open if the Close method hasn't been
previously called. That's pretty much how it works now. The same
semantics can be acheived with a static factory method.
Jon Skeet [C# MVP]
8/1/2006 7:58:01 PM
[quoted text, click to view]

Care to cite any examples? Any language which can't cope with
constructors throwing exceptions is in serious trouble when it comes to
using the framework classes.

[quoted text, click to view]

My approach is to do what's appropriate in the constructor to create a
viable object. In the case of something like FileStream, that involves
opening the file - which would naturally involve throwing an exception
if the file cannot be opened.

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
Barry Kelly
8/1/2006 8:52:42 PM
"Carl Daniel [VC++ MVP]"
[quoted text, click to view]

I know - I mentioned it in a parallel post.

Consider (implementions inlined, copy constructors / assignment
operators / auto_ptr etc. all ignored, for the sake of exposition):

---8<---
class Foo
{
private:
Bar *m_bar;

public:
Foo(bool doThrow)
{
m_bar = new Bar;
if (doThrow)
throw 0;
}

~Foo()
{
delete m_bar;
}
};
--->8---

The same in Delphi:

---8<---
type
Foo = class
private
FBar: Bar;

public
constructor Create(doThrow: Boolean);
// inlined here for exposition, not actually valid Delphi syntax
begin
FBar = Bar.Create;
if doThrow then
throw Exception.Create;
end;

destructor Destroy; override;
begin
FBar.Free; // Free() checks for nil pointer first
end;

end;
--->8---

-- Barry

--
Jon Skeet [C# MVP]
8/1/2006 8:58:32 PM
[quoted text, click to view]

Having a FileStream which hasn't opened the file seems pretty odd to me
- and would mean that you'd have extra code in everything which used
it. Having no public constructors, just static methods, would be doable
- but I don't see the advantage. From the client's point of view
there'd still be an exception occurring.

Where's the benefit in making the constructor *not* open the file? I'm
all for constructors only doing a sensible amount of work - but not
when that means that an object isn't actually ready for use until
another particular method has been called.

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
Barry Kelly
8/1/2006 9:11:10 PM
[quoted text, click to view]

I strongly disagree!

[quoted text, click to view]

This would create a three-state stream - closed, open and disposed -
rather than what we currently have, two states - open and disposed. With
an 'Open' operation, one would expect to be able to close and open it
repeatedly. I, for one, prefer objects with simple purposes in life and
with a minimum of 'modality'.

-- Barry

--
Barry Kelly
8/1/2006 10:13:47 PM
[quoted text, click to view]

One already has 'File.Open' and related methods which provide the
appropriate arguments to the FileStream constructor.

But on the other hand - what's the benefit from using this approach? If
one calls the static method rather than using the constructor, what's
been gained over the losses: extra complexity, the divorce between where
the object is constructed (the static method) and the actual object
implementation, and the extra mode on the file stream? Also, won't all
streams now need this Open() method? What do you do when you get a
stream from elsewhere, like a NetworkStream from a socket? Do you need
to open that too? If not, where does all this documentation go?

-- Barry

--
Carl Daniel [VC++ MVP]
8/1/2006 10:20:42 PM
[quoted text, click to view]

That's correct - the body of the destructor is not run, but the destructors
of all base classes and member variables are run (assuming the exception was
thrown from the body of the constructor). If you use the RAII pattern (as
all modern C++ programmers should), your constructor and destructor bodies
will almost always be empty and throwing an exception from the constructor
will do exactly what you'd want it to do.

-cd

Barry Kelly
8/1/2006 11:52:10 PM
[quoted text, click to view]

On the other hand, Delphi programmers won't be surprised - although
calling C# '~Class()' syntax a 'destructor' is, of course, an abuse of
terminology... :)

-- Barry

--
Barry Kelly
8/2/2006 1:17:37 AM
[quoted text, click to view]

I agree with the general principle that constructors should not initiate
an operation that is costly in time or space, but I don't agree with the
notion that a constructor should delay 'full initialization with all
invariants holding' until a later 'Initialize' method is called. All
that does is complicate the interface, multiply the possible states,
etc. etc. I'm more interested in how you think the rationale behind the
guideline applies in this particular case.

Or to put it another way, I think there's a balance to be achieved -
described below.

[quoted text, click to view]

I can only talk about my personal experience using different classes. I
personally find FileStream nice and easy to work with, and I like its
idiom. On the other hand, I find System.Diagnostics.Process far more
awkward. I need to construct an instance, fiddle with various properties
before finally invoking a method.

Now, starting a process etc. is an expensive operation. As such, it
shouldn't occur inside the constructor. What's more, the various
subtleties and options on how one can create a process aren't fully
appreciated by people who are new to the functionality. With respect to
creating a process, I think the static method approach along with a
do-very-little constructor and tweakable properties works well - though
the static methods are missing in the current version of the BCL.

Thus, I think it's a question of where one draws the line. I think that
FileStream is good and that making it a tweakable stillborn object until
you finally call 'Open()' would be overkill. Just MHO.

I think it has more to do with the cost of the operation than the fact
that it may or may not throw exceptions.

[quoted text, click to view]

This is more an argument for named constructors, but I think that's an
orthogonal topic to throwing exceptions from constructors.

[quoted text, click to view]

But these objects typically block for lengthy time periods. I would
agree to a rule of thumb that says "any operation that you might
consider making asynchronous doesn't belong in a constructor".

-- Barry

--
adebaene NO[at]SPAM club-internet.fr
8/2/2006 1:22:43 AM

[quoted text, click to view]

I think you're projecting your C# way of thinking onto C++, therefore
doing unwise design choices...

Why is the m_bar member allocated allocated on the heap? Any reason for
that in the 1st place ???? 9 times out of 10, the good solution is as
imple as :

class Foo
{
Bar m_bar; //no need for constructor nor destructor
};



Now, suppose there is a good reason to allocate m_bar on the heap, what
about doing modern C++, eg usig the RAII idiom ??

class Foo
{
std::auto_ptr<Bar> m_bar; //depending on context,
boost::shared_ptr may be another option

public:
Foo(bool doThrow)
: m_bar(new Bar())
{
if (doThrow)
throw 0;
}
};

Arnaud
MVP - VC
Barry Kelly
8/2/2006 1:50:29 AM
[quoted text, click to view]

I've been programming in too many different languages lately. That
should be:

FBar := Bar.Create;
if doThrow then
raise Exception.Create('blah');

-- Barry

--
Brian Gideon
8/2/2006 7:14:23 AM
[quoted text, click to view]

I realize I'm splitting hairs on this one, but the main advantage IMHO
is better compliance with the guideline. Anything that throws an
IOException can't possibly be a simple operation. If you use the
static factory method approach then you would have an object that's
ready to use in one call with the added benefit that the interface
should be easier to understand for the caller.

I think one advantage of the guideline is that it encourages developers
to put complex operations in methods where 1) they're expected and 2)
that have self describing names. To me anyway, line 2 is an order of
magnitude more clear that the stream is open than line 1.

FileStream stream = new FileStream("foo.txt"); // Line 1
FileStream stream = FileStream.Open("foo.txt"); // Line 2

I'm not saying that throwing exceptions from a constructor is bad. In
fact the same guidelines say it's acceptable when appropriate. Since
the FileStream does attempt to open a file then throwing an exception
is a logical choice.
Barry Kelly
8/2/2006 4:06:27 PM
[quoted text, click to view]

That's irrelevant. This isn't a program, so there are no design choices.
There are only language features.

[quoted text, click to view]

I explicitly mentioned that I was ignoring auto_ptr for the sake of
exposition.

In my view, C++'s destructors along with the RAII pattern are basically
required to be overused in order to hack around a limitation in the
language. The RAII pattern works very well for simple scenarios (and
they should be used in such reusable scenarios), like an owned pointer
or a ref-counted pointer, but not every paired operation between
constructor and destructor is so reusable that it merits a new type.

-- Barry

--
Jon Skeet [C# MVP]
8/2/2006 6:53:38 PM
[quoted text, click to view]

To split hairs even further, I regard compliance with guidelines per se
as not being an advantage at all - it's only an advantage to the extent
that the guideline itself makes sense. Clearly I disagree with the
generality of the guideline in this case, so compliance with it is
irrelevant to me.

[quoted text, click to view]

*That* is much more of an argument I can at least understand. I still
disagree with it, largely because opening the stream on construction is
precisely the behaviour I expect, but at least it's a reasonable
argument :)

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
Arnaud Debaene
8/3/2006 7:27:34 PM

"Barry Kelly" <barry.j.kelly@gmail.com> a écrit dans le message de news:
acf1d2pj19bjlppmfs4r3qbsmg5termkpg@4ax.com...
[quoted text, click to view]
Which limitation? The limitation is rather on the .NET finalizer side IMHO :
since you don't know when they are run, there is almost nothing you can do
inside them!

[quoted text, click to view]

That's why there are generic solutions to the RAII idiom, such as ScopeGuard
(http://www.ddj.com/dept/cpp/184403758)

Arnaud
MVP - VC

Arnaud Debaene
8/4/2006 12:00:00 AM

"Barry Kelly" <barry.j.kelly@gmail.com> a écrit dans le message de news:
gf55d25vi26gqbfm8p72mfskjjt6ihbjeg@4ax.com...
[quoted text, click to view]

But which limitation are you talking about exactly? That's what I don't
understand...

[quoted text, click to view]

Huuh? Andrei Alexdandrescu doing "hacks and crutchs" ??? Care to justify
your appreciation?

More seriously, I believe there is a true divergence ni philosophy here :
The C++ approach is "do as little as possible in language itself, and as
much as possible in libraries", whereas your approach (I am not really sure
this is indeed the C# approach) is "put everything in language and compiler
itself, so that there is nothing left to do in libraries". I believe the 1st
approach is more flexible because, first, it makes it much easier to replace
a defective component....

Arnaud
MVP - VC

Barry Kelly
8/4/2006 12:00:00 AM
[quoted text, click to view]

Like I said, we'll have to agree to disagree.

[quoted text, click to view]

Nonsense! If that were true, the language would look like LISP! :P

[quoted text, click to view]

That's clearly not true, because there seem to be substantial libraries
packaged with the .NET framework. :) Even the C# basic types are defined
in a library!

You'll have to forgive me, I'm being quite facetious, at the end of a
long day.

[quoted text, click to view]

Consider std::stack::pop() - C++ is a language in which you can't even
write an exception-safe mutator method which returns a value of a
user-defined type!

I think a programming language should have a carefully selected set of
abstractions and abstraction creation tools that are suitable for the
domain to which it is applied. I think C++ has a set of useful
abstractions and abstraction creation tools, but there are interactions
between some of them that are less than desirable - and that the
resulting sum is somewhat less than the sum of its parts. I think it
would be a better language if it removed some features, and changed some
functionality - but then it would no longer be C++.

-- Barry

--
Barry Kelly
8/4/2006 1:35:05 AM
[quoted text, click to view]

We'll have to agree to disagree - I think it's a limitation of the
language definition, nothing to do with .NET or otherwise, in the
context of "throwing an exception from the constructor".

[quoted text, click to view]

Yes, more hacks and crutches...

-- Barry

--
Brian Gideon
8/4/2006 8:05:30 AM
[quoted text, click to view]

My rationale is based on the fact that some FileStream constructors
acquire a resource in a complex manner. To me, opening a file, which
may require network activity, does not qualify as "minimal work".

[quoted text, click to view]

There's always a balance. That's why I can't honestly say I'm too hung
up about it. There are other interface design problems in the BCL that
are more significant. And it's certainly possible that I'm
interpreting the guideline too strictly. But, it did come from people
who are smarter than I so I want to be cautious about ignoring it
altogether.

[quoted text, click to view]

I don't know. Even if Open were an instance method I'm not sure it
would seem overkill to me. Afterall, that's how a lot (most?) of the
classes in the BCL work. But, you're right, as it is, the FileStream
class works well.

[quoted text, click to view]

Yeah, I mean the exceptions that a constructor throws should have
little impact on how the guideline is followed. I just think opening a
file is a potentially expensive and complex operation.

[quoted text, click to view]

You're right. We could probably start a whole thread on that topic.

[quoted text, click to view]

It's probably a bit too specific to include in any formal
documentation. But, it does sound reasonable to me.
AddThis Social Bookmark Button